diff --git a/AGENTS.md b/AGENTS.md index f33d4ff..82149af 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,8 +17,6 @@ serialization shapes; it does not contain a project's live delivery state. rather than redefine the process. They name the project's sanctioned tool for the process store and its channel for surfacing tooling gaps; the rule that binds both is `PROCESS.md` "State records and reconciliation". -- `CLAUDE.md` files are compatibility pointers; they do not override these - instructions. If project instructions conflict with a process rule, stop the affected transition and report the conflict rather than creating a silent local variant. @@ -32,13 +30,16 @@ on a decision, or what is blocked: 1. read the project's root `AGENTS.md` for project-specific rules; 2. read this file and `PROCESS.md`; 3. enter the session with `skills/rdd-start/SKILL.md` — it verifies the store - binding and active release before any selection; then use + binding before selection and the active release for normal delivery; then use `skills/rdd-deliver/SKILL.md` for end-to-end delivery, or the applicable focused `skills/rdd-*/SKILL.md` when the request explicitly ends at one - process pass; use `skills/rdd-verify/SKILL.md` for reverse-engineered - `PENDING_VERIFICATION` rows, and `skills/rdd-reverse-engineer/SKILL.md` to + process pass; use `skills/rdd-verify/SKILL.md` for entered verification work + requiring new tests, and `skills/rdd-reverse-engineer/SKILL.md` to establish an authorized as-built baseline or propose DERIVED additions to an existing requirement corpus; + use `skills/rdd-reverse-engineer-verify/SKILL.md` and + `skills/rdd-reverse-engineer-accept/SKILL.md` for source-scoped baselines + with existing proof (one human acceptance directly to DONE); `skills/rdd-audit/SKILL.md` is a shared utility other passes invoke, not a phase; 4. read the relevant product sources, requirement records, optional epic, and diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index c7a5932..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,8 +0,0 @@ -# Claude compatibility pointer - -The canonical instructions for all agents are in [`AGENTS.md`](AGENTS.md). - -Read `AGENTS.md` in full before planning, changing, reviewing, or delivering -work. It points to the canonical `PROCESS.md`. - -This file contains no independent or overriding instructions. diff --git a/PROCESS.md b/PROCESS.md index 70aae34..3d91dab 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -22,6 +22,7 @@ EPIC: PROPOSED -[HUMAN]-> TODO -> IN_PROGRESS -> IN_REVIEW -[HUMAN]-> DONE UR/SR: DERIVED -[HUMAN]-> PROPOSED -[HUMAN]-> TODO -> IN_PROGRESS -> IN_REVIEW -[HUMAN]-> DONE UR/SR: DERIVED -[HUMAN]-> PENDING_VERIFICATION -[HUMAN]-> TODO -> IN_PROGRESS -> IN_REVIEW -[HUMAN]-> DONE UR/SR: source-scoped baseline authorization -[publish as-built]-> PENDING_VERIFICATION +UR/SR with source-scoped baseline authority: PENDING_VERIFICATION -[complete current verified/delivered proof + one HUMAN acceptance]-> DONE TRACE: PENDING -> PASS | FAIL; PASS | FAIL -> STALE -> PASS | FAIL @@ -31,9 +32,10 @@ HUMAN: DRAFT -> OPEN -> ANSWERED -> CLOSED UR evidence is upper evidence, normally exercised through an acceptance/E2E path. SR evidence is lower evidence, exercised at the appropriate unit, API, -component, contract, or integration boundary. Both are red-first. They are -evidence classes owned by different requirement types, not two arms of one -requirement. +component, contract, or integration boundary. Upper and lower evidence belong +to different requirement types. Normal development is red-first; the +existing-baseline path uses the proof specified under As-built verification +and acceptance. ## Authority @@ -45,12 +47,17 @@ be established from authoritative records, code, tests, or runtime evidence. | Tag | Source | |---|---| | `USER::` | Attributable human fact, decision, or approval | -| `DOC:#
` | Product, domain, architecture, or contract source | -| `CODE::` | Observed implementation behavior | -| `TEST::` | Stable test-case identity | +| `DOC:` | Product, domain, architecture, or contract source | +| `CODE:` | Implementation source file | +| `TEST:` | Verification source file | | `RUN:` | Observed test or runtime result | | `EPIC:#
` | Existing Epic record | +File citations name the source file. The cited file carries the requirement or +other item ID it supports. Optional line, symbol, test-name or section suffixes +are navigation hints; the citation auditor checks only that the file resolves. +Execution evidence separately identifies the tests that ran and their results. + Missing support is an open question. Conflicting support remains a conflict until a human resolves it. Code proves existing behavior, not intended behavior. Repository state — branches, diffs, change lists, and version @@ -106,12 +113,12 @@ UR and SR use the same status vocabulary. | Status | Meaning | |---|---| | `DERIVED` | Inferred requirement awaiting human confirmation; all relations are candidate-only | -| `PENDING_VERIFICATION` | As-built behavior established by exact confirmation or source-scoped baseline authorization; awaiting entry approval and current direct evidence | +| `PENDING_VERIFICATION` | As-built behavior established by exact confirmation or source-scoped baseline authorization; awaiting current direct proof and acceptance; normal development entry applies when tests or behavior need development | | `PROPOSED` | Confirmed or directly sourced requirement being prepared for entry | | `TODO` | Entry trace passed and human entry approval was applied | | `IN_PROGRESS` | Applicable red-first evidence work is underway | | `IN_REVIEW` | Required evidence is complete; delivery, reconciliation, or completion acceptance remains | -| `DONE` | Delivered trace passed completion and human acceptance was applied | +| `DONE` | Delivered trace passed the applicable normal completion or existing-baseline acceptance gate, and human acceptance was applied | | `BLOCKED` | Work cannot proceed; blocker and suspended status are recorded | | `DEFERRED` | Work is postponed with reason, owner, target, and suspended status | | `OBSOLETE` | Terminal rejection or supersession with decision/replacement linked | @@ -162,6 +169,8 @@ existing requirement or its compliance approval. Accepting as-built scope places it in Base/PENDING_VERIFICATION; accepting new desired intent makes it PROPOSED and eligible for normal delivery planning. +Base is the store's destination for established as-built requirements, separate +from a delivery release; the project's store interface identifies that destination. Neither action approves entry, verifies behavior, records a passing test result or marks anything DONE. Candidate confirmation is not delivery release selection. @@ -205,6 +214,13 @@ A trace gate evaluates non-human facts at an exact fingerprint. A human gate records a decision by an authorized human. A human gate may become `OPEN` only after every prerequisite trace gate is `PASS`. +An approval-scope fingerprint identifies the requirement content, declared +relations, scope, and decisions being approved. An evidence fingerprint identifies +the tested code/content, tests, inputs, and revision. Each gate names its inputs. +Implementation within approved scope updates evidence; it does not by itself +invalidate entry approval. Changed approved scope or material review assumptions +require the affected gates to be re-evaluated. + ```text authoritative trace -> TRACE PASS -> HUMAN OPEN -> attributable answer -> answer applied -> records reconciled -> HUMAN CLOSED @@ -226,6 +242,7 @@ not a gate answer. |---|---| | Requirement `DERIVED -> PROPOSED/PENDING_VERIFICATION/OBSOLETE` | Candidate packet and exact confirmation scope complete | | Source-scoped baseline authorization | Bound system/store, current corpus and exact source/document inventory reviewed; allowed baseline publication made explicit | +| Source-scoped baseline requirement `PENDING_VERIFICATION -> DONE` | Complete exact current as-built verification and separate repository integration proof; one dedicated reviewed human acceptance | | Requirement `PROPOSED/PENDING_VERIFICATION -> TODO` | Its Entry packet is complete at the exact fingerprint | | Epic `PROPOSED -> TODO` | Its Entry packet and every selected member's entry trace are complete | | Requirement `IN_REVIEW -> DONE` | Its completion predicate is satisfied at the delivered fingerprint | @@ -316,11 +333,13 @@ a human answer. ### Attributable demotions -Delivered work is not final. An item that reached `IN_REVIEW` or `DONE` re-enters -the loop through an attributable demotion — a recorded transition with an -actor, a basis, a `USER:` source, and the decision or defect it rests on — -never through a duplicate requirement, a hand-edited status, or a synthetic -failure. The basis chooses the destination: +An item that reached `IN_REVIEW` or `DONE` re-enters the loop under the same +identity, never through a duplicate requirement, a hand-edited status, or a +synthetic failure. Record the transition, actor, basis, and supporting evidence +or decision. Observed evidence invalidation follows the automatic rules under +Evidence and completion: attribute it to the evaluating agent or check with +its factual sources, without inventing a human answer or `USER:` source. +Demotions based on a human decision use the human gate described below. | Demotion | Basis | What it requires and what follows | |---|---|---| @@ -328,13 +347,13 @@ failure. The basis chooses the destination: | Requirement or Epic `IN_REVIEW/DONE -> IN_PROGRESS` | Defect: the delivered behavior is wrong against the approved requirement | The invalidated evidence named; red-first evidence is re-established for the defect; `IN_REVIEW` returns through the lower or upper trace and `DONE` only through a successor human completion gate | | Requirement or Epic `-> OBSOLETE` | Superseded or retired | The replacement or the retiring decision linked (the supersession rule above) | -A demotion is recorded as a human gate of purpose `demotion` whose transition -names the destination, whose exact scope names the demoted items, and whose -sources carry the basis. Like a candidate-confirmation gate it names no -prerequisite trace — the facts it rests on are the human's decision and the -named defect, not a fingerprint check — and applying it reconciles the graph -like any other answer. Demoting a member reopens its Epic to the weakest -member state. +A human-directed demotion is recorded as a gate of purpose `demotion`. Its +transition names the destination, its exact scope names the demoted items, and +its sources carry the human decision and `USER:` attribution. This gate requires +no prerequisite trace; retain the decision and supporting facts. Applying it +reconciles the graph like any other answer. Evidence invalidation needs no +human demotion gate. +Demoting a member reopens its Epic to the weakest member state. Siblings the demotion does not touch keep their state: their evidence stays `CURRENT` when it is current at the present revision, and the Epic's next completion re-validates it there rather than requiring it to be posted again. @@ -349,24 +368,35 @@ failure. |---|---|---| | Epic | Multiple requirements form one human-readable change, or shared product/architecture/contract/data decisions are required | Exact member UR/SR set; membership is grouping, not ancestry | | Single SR | Exactly one independently verifiable system behavior changes | Authoritative SR source; Epic and UR relations optional | +| Named UR/SR set | Candidate confirmation or source-scoped baseline verification or acceptance | Exact named requirements and applicable declared dependencies; no Epic required | +| Source inventory | Reverse-engineering before requirement IDs exist | Exact repository/file and document revisions, corpus fingerprint, derivation mode, and source authorization; publication receipts identify the resulting requirements | + +Record Epic and single-SR delivery selections in the existing work-selection +format. Candidate and baseline scopes belong to their authorization, run and +decision records; they do not add work-selection kinds or phase values. + +While preparing source authorization, record the mode or authorization as +pending where undecided. Publication requires the applied authorization. Expand single-SR work to Epic scope when it changes user outcome or acceptance, requires another SR, or introduces a cross-cutting decision. Related approved -items repeat entry approval only when their approved scope changes. +items repeat entry approval only when their approved scope changes. A named +UR/SR set does not authorize normal development: any work needing implementation +or test changes is explicitly selected for normal planning and entry. + +Normal delivery selection requires exactly one active release with a `USER:` +source. Candidate confirmation and source-scoped baseline work do not select a +delivery release and do not require one to be active. ## Planning and readiness Planning consists of packet authoring, independent cold review, and entry -review, in that order. A changed fingerprint or failed result returns work to +review, in that order. Changed review inputs or a failed result return work to the earliest affected pass; a downstream pass cannot repair an upstream gap. Packet depth is proportional to the selected scope — a single-SR packet may satisfy an item in a sentence where an Epic needs pages — but no packet item -may be omitted. Depth is also bounded: a single-requirement packet is at most -one page. Reconnaissance that needs more than that page is evidence that the -scope is wrong, not that the packet should grow — split or replan the scope. -The bound is a limit, not a preference: every line a packet carries beyond -what a builder or a gate acts on is a line a review attacks instead of the -change. +may be omitted. Include the information a builder or gate needs to assess the +change; document length does not determine requirement scope. ### Entry packet @@ -382,44 +412,45 @@ The fingerprinted packet must contain: and each write shape it admits (a birth, an edit of an open row, an edit of a settled row, a row born before the change), the readers that branch on it, what a crash mid-write leaves, what makes it stale, and how it - recovers, each mitigation ending `closed`, `residual`, or `decided`; + recovers, with the planned mitigation, supporting criterion or decision, + and any unresolved risk; 4. each SR's owned flow segment, change boundary, dependencies, risks, and test path; -5. an upper-RED strategy for every selected UR, a lower-RED strategy for every - selected SR, and proportional regression gates; +5. an upper-RED strategy for selected UR scenarios requiring new evidence, a + lower-RED strategy for selected SR clauses requiring new evidence, and + proportional regression gates; unchanged proven scenarios need revalidation, + not a new RED; 6. sourced decisions, conflicts, gaps, deferrals, blockers, and unknowns; 7. cold-review findings and verdict; and 8. the human entry brief. -Reconnaissance cites `DOC:`, `CODE:`, and `TEST:` sources. It starts from the -ledger: each surface the change touches names the delivered requirement that -owns it — found by searching the records for every verb, symbol, and path -the change touches, not by recalling likely owners — and the packet carries -that record's acceptance and the rule its tests hold as a constraint the -change preserves or, through a scope decision, amends or supersedes. A -change that contradicts a delivered acceptance is a scope question at -planning, not a finding at review. Generated system documentation is read -before the code and cited as `DOC:`; it is navigation, and where it and the -code at the revision disagree, the code wins and the packet records the -disagreement. Material revision drift makes the packet and its dependent -reviews stale. - -A packet is complete before its review starts. The state inventory is where -the packet states what a review would otherwise have to derive: a row the -change touches but the inventory lacks is a finding, a cell that ends in -`backlog` while an acceptance criterion asserts it is a finding, and a -mechanism the packet does not name is not part of the change. A value the -packet states — a limit, a timeout, a constant — is read at the call site -that applies it, not at its definition. - -A RED strategy names, for each selected requirement, the test file its case -lives in, the behaviour the case asserts, and why it fails at the revision. -It carries no command, pattern, or test name: the command that runs the case -is evidence recorded at the RED commit, where running it is the verification. -A review finding about a command or a name the packet need not carry is a -note that the line is dropped, never a blocker. A migration or a schema -change is production: it lands with the GREEN it serves, never with a RED, -and a case that needs it fails at the revision because it is absent. +Reconnaissance cites `DOC:`, `CODE:`, and `TEST:` sources. Search the requirement +records for existing ownership and constraints on affected behavior; verify +the matches against their content and declared relations. Preserve applicable +delivered acceptance unless an authorized scope decision changes it. If no +existing requirement owns a surface, record that fact and its relation to the +proposed work; do not invent a delivered owner. Read available system +documentation for context. Resolve claims about existing behavior against code +at the named revision; differences from intended behavior remain findings. +Material revision drift makes the packet and its dependent reviews stale. + +Items 1–6 and the human brief must be complete before cold review starts; +entry review also requires the cold-review verdict. Missing required state +analysis or an unresolved risk to an acceptance criterion is a finding. Read a +stated limit, timeout, or constant at the call site that applies it, including the +conditions that select its value. + +A RED strategy names, for each case requiring new evidence, the planned test +file, the behavior it asserts, and why it is expected to fail at the revision. +For new or changed behavior, every planned RED case must fail against the code +at the planning revision for the stated reason; a case that would already pass +cannot serve as RED evidence. For entered verification of existing behavior, +the strategy names the safe temporary mutation or equivalent targeted failure +that makes the case fail, as described in `rdd-verify`. Cold review checks these +failure reasons against the code at the recorded revision. +Planned commands and test identities are proposals, not execution evidence. +Record the actual command and expected failure at the RED revision. A migration +or schema change that satisfies the test lands with GREEN, not with RED. Cold review runs from a context independent of packet authoring and audits the trace, scope, technical surface, changed flow, contracts, data, compatibility, @@ -434,9 +465,8 @@ The review audits the change, not the document. A finding about the packet's own wording, counts, or citations that would alter none of the code, the tests, the interfaces, or the risks is a note and never blocks; a traceability finding is material only when a builder or a gate would act on the wrong -citation. The independent context is a recorded fact of the verdict — the -context the verdict was recorded from — not a claim in its text: a verdict -recorded from the authoring context is not a cold review. A closure carried +citation. Record the reviewer and independent review context with the verdict; +an author's self-review is not a cold review. A closure carried from an earlier round is a claim to re-verify, not a fact. A finding that would change a human decision returns to that human as a question; it is never resolved by editing the packet. @@ -447,32 +477,33 @@ decision with its `USER:` source. No new mechanism enters a packet during a review cycle. A finding whose fix needs a new acceptance criterion, a wider boundary, or a new flow hop is a scope question — split, defer, or decide — and the mechanism is planned with its own reconnaissance as its own change. -A resolution edit re-enters reconnaissance for what it names: every symbol, -path, or test it names is read at the revision before the disposition is -recorded, and a fix the reviewer proposed is a claim verified the same way -as a closure carried from an earlier round. A round whose material findings -fall on mechanisms an earlier round's resolutions introduced is evidence -that the packet was reviewed incomplete, not that the review is thorough. - -Cold review converges or stops. At most two rounds run on one change. When a -second round's new blocking findings are about the packet rather than the -change, the packet is cut to what the change needs and review proceeds. A -third round does not start: the work stops and what is known is handed to a -human. - -A review of the built change is not a round of the packet's review. It runs -from its own independent context at the revision it read and numbers its own -rounds; its findings are recorded on the same scope but count neither toward -the two-round bound nor in the packet's round history, and an open material -finding on the change stops delivery. A `RESOLVED` finding on the change -names the commit that resolved it: the commit only brings the code to what -the approved change already contained, and a fix that needs a new acceptance -criterion, a wider boundary, or a new flow hop is a scope question, as in the -inner loop. +A resolution edit re-enters reconnaissance for what it names: reread every +symbol, path, and test it names at the recorded revision before marking the +finding `RESOLVED`. Verify a fix proposed by the reviewer in the same way as +a closure carried from an earlier round. +Changes to approved behavior, scope, architecture, acceptance, or a material +technical decision return to the affected planning pass. A review finding does +not itself authorize implementation. + +At most two cold-review rounds run on the selected planning scope. A current +pass proceeds to entry review. After a second failed round, report the remaining +material findings to the human; do not start a third round automatically. + +Completion review requires an independent code review of the built change for +Epic scope. For single-SR scope, obtain one when project gates or the user +require it. The review runs from a context independent of implementation; +record the reviewer, reviewed revision, findings, and verdict separately from +planning review. Missing required review or open material findings stop +delivery and completion. Resolved implementation findings cite the correcting +commit and verification. Entry review evaluates the complete packet at its exact fingerprint. Only a current entry trace `PASS` may open the human entry gate. Do not create or -change tests or implementation until every selected item is `TODO`, with one +change tests or implementation until current applied entry approval covers the +whole selected delivery scope, including the Epic when selected. Newly entered +items must be `TODO`; already-entered items retain their current states. +Unchanged `DONE` dependencies are not re-entered. Partial entry approval does +not permit development to start on the approved subset. There is one exception — the defect lane. When a defect is already diagnosed and the change is bounded, the failing test may be written first, on a branch and before entry, and cited in the packet as a `RUN:` source: it is the reconnaissance, @@ -493,13 +524,15 @@ focused skill alone only when the requested scope explicitly ends at that pass. | Phase | Skill | Required exit | |---|---|---| -| Enter session | `rdd-start` | Store binding and single active release verified from the store; answered gates reconciled; frozen scope routed to its earliest unmet phase, or an orientation request answered from the current pending-decision projection | +| Enter session | `rdd-start` | Store binding verified; single active release verified when selecting normal delivery; answered gates reconciled; frozen scope routed to its earliest unmet phase, or an orientation request answered from the current pending-decision projection | | Source/classify | `rdd-discover` | Authoritative input or an exact confirmation gate; no unconfirmed requirement proceeds | | Plan/reconnaissance | `rdd-plan` | Entry-packet items 1–6 and the human brief at a named revision | | Cold review | `rdd-cold-review` | Current cold-review trace verdict and finding dispositions | | Entry | `rdd-entry-review` | Applied human approval and selected items in `TODO`, or an explicit non-entry result | | Execute changed SR | `rdd-build` | Current lower evidence; eligible SR in `IN_REVIEW`; selected UR evidence updated independently | -| Verify as-built requirement | `rdd-verify` | Current UR upper or SR lower evidence; eligible requirement in `IN_REVIEW` | +| Verify entered work requiring tests | `rdd-verify` | Current UR upper or SR lower evidence; eligible requirement in `IN_REVIEW` | +| Verify existing baseline | `rdd-reverse-engineer-verify` | Complete applicable current assertion/execution proof and separate repository integration observations; exact eligibility packet | +| Accept existing baseline | `rdd-reverse-engineer-accept` | One reviewed human decision atomically applied from `PENDING_VERIFICATION` to `DONE`, with durable receipt; compliance unchanged | | Deliver/complete | `rdd-completion-review` | Delivered revision, reconciled records, completion trace, and applied human result | | Route change | `rdd-triage` | Discovery assigned to the earliest phase it invalidates | @@ -507,14 +540,59 @@ Before each phase, reconcile answered gates and state, then select the earliest unmet prerequisite. A focused skill's exit is a handoff, not completion of the full loop. +### As-built verification and acceptance + +A published source-scoped baseline starts in `PENDING_VERIFICATION`. This path +requires that persisted baseline authority; the status alone, including status +from individual DERIVED confirmation, does not confer eligibility. Publication +establishes requirement authority, not test PASS, delivery or compliance approval. +A dedicated existing-behavior path may move exactly reviewed URs/SRs directly to +`DONE` with **one human acceptance decision** after all of the following hold: + +- Every active applicable criterion has inspected semantic assertion coverage, + confirmed code/test connections and genuine current named execution proof. + UR upper evidence is evaluated independently and includes its required SRs; + a standalone SR needs no invented parent or Epic. +- Exact requirement content, graph, source/test bytes, revisions, report/result + identities and CI provider/repository/run/job/attempt/tested commit are pinned. + Missing, unexecuted, contradictory, stale, inaccessible or revoked proof is a + gap, not a partial PASS or an accepted undisclosed coverage limit. +- Every repository has a distinct retained integration observation of the clean + tested revision at the fetched remote default-branch tip, matching the captured + snapshot. Passing unmerged branch tests do not prove delivery. This is an + integration observation, not a deployment claim or a live provider connector. + Retain the observed remote identity. If the integration check does not validate + it against an independently declared repository identity, disclose that + limitation; a local origin setting alone does not establish repository ownership. +- A current eligibility trace evaluated through the sanctioned tool supports + the exact human decision. + Its attributed reviewed answer and guarded application recheck the complete + proof. Application is atomic across the named scope and uses normal lifecycle + events. A stable key and identical input recover the same receipt; changed + input conflicts. Historical receipts and their exact reviewed evidence remain + readable after drift, while stale proof cannot be applied or replayed as current. + +`rdd-reverse-engineer` remains publication-only. The dedicated +`rdd-reverse-engineer-verify` gathers and evaluates existing evidence; +`rdd-reverse-engineer-accept` reviews the exact packet, records the one human +answer and applies/readbacks its receipt. No skill fabricates RED or rebuilds an +already proven product. Test additions and behavior changes remain gaps until +an explicitly scoped handoff to normal development. No general-purpose gate +label, client flag or generic advance authorizes this transition. + +This path changes work lifecycle only: compliance draft/approved fields are +unchanged. Normal `rdd-build`, `rdd-verify` and `rdd-completion-review` retain their +RED/GREEN, entry and completion contracts. Requirements reopened for a defect +return to normal development; baseline provenance alone does not reroute them. + ### AI TDD inner loop After human entry places the selected scope in `TODO`, the AI owns the automatic `TODO -> IN_PROGRESS -> IN_REVIEW` transitions. It does not request human input -while the approved fingerprint remains unchanged. +while the approved scope remains unchanged. ```text -establish selected UR upper RED +establish required selected UR upper RED -> select an unmet approved SR clause -> SR lower RED -> GREEN -> CLEAN -> lower verify -> rerun affected UR upper evidence @@ -540,9 +618,9 @@ Run the loop as follows: its required SRs in `IN_REVIEW` or `DONE`. Use a reviewable feature branch and preserve RED and passing fingerprints. For -`PENDING_VERIFICATION`, demonstrate regression sensitivity with a safe -temporary local mutation or equivalent targeted failure, then restore it. The -restored implementation may require no product-code change. +as-built behavior entered into normal verification, demonstrate regression +sensitivity with a safe temporary local mutation or equivalent targeted failure, +then restore it. The restored implementation may require no product-code change. If an upper failure remains after all planned SR lower traces pass, diagnose it. Repeat the inner loop when the failure is within approved behavior. Return to @@ -567,9 +645,8 @@ A pass may be delegated to another context — a cold review, a verification sweep, one reconnaissance surface. A delegated pass establishes facts and returns them: findings, a verdict, citations. It writes nothing to the process store; the orchestrating session records what the pass returned, under its own -actor attribution. The independence of a cold review is a property of the -context the verdict is recorded from, not of which process runs the recording, -so recording from the orchestrating session does not compromise it. +actor attribution while retaining the reviewer's identity and context. Recording +an independent review's returned verdict does not turn it into self-review. A delegated pass that is refused by its environment — a permission denial, an authentication failure, a store refusal — stops and returns the refusal @@ -587,12 +664,19 @@ Outcome is `PASS`, `FAIL`, or `SKIP`. Validity is: |---|---| | `CURRENT` | Matches the exact clause, content/code fingerprint, and revision | | `STALE` | A traced input changed after the result | -| `INVALID` | The tested content is unreachable, reverted, abandoned, or not delivered | +| `INVALID` | The tested content is unreachable, reverted, or abandoned | | `INHERITED_UNVERIFIED` | Carried from another revision or change without a confirming run | Only `CURRENT` evidence linked to the exact clause, test case, code/content fingerprint, and revision counts. Broad suites prove only exercised assertions. -Line numbers are navigation hints, not test identities. +Line numbers are navigation hints, not test identities. Evidence may be current +on a feature branch before integration; delivery is a separate completion +prerequisite. Earlier RED results demonstrate regression sensitivity at their +recorded revision; they are not relabelled as executions of the passing +implementation. Current passing proof is required separately. + +Normal development requires the following evidence. The existing-baseline path +uses the requirements under As-built verification and acceptance instead. | Requirement/evidence | Required evidence | |---|---| @@ -618,8 +702,8 @@ Supplemental evidence causes no demotion. Re-verification may restore completion gate. Material approved-scope changes stale entry approval and send work back to planning. -A completion human gate may open only when named items are `IN_REVIEW`, code is -delivered, evidence is current at the delivered revision, state is reconciled, +A normal completion human gate may open only when named items are `IN_REVIEW`, +code is delivered, evidence is current at the delivered revision, state is reconciled, candidate relations are excluded, and gaps/deferrals/decisions are disclosed. The delivered revision is the one the authorized integration path produced, not the branch head that fed it. A member-scoped trace from an earlier round @@ -677,7 +761,7 @@ file-state/ `EPICS.md` stores optional grouping records. `REQUIREMENTS.md` stores URs, SRs, declared relations, and trace references. `GATES.md` stores every trace and -human gate record. `WORK-SELECTION.md` stores the frozen scope, suspended +human gate record. `WORK-SELECTION.md` stores the frozen delivery scope, suspended selections, and selection history. `BACKLOG.md` stores unrouted triage items and gap records. Derived queues and progress views — including the pending human-decision projection — are regenerated, not backed up separately. @@ -724,7 +808,8 @@ After every transition, update the complete affected graph and run checks for: - stable test identities, revision-pinned validity, and invalidation cascades; - exact gate fingerprints and legal gate/state transitions; - no `TODO` without applied entry approval; -- no `DONE` without delivered evidence, reconciliation, and applied completion; +- no `DONE` without delivered evidence, reconciliation, and applied human + acceptance through normal completion or the eligible existing-baseline path; - isolation of `DERIVED` items and candidate links from authoritative scope; - agreement between authoritative state and generated projections. @@ -745,8 +830,8 @@ human decisions. | Contradicted or removed behavior | Conflict or `OBSOLETE` with replacement | | Delivered item found defective, or its decision reversed | Attributable demotion of the existing item (§Attributable demotions); never a duplicate requirement | -A project's release registry holds exactly one active release, and release -selection requires a `USER:` source. Drift between repository records and the +Normal delivery selects the single active release from the project's registry +with a `USER:` source. Drift between repository records and the store binding is a defect to report, not a variance to work around. `DERIVED` items are not release commitments. Preserve competing authoritative sources and request a human decision; never resolve intent by timestamp or weaken a diff --git a/README.md b/README.md index da7f989..17e1b1a 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,13 @@ EPIC -- optionally groups --> UR and/or SR UR -> acceptance scenario -> TEST_CASE -> TEST_RESULT UR acceptance scenario -- may require --> SR SR -> CODE -> TEST_CASE -> TEST_RESULT +``` -Each selected trace passes planning, technical review, human entry, red-first +Normal development passes planning, technical review, human entry, red-first evidence, implementation, cleanup, verification, delivery, reconciliation, -and human completion. -``` +and human completion. An eligible source-scoped baseline uses existing-proof +verification and one human acceptance instead; publication alone proves neither +verification nor delivery. Product repositories hold authoritative process records in one selected store, alongside specifications, code, tests, evidence, and attributable gate answers. @@ -27,7 +29,8 @@ or the other, never both at once. 1. [`AGENTS.md`](AGENTS.md) — binding agent rules. 2. [`PROCESS.md`](PROCESS.md) — the complete canonical process. -3. [`skills/rdd-deliver/SKILL.md`](skills/rdd-deliver/SKILL.md) — complete-loop +3. [`skills/rdd-start/SKILL.md`](skills/rdd-start/SKILL.md) — session entry and scope routing. +4. [`skills/rdd-deliver/SKILL.md`](skills/rdd-deliver/SKILL.md) — complete-loop orchestration; use the other `skills/rdd-*/SKILL.md` files for explicitly bounded passes. @@ -42,8 +45,7 @@ apply that model; `file-state/` serializes its records without redefining it. |---|---| | `AGENTS.md` | shared agent policy and canonical entry point | | `PROCESS.md` | complete canonical process | -| `CLAUDE.md` | root compatibility entry required for Claude discovery | -| `skills/` | full-loop orchestration plus focused procedures for discovery, planning, review, building, triage, completion, and as-built verification; corpus adoption for codebases without requirement records (`rdd-reverse-engineer`); a shared document/citation auditing utility (`rdd-audit`) | +| `skills/` | delivery orchestration and focused passes; `rdd-verify` for entered verification work; `rdd-reverse-engineer` for baseline publication or DERIVED additions; `rdd-reverse-engineer-verify` and `rdd-reverse-engineer-accept` for eligible existing baselines; `rdd-audit` for documents and citations | | `file-state/` | canonical serialization shapes for Epic, requirement, gate, work-selection, and backlog/gap records | ## Distribution @@ -53,9 +55,9 @@ for ModernPath workspaces, the `modernpath` CLI — embeds a byte-identical snapshot of these files and installs it under `.modernpath/rdd/`, so in a consuming repository the canonical process resolves at `.modernpath/rdd/PROCESS.md` with every `skills/rdd-*/SKILL.md` beside it. -The installer also registers the skills and hooks with each agentic platform -in use (for example `.claude/skills/`) and writes managed instruction blocks -pointing agents at the installed paths. +Platform-specific metadata, compatibility files, registration and hooks belong +to the distribution tool. This repository supplies the shared instructions and +skills; the installer supplies the adapters for each platform in use. In a store-backed consuming repository the tooling additionally materializes two uncommitted projections (for ModernPath workspaces, diff --git a/file-state/BACKLOG.md b/file-state/BACKLOG.md index 8ee03f0..b3a117b 100644 --- a/file-state/BACKLOG.md +++ b/file-state/BACKLOG.md @@ -15,9 +15,9 @@ inferred one to `DERIVED` plus its confirmation gate. ## Triage backlog -Discoveries with unclear ownership or a cross-cutting concern, held until a -human assigns them. An item that already has an owner and a source is a -requirement and does not belong here. +Discoveries awaiting classification or assignment. Route them using the +discovery table in `PROCESS.md`; an owner and a source alone do not establish +a requirement. ## BACKLOG-«NNN» — «Discovery in one line» @@ -31,8 +31,8 @@ requirement and does not belong here. ## Gap records A capability or specification deficiency linked to the traces it affects. A gap -is a disclosed absence, not a deferral: deferral postpones work that is already -a requirement, a gap names something no requirement yet covers. +is a disclosed absence. Deferral records a decision to postpone requirement work; +it does not resolve a gap in an affected trace. ## GAP-«AREA»-«NNN» — «Missing capability or specification» @@ -45,3 +45,6 @@ a requirement, a gap names something no requirement yet covers. Every open gap affecting an item in a completion gate's scope must be disclosed in that gate before it is answered. +Acknowledging a gap does not resolve it or waive missing trace evidence. A scope +decision that removes the affected obligation is recorded on that requirement +and its gates before the gap is closed. diff --git a/file-state/GATES.md b/file-state/GATES.md index 73be8f5..2556dd3 100644 --- a/file-state/GATES.md +++ b/file-state/GATES.md @@ -9,17 +9,17 @@ - **Source store/revision:** «database revision or repository SHA» - **Context / release:** «scope» -Trace gates and human gates are recorded in the same file because a human gate -is addressable only through the trace gates that gate it. A human gate with no -recorded prerequisite trace gate is unreadable, not implicitly open. +Human gates name every prerequisite required by their transition. A gate with +missing required prerequisites cannot open. An empty prerequisite set is valid +only where `PROCESS.md` explicitly permits it, such as an attributable demotion. ## GATE-«AREA»-«NNN» — «Transition or decision purpose» - **Kind:** trace or human / «confirmation, entry, decision, demotion, cold-review, start-review, completion» - **Transition / purpose:** «exact state transition, or the decision being asked» -- **Exact scope:** «named EPIC/UR/SR ids this gate covers; one answer may cover an Epic and named members» +- **Exact scope:** «named EPIC/UR/SR ids, or the immutable source inventory for baseline authorization before requirements exist» - **Prerequisites:** «gate ids that must be PASS before this one may leave DRAFT, or none» -- **Fingerprint:** «content/code fingerprint the gate was evaluated at» +- **Fingerprint:** «approval-scope or evidence fingerprint and the exact inputs evaluated, per PROCESS.md» - **State:** «trace: PENDING / PASS / FAIL / STALE — human: DRAFT / OPEN / ANSWERED / CLOSED / SUPERSEDED» - **Verdict / answer:** «trace verdict with exact blockers, or the human answer as given» - **Actor / evaluator:** «real human actor and role for a human gate; evaluating agent or check for a trace gate» diff --git a/file-state/REQUIREMENTS.md b/file-state/REQUIREMENTS.md index 8252272..f5815a6 100644 --- a/file-state/REQUIREMENTS.md +++ b/file-state/REQUIREMENTS.md @@ -30,12 +30,14 @@ The RED/Passing split carries each result's role; `Outcome`, `Environment`, and `Fingerprint` carry the remaining mandated evidence-record fields. +RED is required only on the applicable normal-development path; the +existing-baseline path does not fabricate it. ### Gates and delivery - **Confirmation gates:** «GATES.md gate ids, or N/A» -- **Entry gates:** «GATES.md gate ids» -- **Start/review gates:** «GATES.md gate ids» -- **Completion gates:** «GATES.md gate ids» +- **Entry gates:** «GATES.md gate ids; N/A for the dedicated existing-baseline path» +- **Start/review gates:** «GATES.md gate ids, or N/A» +- **Completion gates:** «normal completion or dedicated existing-baseline GATES.md gate ids» - **Delivered revision:** «repository + revision or not delivered» - **Gaps / deferrals / blockers / notes:** «refs or none» diff --git a/skills/rdd-audit/SKILL.md b/skills/rdd-audit/SKILL.md index 1bb48a2..cc4c552 100644 --- a/skills/rdd-audit/SKILL.md +++ b/skills/rdd-audit/SKILL.md @@ -1,983 +1,120 @@ --- name: rdd-audit -description: Audit a document corpus, a ledger, or a check you wrote — resolve citations, diff an inventory both directions, judge a count, and recognise how an instrument fails. Use when verifying that documents still describe the code, when a measurement disagrees with a previous one, when writing or widening a matcher, or when deciding whether a finding is real before acting on it. A shared utility invoked by rdd-reverse-engineer, rdd-cold-review, and rdd-completion-review — it establishes facts and findings, routes them through rdd-triage, and never assigns lifecycle state. +description: Check document claims, source citations, and inventory completeness against direct evidence. Use within reverse-engineering, planning review, or completion review, or for an explicitly requested document audit. Reports verified findings and measurement limits; does not assign lifecycle state or authorize changes. --- -# Auditing what a document claims +# Audit claims and citations -A shared utility, not a phase. `rdd-reverse-engineer` invokes it before -claiming coverage, `rdd-cold-review` and `rdd-completion-review` invoke it to -verify citations and inventories against the code, and any pass correcting a -stale claim may load it alone. Its contract: +Read the project `AGENTS.md` and canonical `PROCESS.md`. This is a shared +utility, not a delivery phase. The invoking pass owns scope and routes findings +through `rdd-triage`. An audit request alone does not authorize document or +implementation changes. -- it establishes facts about documents, records, and the instruments that - check them; it never assigns or advances a lifecycle state; -- its findings are discoveries — route them through `rdd-triage`, which owns - where they land; -- invoked inside the loop it is scoped to the affected surface; the - full-corpus sweep is a deliberate act — at adoption, before a release, or - when `rdd-start` reports drift — never an every-iteration cost. +## Establish the scope -Read the project `AGENTS.md` and the canonical `PROCESS.md` -(`.modernpath/rdd/PROCESS.md` in a consuming repository) for the authority -and reconciliation rules these checks serve. +Identify the documents, source repositories, revisions, and claims being checked. +Use the project's actual document locations. Separate intended behavior from +claims about implemented behavior: code can establish the latter but cannot +silently replace approved intent. -Two sections, and they answer different questions. **Citations** asks *does this -reference resolve* — mechanical, and the place a pass first writes a checker. -**The audit** asks *is this document still true, and is my check trustworthy* — -which is mostly about not believing your own instrument. +In a store-backed project, use its sanctioned tool for authoritative records, +typed citations, inventory projections, and immutable source reads. Do not infer +the requirement corpus from local snapshots or recreate retired task ledgers. ---- - -## Citations — does every reference resolve? - -Every `file:line` you wrote must resolve. This is mechanical, it takes seconds, -and it is the cheapest guard against a ledger that reads well and points nowhere. - -**Run the script; do not re-derive it.** - -```bash -# beside this skill; installed at .modernpath/rdd/skills/rdd-audit/ in a consuming repository -node .modernpath/rdd/skills/rdd-audit/audit-citations.mjs # docs/ + ARCHITECTURE.md -node .modernpath/rdd/skills/rdd-audit/audit-citations.mjs docs/recovered \ - --repository=api=/workspace/api --repository=legacy=/workspace/legacy -``` - -Declare every source repository explicitly when auditing from a non-Git parent -or across repositories. Git worktrees (`.git` files) and scoped non-Git roots -are supported. `CODE:repository@revision:exact/path.xml:12` and `TEST:` use the -declared identity; revision disagreement fails. Unqualified suffixes must resolve -uniquely, never to whichever candidate happens to have enough lines. XML, JSP, -XSL and XSLT are recognized; unknown prefixed forms fail visibly. - -It sweeps citation shapes over every markdown file under the given document roots, -flags elided paths, excuses named gaps, and exits non-zero on failure, ambiguity, -or zero recognized citations. Raise `--min=N` to the known corpus floor. This is a -checkout citation audit, not proof that historical captured bytes remain available; -use the sanctioned immutable source reader for that check. - -For store-backed onboarding, read the authoritative run's inventory coverage -projection: included/excluded/unassessed/unresolved source units, candidate links, -governed links and overlap. Measure behavior-class denominators separately. Do not -recreate or scan retired task ledgers as if they were the requirement corpus. -Store citations and proposed links are checked through the store's typed source -contract, not inferred from an empty local markdown scan. The rest of this section explains *why* each -of those rules exists — read it when the output surprises you, and when you are -tempted to write your own. - -**That temptation is the point.** This procedure was re-derived by hand five times -in one session and was wrong three of those. Each rewrite looked correct and -produced a confident number. The rules below are the scar tissue: - -**Skip named absences.** A row that says *"no test — there is no -`test_draft_service.py` in the repository"* is naming a gap, which is the most -useful thing a derivation pass produces. It is not a citation, and an audit that -counts it as broken teaches the next pass to stop naming what is missing -(8 of 8 "broken citations" in a 3,222-citation ledger were -absences stated correctly). Ignore any reference preceded by *no*, *missing*, -*there is no*, or *does not exist*. - -**And resolve paths properly before reporting a failure.** A citation written -`db/models.py:1483` may live six directories deep; a bare `admin.py` may match two -files, only one of which is long enough. Search the declared repository scope, -but accept a suffix only when it has **one** match. Multiple matches require an -exact repository-qualified path; line count never disambiguates identity. -Three separate audit scripts written in one session each reported the -ledger as broken when the resolver was at fault. Prove your -checker on a citation you know is good before you trust its failures. - -### How an instrument fails, and in which direction - -#### Reading what the instrument told you - -**A near-total failure rate is a broken instrument, not a discovery.** Before -believing a result, ask what fraction of the population it condemns. A check that -indicts 100% of anything has found a convention it does not understand. Near 10% -the balance tips and a finding becomes likelier than a bug. The converse holds: a -check that passes *everything* on its first run has usually matched nothing — -which is why a new check earns trust by being made to fail on purpose. - -**A module path is not a table name.** A `compliance/` directory prefix is not -part of `schema "change_plan_messages"`. **Read the declaration, never the -filename** — the `schema "…"` line for Ecto, `__tablename__`/`@Table` for an ORM, -the DDL for SQL. - -**A shell utility that fails on your data reports an empty result, not an error.** -`sort` exits on non-UTF-8 bytes and swallows its input; the pipeline prints a -clean, wrong, empty answer. Run text sweeps under `LC_ALL=C`, and treat *"none -found"* with the same suspicion as a 100% failure rate. - -**An overstated gap makes the wrong decision for you.** A gap measured at 52 -files across four subtrees was filed as too big to fix; re-measured with the -population defined it was 12, and closed the same day. **Audit the numbers that -license inaction hardest** — an overstated gap buys a permanent deferral, while -an understated one is corrected the moment someone starts work. - -**A count with an undefined population is not a measurement.** One question — *how -many cited tests name their requirement?* — gave 12, 35, 45 and 123 across four -bug-free runs, differing only in what counted as a cited test. **State the -population next to the criteria**, and when a re-measurement disagrees with a -recorded one, **suspect the population before the matcher**: a factor-of-ten -spread is what a definition disagreement looks like. - -**Report the instrument's count and the verified count separately.** "35 -mismatches" implies each was inspected. Say *upper bound*, and name the ones that -were. - -#### Changing a matcher - -**Widening a matcher to fix a false negative is the moment to write the -false-positive test** — not after. Each widening below let something through that -must not pass, and every one was caught by adding the negative case, none by -re-reading the regex: - -| Widened to accept | Also accepted, wrongly | -|---|---| -| `APPROVED` anywhere on a line | `SPEC-APPROVED` — a different gate | -| any heading containing "approval" | `## Pre-approval audit` | -| every line of a section | rows belonging to the other gate | - -A widened pattern reads as *"now it accepts X"*; the question that matters is -what **else** it accepts. Write the shape you must still reject, and watch it fail. - -**Two implementations with *different* fixtures beat either suite alone.** A -parity mirror or a port is justified as a compatibility requirement; its quieter -value is that its tests were written by someone solving the same problem from -another angle, so it holds fixtures the original never thought to write. When a -widening left one suite green and failed the mirror on a case the first lacked, -the disagreement was the only detector. **Run the mirror's tests before your own -conclusions**, and copy back the fixture that surprised you. - -**A widening that clears more than you expected is a warning, not a result.** If a -change fixes more cases than the one you were chasing, find out which extra ones -moved before booking them. - -**Be most suspicious when the new behaviour is a pass.** A false negative annoys -someone; a false positive silently asserts that a thing was checked. - -#### When the tool says nothing, or says it sideways - -**Do not let display truncation become evidence.** A check that printed cited -lines through `cut -c1-46` made six correct citations look wrong. When a check -disagrees with a document, **widen the view before you edit** — print the whole -line, and confirm with a second method sharing no code with the first. Agreement -between `grep -n` and `awk` means something; agreement between a script and its -own truncated output means nothing. - -**Read a checker's first run as a test of the checker, not of the corpus.** Four -checks each found a bug in *themselves* on first contact with real data: an -exemption applied before resolving (skipped 116 resolvable citations), an elision -gate whose hits were prose, an escape fix that collapsed counts 2220 → 483, an -anchor matcher that mangled its own character class. None was found by re-reading -the code. Budget the first run for debugging the instrument. - -**Silence is not agreement.** A command producing *no output* has not been shown -to have run — a fixture using an unscanned extension reports `0/0`, a gate run -from the wrong directory reports *"checks pass"*, a command inside a broken `&&` -chain never executes. Verify the **effect**, not the exit code, and never pipe to -`tail`: the last two lines of no output are no output. - -A gate proves what it checks, never that it was reached. - -#### Which direction to distrust - -**Both directions of failure happen; only one is self-correcting.** - -| | What it does | How it ends | -|---|---|---| -| **False alarm** — a regex matching `.ex` inside `.exs`; a truncated display | sends you *to* the evidence | caught within minutes — you open the file to fix it and the code disagrees | -| **False pass** — a sweep over a subset reporting `56/56`; an exemption applied too early | sends you *away* from the evidence | survives until something unrelated exposes it; several persisted for months | - -Budget suspicion asymmetrically. A false alarm costs one round trip and pays for -itself. A false pass costs nothing today and everything later, and **nothing in -your own workflow will surface it** — the only reliable detectors are a second -implementation and a number that does not match the change. - -**Stop when the evidence explains *why*, not when it establishes *that*.** A -finding whose meaning changes as you look closer has not finished changing. One -sequence ran: *93 rows stranded on the server* → *but the ids are in `tasks/`* → -*so the builder is dropping rows* → *they were retired deliberately, and the data -model says so in its own headings*. Each reading pointed at a different action; -the one that held explained why the state exists. **The most alarming reading was -third of four, and it was wrong** — alarm is not evidence of depth. - -**Splitting findings into "certain" and "ambiguous" puts the danger in the wrong -bucket.** The ambiguous pile gets read carefully because you cannot act on it; the -certain pile gets *acted on*, so a detector error inside it goes straight into an -edit. → **Before acting on the confident half, re-derive it once with a stricter -matcher.** If the count drops, your certainty came from the tool. - -#### What the pattern never saw - -**Count what your pattern did *not* match — a loose pattern does not over-report, -it stops looking.** Citations use a grammar: `file:N`, `file:N-M`, `file:N,M`, -`file:N-M,P`. A pattern matching `file:(\d+)` matches all of them and reads only -the first number, so `466,480` scores as one citation and 480 is never examined. - -1. **Write down the grammar before the regex.** If the data has lists, ranges or - optional parts, enumerate them. -2. **Measure coverage, not just hits.** If a line holds four numbers and your - matcher reports one, that gap is the finding. - -**Report the result as a fraction (`140/140 resolve`), and make the denominator -the whole corpus.** A pass that greps only its own `CODE:` prefix measures the -citations it thought to prefix — one corpus reported `56/56` while carrying 11 -bare `` `adapter.ex:48` `` references no audit had ever seen. Sweep both shapes, -resolving bare ones by path suffix against the tracked file list. -### What the sweep must cover, and what it still cannot tell you - -**And sweep every document, not the ones this pass wrote.** The subset error -recurs one level up, and it is easy to miss because each fraction looks complete. -The same corpus reported `56/56` over the derived set, then `67/67` once bare -references were counted, then **`119/123`** once the sweep covered `docs/**` — and -the four failures were in a document no earlier audit had opened, because it was -not part of the derived set. They were **elided paths**: `CODE:.../ai/proxy.ex`, -written by an author who knew where the file was and left the reader a citation -that resolves to nothing. - -```bash -grep -rn 'CODE:\.\.\.' docs/ # elided paths — expect no output -``` - -Elision is worth a check of its own because it is invisible to a reader and to a -naive resolver alike: the line *looks* like a citation, and a suffix-matching -audit can even accept it if it strips the dots. Write the path from the repository -root, every time. - -**Resolving is not being right, and the gap between them is where rot lives.** -Every check above is structural: the file exists, the file is long enough. A -citation can pass all of them and point at a line that no longer says what the -claim says. a corpus reported `50/50 resolve` while one -document quoted a per-file cap of 15,000 characters that applied only when the LLM -proxy was **off** — the code selects between two budgets, and the smaller one -(8,000) governs any deployment using the proxy. The citation resolved perfectly. - -**So cite the line that carries the claim, not the definition that contains it.** -That document cited a function's `defp` head while quoting an expression three -lines inside it. Pointing at the head is what let the quote go unchecked — nobody, -human or script, could compare the claim to the cited line, because the cited line -was a signature. When you quote or paraphrase a specific expression, cite *its* -line; reserve the head for claims about the function as a whole. - -Then one more check becomes possible and worth running: **for every citation where -the prose quotes code, assert the quoted text appears in the cited range.** That is -still mechanical, and it catches the drift the existence check cannot. - -**A token-overlap heuristic is a triage list, not a gate.** Comparing symbols named -in the prose against tokens on the cited line flagged 14 of 52 citations in that -same corpus; 13 were false — the surrounding text was a table, and the "prose" was -a neighbouring cell. One was real, and it was the one above. Run it to decide what -to read, never to decide what to report; a checker with a 93% false-positive rate -teaches the next pass to ignore it. - ---- - -## The audit — is the document still true, and is your check trustworthy? - -Everything below applies to any document this process produces or inherits — a -recovered design corpus, an adopted `ARCHITECTURE.md`, per-context documents, -and the serialized process records. It is written as one section because these checks are a single -discipline, not per-document advice. - -**Adopting is not accepting. Audit what you adopt.** A maintained document is -maintained *as of some date*, and the code moved after it. Before you adopt one, -run at least one **countable** check — a set the document enumerates against the -same set in the code: - -- tables it lists versus `__tablename__` declarations -- services it names versus what the compose file and CI actually build -- endpoints it documents versus the routers on disk - -On one real corpus that check took two commands and found a `Database Schema` -section that was **6 tables short of the code and named 2 that had been dropped** -— the document was edited 2026-06-10 while the services changed through -2026-08-03. A reader trusting it would have looked for a table the migrations had -deleted. - -Then **extend it in place** with what you found, and say in the document that you -did, with the date and what you reconciled against. A silent correction leaves -the next reader unable to tell which parts have been checked. - -**Two commands that do this well:** - -```bash -grep -oE '__tablename__ = "[a-z_]+"' | sed 's/.*"\(.*\)"/\1/' | sort -u > /tmp/real -# extract the same set from the document, then: -comm -23 /tmp/real /tmp/doc # in the code, undocumented -comm -13 /tmp/real /tmp/doc # documented, no longer real — the sharper finding -``` - -### Groundedness first, then correctness - -**Measure groundedness before you measure correctness — `0 broken` on `0 -citations` is not a pass.** A citation audit reports what it found wrong among -the claims that can be checked. A document that cites nothing cannot be wrong by -that measure, and will score perfectly. - -Run this first, and read it as the headline result: - -```bash -docs=$(ls docs/*.md docs/**/*.md 2>/dev/null | wc -l) -cited=$(grep -rl 'CODE:' docs/ 2>/dev/null | wc -l) -echo "$cited of $docs documents carry at least one citation" -``` - -Measured across three real corpora, which is the range to -expect: - -| Corpus | Documents | With ≥1 citation | Citations | -|---|---:|---:|---:| -| derived by this process | 26 | 22 (84%) | 1,003 | -| a workspace's own design docs | 48 | 9 (18%) | 48 | -| a repository with 21,410 code files and no derivation pass | 36 | **0 (0%)** | **0** | - -The third is the case to recognise. Thirty-six documents describing a substantial -system, none of them making a single checkable claim about it — and the citation -audit returned "0 broken", which looks like health. - -**Audit a document's own status tags — they are a promise, and they are -machine-checkable.** A design document that marks each item **EXISTS** or -**TODO**, **built** or **planned**, is making a per-claim assertion far sharper -than its prose. That tagging is usually the most useful thing in the document and -the least maintained. - -One audited API contract carried 69 endpoints tagged EXISTS: **five -were not in the router at all**, their only matches being LiveView modules rather -than JSON routes. A team building a frontend against that contract would have -discovered the gap at runtime. The other 64 EXISTS tags and all 65 TODO tags -held — so the document was 96% right, and the 4% was concentrated exactly where a -reader would act on it. - -Note which question actually paid. The first comparison asked *"is this endpoint -in the router?"* and returned 40 of 138 missing — mostly the document's own TODOs -and scope-prefix noise. The useful question was **"is this document's claim about -itself true?"**, which is answerable, small, and directly actionable. - -**Design documents and derived documents are different genera, and the audit only -speaks to the second.** A document written *before* the code says what should be -true; a derived document says what is. Do not "fix" the first kind by hanging -citations on it — check instead whether the system it describes was ever built -that way, and record the answer as findings. An uncited design corpus over a -large codebase is a **drift question**, not a formatting defect. - -**Expect the ratio to be alarming and mostly fine.** A "documents with zero -citations" query over one workspace returned **48 of 57**, and -nearly all of them were right to have none — API contracts, a ubiquitous-language -glossary, feature specs, product positioning. Sort by genus before you react, or -the number will push you into hanging citations on documents that precede the -code, which destroys what they are for. - -**Among the derived ones, though, uncited predicts wrong.** In the same corpus the -grounded derived documents had almost no defects; the one derived document with -**zero** citations had three, all in the direction that misleads someone doing -real work — two endpoint paths listed without the mount prefix they are registered -under, and two endpoints missing entirely. Nobody had checked, because there was -nothing to check against. Ground a derived document and you are not tidying it; -you are running its first test. - -**And watch the citation form itself.** Two citations in that corpus were written -`CODE: path` with a space, which every checker's regex missed — so they were never -verified by anything, in a document that declares itself *generated from code*. -One of the two resolved only by suffix; the path as written did not exist. A -convention followed 130 times and broken twice is broken invisibly. - -### Citations: whole, rooted, and re-checked - -**A citation must resolve, which means it must be whole.** Never elide a path. -`CODE:.../job_processor.py:265` reads tidily and is worthless: a reader cannot -open it and a checker cannot verify it. Write the repository-relative path in -full, every time, however long. - -Run the shipped audit over the corpus before you call a pass done — it reads -every citation in every document in seconds: - -```bash -node .modernpath/rdd/skills/rdd-audit/audit-citations.mjs # docs/ -node .modernpath/rdd/skills/rdd-audit/audit-citations.mjs docs/recovered --min=50 \ - --repository=api=/workspace/api --repository=legacy=/workspace/legacy -``` - -**This section used to carry an inline Python re-implementation, and removing it -is the point.** That snippet swept `docs/**` -only, matched the `CODE:` prefix and not bare `` `file.ex:12` `` citations, held -two line-parts so everything after the second in `file:N,M,P` was invisible, and -closed by claiming *"a failure is always real"* — which five separate false alarms -in one session disproved. Every one of those flaws was fixed in the script and -would have had to be fixed again in the snippet. - -A skill that tells a reader to hand-roll the check it also ships is not offering -a choice; it is offering the version nobody maintains. - -### The runbook, the published copy, and being findable - -**Audit the runbook — the lines a reader will type.** Ports, URLs, commands and -env var names are the most checkable claims in any document and the most -expensive to get wrong: a wrong architecture paragraph misleads, a wrong port -wastes an afternoon and gives no clue whether the reader broke the setup or the -document is lying. - -Take every URL and port the document names, and confirm each against what the -compose file or deploy config actually **publishes** — not what a service listens -on internally. The two are different, and documents routinely conflate them. - -One *Access points* table listed `http://localhost`, -`http://localhost:8082` and `http://localhost:8083/health`. The compose file -published exactly two ports and the strings `8082` and `8083` appeared **nowhere -in it**; both application services declared no `ports:` at all. Every URL but the -database was fiction, and the service sections above repeated it. - -A one-line check catches this class: - -```bash -grep -oE 'localhost:?[0-9]*' | sort -u # what the document promises -grep -oE '"[^"]*:[0-9]+"' docker-compose.yml # what is actually published -``` - -**"Listens on" is not "reachable".** A service with an internal port and no -published mapping is reachable only from inside the network. Say which it is — -the reader's next command depends on it. - -**Audit the published copy, not just the file.** A document that syncs to a -platform now exists twice, and the copy a reader opens is the remote one. Sync is -usually hook-driven and fire-and-forget, so a failed push leaves the repository -right and the platform stale with nothing raising a hand. - -Compare the far side after a pass. Content length is enough to catch drift -without pulling every document back: - -```sql --- the shape of the check, against whatever table holds the synced copies -select external_id, length(content) from system_documents -where external_id is not null order by external_id; -``` - -then diff those against the files on disk. In one checked sync, 21 documents -across two systems matched exactly — which is the result to expect and worth -recording, because the interesting version of this check is the day it does not. - -**The failure this guards against is silent by construction.** Earlier the same -day, a server rejecting *every* batch produced no error anywhere a person would -see it; the workspace looked fine and the platform was hours behind. A length -comparison would have shown it in one query. +For each inventory, state what one item is, how it was enumerated, and which +items are excluded with reasons. Compare both directions: entries lacking +support and relevant source items absent from the inventory. Account for each +item as covered, excluded with a reason, or unresolved. A disclosed unresolved +gap remains a gap. Counts and percentages describe that population; they do not +prove semantic coverage or authorize a lifecycle transition. -**A document nobody can find has not been written.** After producing or -superseding anything, update the corpus index — usually `docs/00-overview.md` or -a README table — and then check the index against the filesystem: +## Check citations -```bash -ls docs/*.md | xargs -n1 basename | while read f; do - grep -q "$f" docs/00-overview.md || echo "unlisted: $f" -done -``` - -One pass had written five documents, five ADRs and a guide, -synced them, and audited them — and listed **none of them** in the index, which -still routed readers to a document the same pass had marked superseded. The -corpus was correct and unreachable. - -**An index row carries a status, not just a name.** *Exists* and *is in force* -are different facts, and a filename alone conveys the first while implying the -second. One index gained nineteen rows; reading each document -to write its row revealed that one was a **tombstone** — its content had moved -months earlier and the file remained as a pointer — and another was an explicit -**proposal that was never ratified**. A reader meeting either as a bare filename -would have taken it for current guidance. - -Use a status vocabulary that distinguishes them — `derived`, `decided`, -`proposed`, `superseded`, `moved`, `living`, `operational`, `report` — and take -each row's purpose from that document's own heading and opening line. That keeps -the job mechanical enough to finish, and stops the index asserting things the -documents do not. - -Two cautions from running it. **Wildcard rows are invisible to exact matching**: -a `10–17 | 10-.md …` row legitimately covers eight files, and the naive -check called all eight missing — inspect the hits. And **listing is not -describing**: adding a filename with no one-line purpose makes the index longer -without making the corpus navigable, so where a backlog of unlisted documents -exists, record it as editorial work rather than padding the table. - -### Staleness travels in groups - -#### Enumerate, then diff - -**Audit an inventory against the thing it inventories.** A document that lists -*what exists* — a structure table, a context register, an endpoint table — makes -a claim no other check can reach. Citations resolve, counts match, prose stays -coherent, and the list is still missing things it purports to enumerate. Nothing -contradicts an absence. - -Three instances in one session, each found this way and by -nothing else: - -| Inventory | Checked against | Found | -|---|---|---| -| `00`'s repository structure table | the filesystem, and `AGENTS.md` | **4 of 9 subtrees missing**, including the decided auth boundary | -| an overview's *"the pass seeded one context"* | `ls tasks/*-REQUIREMENTS.md` | **eleven** ledgers existed | -| an architecture note's endpoint table | the router's mount block | 2 paths wrong, **2 endpoints absent** | - -**Enumerate the real thing, then diff the document against it — not the reverse.** -Reading the document and checking each entry exists finds *wrong* entries and -never *missing* ones, and missing is the half that rots. - -**"The real thing" is itself a derivation, and the first one is usually wrong.** -Enumerating one estate's tables gave **171** from `create table(`; the -real figure was **112** once 59 drops and 7 renames were applied — a 53% -overstatement that would have manufactured a finding. And 112 was still the wrong -denominator: the document claimed to map *Ecto schemas*, of which there were -**148**. **Enumerate the population the document claims to cover, not the one -that greps most easily** — and for anything with a history (migrations, changelogs, -event logs) the current set is creations *minus removals*, never creations. - -**A missing entry has three degrees, and only one is a defect.** Reporting all 49 -omissions as "undocumented" would have been false and would have buried the part -that mattered. Separate them before writing a word: - -1. **In a sibling document, absent here** — the two disagree; say which is more - current (29 of them; `02` was ahead of `40`). -2. **Specified elsewhere, but in no index or map** — the spec exists and the map - never caught up; point at its real home rather than restating it. -3. **Nowhere at all** — the only genuine gap. Six of the forty-nine, and the - only ones worth a requirement. - -Collapsing these into one number is how an audit becomes noise: a reader who -checks two entries, finds them documented elsewhere, and stops will discount the -whole finding — including the six that were real. - -#### Scoping an audit honestly - -**Before writing "not checked in this pass", price it.** Once a -banner was written saying the reverse comparison had not been run — and running -it took one command and found two real errors. The known-unknown note exists for -audits that would be **expensive or noisy**, not for ones a minute would settle; -used as a default it turns honest scoping into a licence to skip. The test is -cheap to apply: if you can state precisely what the check would be, you are -usually already most of the way through doing it. - -**Sometimes the right call is not to run the diff — then say what that leaves -unchecked.** A realtime catalog scoped itself to *cross-context* events; the code -carried 59 message atoms across 111 broadcast sites, most of them intra-context -progress. Diffing those would have produced dozens of false gaps and taught -everyone to ignore the next audit. Declining was correct. **Silence about it was -not** — the document now names the narrower claim nobody has verified: that the -catalog is *closed*. An audit you chose not to run is a known unknown, and -writing it down is the difference between scoping and quietly implying coverage. - -**An audit banner suppresses the next audit, so record which direction it ran.** -One API contract carried a prominent *"Tag audit: -69 endpoints tagged EXISTS, of which 5 are not in the router"* -— specific, honest, recent, and one-directional. It checked each documented entry -against the router and never the router against the document. Enumerating the -router found **264 routes across 42 prefixes** and a *"read first"* paragraph -claiming six whole contexts had **no JSON API**; all six had one, and the -controllers predated the audit by a month. The banner is why nobody looked: a -document that says it was verified reads as verified. **Write what was compared -against what** — *"every EXISTS tag checked against the router; the router was -not checked against this document"* — so the next pass knows which half is -unexamined instead of inferring both. - -**And weigh the two directions differently.** A documented-but-absent entry fails -loudly the first time someone calls it. A real-but-undocumented one fails as -silent duplicated work — six contexts' worth of backend scheduled that already -existed. The cheap direction is the one that gets audited; the expensive one is -the one that needs you to enumerate. - -For an HTTP inventory specifically, three things make the enumeration wrong if -you skip them: parse **scopes** so nested prefixes compose into full paths, drop -**comment lines** (a commented-out route reads as live), and remember that a -framework's non-verb route macros — Phoenix's `live`, mounts, forwards — are not -matched by a verb regex and are not JSON either. Getting any of those wrong -changes the count by enough to invent or hide a finding. - -#### After you correct something - -**A stale claim is rarely alone — grep for it after you correct it.** A document -states the same fact in more than one place: once in prose and once in a "key -patterns" list, once in an overview and once in a table. One -wrong migration mechanism was corrected in a schema section while an identical -claim sat forty lines below in a patterns list, and shipped uncorrected. After -every fix, search the corpus for the distinctive phrase and the thing it names. - -**A correction banner is not a correction, and it is worse than none.** A -runbook was once corrected by adding a *"superseded in part"* note -to the section that described a removed credential — and two later paragraphs in -the same file went on describing it as in use, one of them in the Notes section a -reader actually lands on. The banner made the document look maintained, which -made the surviving stale claims look reviewed. Either correct every instance or -don't signal that you did. - -**And the fact escapes the document.** The same retired credential was still -being handed to operators by `.kamal/secrets-common.example`, which told them to -mint it and set it. A fact lives in prose, in the example config that -operationalizes it, in templates, and in the code that reads the variable — and -correcting the prose is the easiest of the four. After correcting a fact, grep -the **repository** for the identifier, not the document for the sentence. - -That sweep is also where the real finding usually is. Chasing which of two -contradictory paragraphs was true is what surfaced that the credential was gone -from the *deployment* and still live in the *code* — a difference neither -paragraph stated, and a better result than picking a winner between them. **Treat -a document contradicting itself as evidence about the system, not as a typo.** - -**Audit the whole document, not the section you came for.** The same pass that -found the schema section six tables short stopped there — and the service -sections, unexamined, said "four job types" where the enum had five. A document -drifts uniformly; a section that is stale is evidence about its neighbours, not -an isolated defect. - -**And be as ready to be wrong as the document is.** In the same audit the pass -suspected `google-genai SDK directly` was stale, because the dependency manifest -listed `spaik-sdk`. Both were true: the backend goes through `spaik-sdk`, the -worker imports `google.genai` directly, and the *pass's own* document was the one -with the incomplete claim. Check the code before correcting a document — the -existing text may be recording something you have not found yet. - -#### Claims that age without being edited - -**A claim with a shelf life carries the moment it was true.** Counts, hashes, -versions, "currently N" — these are measurements, not facts, and a document that -states them bare will be wrong without ever being edited. - -Two ways to keep them honest, in order of preference: - -1. **Write the invariant, and let the instance illustrate it.** *"A credential - ping and a generation call carry different timeouts by design"* survives a new - vendor; *"six of the eleven adapters use 10 seconds"* does not. -2. **Where the number is the point, date it** — `RUN:` in the same - sentence, and say which direction it moves. *"88 of 132 paths resolved when - measured, a figure that falls as checkouts are pruned"* tells a reader both - what was true and how to think about it later. - -A byte-hash asserting that three files are identical is the sharp case: the -durable claim is *"a lockstep test fails if they drift"*; the hash is evidence for -a moment and needs its date beside it. - -**Traceability is bidirectional, and only one direction is ever checked.** A -ledger row citing a test is audited to death — the path resolves, the line exists, -the extension is right. Whether the **test** names the requirement is checked by -nothing, and that is the direction that survives the ledger being reorganised: a -test carrying `REQ-PLN-061` in its `describe` can be traced back from the code -even if every ledger row is rewritten. - -Measure it, because the number is not what you expect. On one measured workspace, -**129 of 181** cited test files named a requirement that cites them — **52 did -not**, in a workspace whose ledger citations were 100% resolving. - -Two cautions, both learned by getting it wrong. **Recognise a test by its path or -suffix**, never by the word *test* appearing in a filename: the first run counted -58 because it matched `specification_pipeline.ex` and `test_execution.ex`, which -are implementation. And **naming any one covering requirement is enough** — a test -covering three requirements does not need three ids, and demanding that turns -traceability into bookkeeping nobody maintains. - -**Abbreviation is how a correct citation becomes a broken one.** Sweeping 1,359 -file paths across a workspace's ledgers found **two** -failures, and neither was stale — both were *shortened*. One dropped a directory -segment (`controllers/app_token_controller.ex` for -`controllers/auth/app_token_controller.ex`); the other dropped a filename prefix -(`bridges_test.exs` for `work_events_bridges_test.exs`), in a sentence that had -just named `bridges.ex`, so the shorthand read naturally to whoever wrote it. - -That is the failure mode to expect in a mature corpus. A citation is rarely wrong -because the file moved — a move breaks a build. It is wrong because a writer -mid-sentence wrote the part a human reader would need and dropped the part a tool -needs. **Paste paths; never retype them**, and be most suspicious of the second -mention of a file, where the writer already has the context and the reader of the -tool does not. - -**Every citation resolves from the repository root**, not from wherever the code -felt close. In a monorepo with vendored subtrees this is not pedantry: in one measured workspace -**19 of 40** citations in one workspace's documents were written -relative to a subtree — `apps/core/lib/...` — which exists only under the -vendored subtree's own root. They read correctly beside the code and -cannot be opened by a reader at the root, which is where the document lives. - -Set the checker's working directory to the repository root and let it fail -loudly; a citation that only resolves after a human guesses the prefix is not a -citation. - -### Your own workspace, and documents against each other - -**But not on the prompts — and the tool now refuses.** Teaching material quotes -citations that must not resolve: an elided path shown as the thing *not* to -write, a template row citing `domain/user.ts`, a finding cited from the -repository it was found in. Pointed at `.claude/` or the installed `.modernpath/rdd/skills/` the audit reports broken and -elided paths that are all correct prose, and the obvious next move deletes the -lesson. It exits 2 with an explanation instead; `--force-prompts` overrides it for -a reader who will inspect every hit. - -That refusal was priced before it was written, not assumed: **132 backticked -paths across the prompts, 21 unresolved, all 21 legitimate** — templates, other -repositories, and paths the skill *instructs a pass to create*. Four looked like -real errors until opened. Nothing was being missed. - -**Run this audit on your own workspace, not only on the one you are analysing.** -The same pass that fixed elided citations in a client repository had left three -of them, and nineteen subtree-relative paths, in its own — because it had never -pointed the check at itself. - -**Line numbers rot faster than paths.** A citation surviving this check proves -the file exists and the line is in range, not that the line still says what you -claimed. Spot-check a sample by reading them back; cite a range when the exact -line is likely to move. - -**Cross-check the documents against each other, not only against the code.** -Where two documents in one repository describe the same set, the disagreement -tells you which one is being maintained. - -`ARCHITECTURE.md` was six tables short and named two that had -been dropped — while `docs/02-bounded-contexts.md`, sitting beside it, listed -**all 34 correctly**, every one owned by exactly one context. The pass had -adopted the stale document as `03` without noticing the accurate one next door. - -So when you adopt, compare the candidate against the corpus first. The document -that agrees with the code is the one to adopt or to extend from; the one that -disagrees is a finding, and often tells you *when* maintenance stopped. - -**Read the siblings before you enumerate the code — it is the cheaper audit, and -often the same finding.** One realtime map listed three PubSub -topics that do not exist. Finding it by enumeration meant extracting 111 -broadcast call sites across 1,075 files, and the first two extractors were wrong -(one matched progress payloads, not topics). **Two sibling documents already said -all three were net-new** — one called that context "mostly new projections", -another called the feature net-new over a flat column, and the third put the data -in a table column rather than behind a topic. Minutes, not an extractor. +Use `audit-citations.mjs` beside this skill for local Markdown citations. Pass +the actual document roots and source repositories explicitly. Substitute the +paths and repository keys in this command: -**And weigh agreement by count.** Three documents agreeing against a fourth is -stronger evidence than any single pairwise comparison, and it points at the -outlier without needing the code at all. Use the code to *confirm* the outlier, -not to discover it. - -**A check is useful when you can afford to inspect every hit.** That is the -threshold to iterate towards, and it usually takes two or three attempts at the -instrument rather than one. - -On one pass, verifying a data model's column claims: the first attempt -checked every backticked token in each row and returned **39 suspects out of -69** — it was reading the writer-service column as if those were column names. -Narrowing to the constraints cell and stripping enum braces gave **33 checked, 3 -hits**, and all three turned out to be values rather than columns. Three is -reviewable by hand; thirty-nine is a pile nobody reads, and a check nobody reads -is worse than none because it looks like diligence. - -Tighten the extraction until the hit list is short enough to read, then read all -of it. **Never report the raw hit list as findings** — every hit needs a human -look before it becomes a claim. - -**Exclude what the language treats as inert, and read the document's own caveats -before reporting a gap.** An extractor that cannot tell live code from commented -code manufactures findings. - -One route audit reported three surfaces missing from a document -titled *"every view, its actors, its use case"*. All three were in a commented-out -legacy block — and the document already listed them, with ten others, under a -**Dead surface** heading, citing the exact line range and raising a question about -the two admin routes still live above them. The document was more thorough than -the check. - -So before a gap becomes a finding: strip comments and disabled blocks from what -you extract, then search the document for the thing you think is missing — -including its "dead", "deprecated", "not covered" and "open questions" sections. -Documents written by a careful pass usually record their own exclusions, and a -gap that is already named is not a gap. - -### Report what held, not only what broke - -> How a *matcher* fails — false alarms against false passes, the danger in the -> "certain" bucket, counting what a pattern did not match — is in **Citations** -> above, where a pass first writes a checker. This section is what you then say. - -#### Reading a result before acting on it - -**Re-read the evidence at the moment you decide to act, not when you measure.** A -count is reported once and reused — in a row, a summary, the next decision — each -reuse further from the instrument. When a number is about to become a change, -**open two of the things it counts.** It costs a minute and is the last point at -which a measurement error is cheap. (A finding of *"3 rows with no question"* -survived measurement, a requirement, a commit and publication; acting on it opened -all three and every one had its question, in a field the matcher could not see.) - -**Watch for rules that grew around a bad number.** That finding had already -sprouted an acceptance criterion derived from a population that did not exist. A -wrong count does not merely misreport — it becomes policy, and the policy outlives -the correction unless you go looking for it. - -**A cross-reference is a claim, and its qualifier is the load-bearing part.** A -decision listing *"**Resolves:** OQ-101, OQ-102, …"* looks like authorisation to -close them; the same line ends *"(theme T-B **partial**)"*. **Batch-closing on a -cross-reference asserts a completeness its own author declined to claim** — and it -is tempting because it makes a number go down. When a reference resolves N things -at once, read what it says about *itself* first. - -**Read the false positives before dismissing them — sometimes they are the -finding.** A sweep scored 146 cited, 144 resolved; the two failures were library -modules the enumeration had not scanned. Dismissing them was correct about the -sweep and would have lost the result: one was `Ecto.Enum`, and a canonical -document stated flatly that `Ecto.Enum` is not used here. Ten schemas use it. Ask -what made a false positive *look* plausible before deleting it. - -#### When nothing was wrong - -**A clean audit is a result, and needs a banner as much as a dirty one.** Record -what was compared and what was left unchecked — an unbannered document invites the -next pass to redo the work, and *"we checked and it held"* is what stops that. - -**A clean audit is the cheapest moment to mechanise the rule it just confirmed.** -The sweep has done the expensive half: it established the corpus is clean, so the -new check goes green on the first run and you never mix enforcement with cleanup. -Add the same check after it breaks and you must fix N violations and land the -guard in one change — which is when guards get watered down to fit the mess. - -**And the exemptions come out of the sweep.** When a rule held across 948 rows -with four exceptions, all one status, that status became the carve-out. Had they -been a status the rule should cover, the answer would differ — and no amount of -thinking in advance would have said so. - -→ Every time an audit comes back clean, ask what one-line check would keep it that -way, and whether anything enforces it today. - -#### Writing the report - -**Say what held, not only what broke.** A derived document that passes its audit -is a result, and a report listing only corrections implies the rest was unread. - -**A finding needs its counterweight when the counterweight changes how it reads.** -*"Four optional credentials behave four different ways"* reads as carelessness -until you add that the two which would compromise the system fail loudly at boot. -Same facts, opposite conclusion. - -**Record what you checked and found correct, not only what you fixed.** Otherwise -the next pass re-derives it, and a corpus accumulates repeated audits of the same -clean thing while the unexamined half stays unexamined. - -**A confirmation you wrote yourself is not evidence.** Prove the instrument can -report the other answer before believing this one. The shapes that lie: - -- a check reporting **perfection** — feed it something known-broken; -- a check reporting **catastrophe** — a real document is rarely 80% wrong; -- a script printing **"done"** unconditionally; -- a **runtime probe** answering from the wrong state (`function_exported?` before - the module is loaded); -- an **exit status from the wrong command** — a pipeline returns the last stage's - status, so `… | tail` reports the success of `tail`. - -#### What actually rots - -**It is not documents that rot, it is *claims about sets*.** A corpus wrong about -which enums exist scored 146 of 146 on the module names it cited. Named references -hold — someone wrote the name while looking at it, and a rename breaks a build -long before it breaks a document. Quantified claims do not: - -| Shape | Example | Ages | -|---|---|---| -| Named reference | *"`Aiengine.Repo` injects the tenant filter"* | slowly — checkable and load-bearing | -| Coverage claim | *"every endpoint named here is in `07`"* | fast — new ones arrive without touching the document | -| Convention claim | *"enums are never `Ecto.Enum`"* | fast and silently — one exception falsifies it | -| Bare count | *"the ~80 Ecto schemas"* | fastest — wrong without anyone editing anything | - -**Aim an audit at the quantifiers** — *every, all, none, never, only, the N* — not -at the nouns. Grepping for those finds more rot per minute than reading, and each -hit settles with one command. - -**The quantifier is not what makes a claim fragile — writing it without opening -the code is.** The same sweep against a *derived* corpus found every absolute -holding. A derived pass states an absolute only after enumerating, so its -absolutes survive; a design document states one as an intention, and intentions -acquire exceptions silently. That is where to spend an audit first. - -Two cautions when running it. Most quantifier hits in a UX or product document are -**prescriptive** — *"never display a secret after creation"* is a requirement, not -a claim about code, and checking it against code is a category error. And scope -the check to the **declaration** you are testing: counting constraints in a window -around a class catches its neighbours. - -### Ids, capture, and siblings - -**Every id a document cites must be defined somewhere — check both directions.** -An id cited but never defined is a dangling reference; one defined but never cited -is either dead, or a gap in the document that should point at it. - -**Scope the check to the ids this workspace owns.** A platform that analyses other -repositories will carry ids belonging to them; a sweep that does not scope reports -those as dangling forever. - -**Register by reference, not by copy.** The full statement belongs in one place; -everywhere else cites its id. Two copies of a question diverge, and the reader -cannot tell which is current. - -**A finding recorded only in prose is not captured.** An audit ending with a note -inside the document it audited has told the document about itself. A discovery -becomes a ledger row or a backlog line, with provenance, or it is carried rather -than captured. - -**Cross-check siblings.** Where two documents describe the same set, the -disagreement tells you which one is being maintained. - -### Audit this document too - -**A prompt's own counts rot like any other document's.** An earlier version of this material said *"Three phases, in this order"* directly above a block listing -**four** — the sentence was written when there were three and never revisited -when D was added. It had shipped that way to two workspaces. - -Sweep your own stated counts against the thing they count, the same way you would -sweep a document you inherited: - -```bash -# the leading [^-[:alnum:]] matters: \b alone matches "six" inside "Thirty-six" -grep -onE '(^|[^-[:alnum:]])(two|three|four|five|six|seven|eight|nine|ten)[[:space:]]+(phases|documents|rules|steps|files|ways|copies)' SKILL.md +```text +node /audit-citations.mjs --repository== ``` -That refinement came from running this very command on this very -file: of 14 hits, one was *"six documents"* matched inside -*"Thirty-six documents"*. It is the same substring trap that has now produced a -false finding three times in one session — `NFR` inside `INFRA`, `Q-AGT-001` -inside `REQ-AGT-001`, and this. **A word boundary is not a word boundary when the -neighbouring character is a hyphen.** - -Then check each against its list. Here *"five documents"* matched five rows and -*"three files"* matched the contract's three copies — one defect in four claims, -which is roughly the hit rate to expect from any document nobody has counted. - -**Audit this document too — a prompt is a document.** Everything above applies to -the skill itself, and it fails the same ways. - -Once a rule was inserted by anchoring on a phrase, and the anchor -sat **inside a numbered checklist**: the new rule became "step 6", its code block -landed between steps, and the two-line step it displaced vanished. Nothing -errored. The skill still rendered. It was found by counting the steps and reading -them back — the same check the sequence itself prescribes. - -So after editing any structured document programmatically, verify the -**structure**, not just the text: item counts, balanced code fences, headings -still where they were. An anchored replacement is a blind edit, and prose anchors -are unstable exactly where documents are most structured. - -### The audit as a sequence - -The rules above are the reasoning; this is the order to run them in. Each step is -minutes, and each one has caught a real defect. - -1. **Groundedness.** `grep -rl 'CODE:' docs/ | wc -l` against the document count. - Zero citations over a real codebase is the headline finding, not a pass. -2. **Citations resolve**, from the repository root, no elided paths. The - shipped script does the whole corpus in seconds. -3. **Read a sample back.** Five citations, opened, compared to the sentence that - cites them. Resolution is not correctness. -4. **One countable set per document** — tables against `__tablename__`, routes - against the router, ports against what compose publishes, commands against - `package.json`. Probe the check with a value you know is absent. -5. **Status tags.** If the document marks claims EXISTS/TODO or built/planned, - verify those — they are the sharpest promise it makes. -6. **Ids resolve, and siblings agree.** Every `Q-`/`REQ-`/`ADR-` id cited is - defined somewhere; where two documents describe the same set, the - disagreement names the stale one. -7. **The runbook** — every URL, port and command a reader will type. -8. **The index.** Every document listed, with a status; every listed document - present. -9. **The published copy**, if the corpus syncs anywhere. -10. **Record what held**, with the date, inside the documents themselves. - -**Inspect every hit before writing any of it down.** Across one session this -sequence produced four false findings — an ASCII tree read as paths, commented-out -routes read as live, a writer-service column read as column names, a -module-plus-function read as a missing module — and each looked exactly like a -real defect until it was opened. +Repeat `--repository` for multiple repositories. Git worktrees and explicitly +declared non-Git roots are supported. A qualified reference has the form +`CODE:repository@revision:exact/path` or `TEST:` with the same structure. +Qualified Git revisions must match the declared checkout's HEAD; files must +exist in that commit, regardless of working-tree changes. +Unqualified references and `@unversioned` roots use local files. Use the +sanctioned source reader for captured dirty snapshots or other historical revisions. + +The checker resolves cited files for `CODE:`, `TEST:` and `DOC:`. The referenced +file carries the requirement or other item ID it supports. Optional symbol, +line, test-name and heading suffixes are ignored. The checker does not read +source contents or match strings within them. File resolution does not establish +that the source supports a claim or that a test executed. + +Describe missing artifacts as gaps in prose. Do not prefix an absent path with +`CODE:` or `TEST:` as though it were supporting evidence. Nearby words such as +“no” or “missing” do not exempt a citation from checking. + +Teaching examples may use the per-line `` marker or +an `example-citation` fenced block. Those references are reported as skipped, +never included in the checked denominator. Prompt directories are guarded by +the checker; use `--force-prompts` only for an intentional review of their +examples and real references. + +The checker uses these exit statuses: + +- `0`: the file-resolution check passed and the minimum citation count was met. +- `1`: broken, ambiguous, unsupported, or elided references, or fewer than + `--min=N` citations checked. +- `2`: a requested document target is missing, the source inventory is invalid, + or a guarded prompt target was refused. + +Exit `2` means the audit could not run on the requested inputs. Retain the error, +correct the inputs or invocation, and rerun; it is not a pass or an automatic +skip. The default minimum is one; `--min` is a citation-count guard against an +empty or incomplete scan, not an extraction-coverage threshold. Establish an +expected citation count independently before using a higher minimum. + +## Verify meaning and measurement + +Open each suspected defect and check the full relevant expression, declaration, +caller, and document context before reporting it. Distinguish a documented +exclusion or intended future behavior from an incorrect claim of current behavior. + +Check claims about complete sets against an independently enumerated population. +Account for removals, renames, disabled code, nested route prefixes, and other +language-specific constructs where they affect that population. Verify named +references in addition to counts; equal counts can describe different sets. + +Validate a new or changed checker against both known-good and known-bad inputs. +Check exit status, selected inputs, and actual output. Neither a high failure +rate nor a clean first run establishes whether the checker is correct. Keep +uninspected detector hits separate from confirmed findings. + +Compare related documents to locate disagreements, then resolve factual claims +against authoritative sources. Agreement among several documents does not make +their claim authoritative. Do not resolve conflicting intent by majority or +timestamp. + +For published copies, use the sanctioned publication/read-back route and compare +content or digests at the relevant revision. Content length alone cannot establish +equality. Check applicable runbook commands, configuration, document links, and +indexes against their actual targets. + +## Report + +Report the inspected scope and revisions, inventory units and counts, checked +citations, confirmed findings with direct sources, exclusions, and unresolved +or unsupported checks. State what was checked and held as well as what failed. +Preserve command output and exit codes for measurements used by a gate. + +Route findings through the invoking pass and the sanctioned process store when +they affect process records. A report does not itself change a requirement, +resolve a gap, approve a decision, or waive missing evidence. + +After an authorized correction, search the audited documents and relevant +repositories for other occurrences of the corrected claim and its identifiers, +including examples, configuration, and templates. Verify each occurrence +against current sources before editing. Correct only within the authorized +scope and report findings outside it. Recheck affected claims after changes. diff --git a/skills/rdd-audit/agents/openai.yaml b/skills/rdd-audit/agents/openai.yaml deleted file mode 100644 index 0f8cc80..0000000 --- a/skills/rdd-audit/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Audit" - short_description: "Verify citations, inventories, and instruments" - default_prompt: "Use $rdd-audit to verify this document or measurement against the code." diff --git a/skills/rdd-audit/audit-citations.mjs b/skills/rdd-audit/audit-citations.mjs index a1b36b2..c15d2b0 100755 --- a/skills/rdd-audit/audit-citations.mjs +++ b/skills/rdd-audit/audit-citations.mjs @@ -1,103 +1,31 @@ #!/usr/bin/env node -// Citation audit — the C8 procedure, as a program rather than a paragraph. -// -// Every `file:line` a document claims must resolve. This was re-derived by hand -// five times in one session and was wrong three of those — a regex whose -// non-greedy alternation matched `.ex` inside `.exs`, a display truncated at -// column 46 that made six correct citations look wrong, and a sweep that covered -// one subset while reporting a fraction as if it covered the corpus. -// Those are the three failures this file exists to stop repeating. -// -// node .modernpath/rdd/skills/rdd-audit/audit-citations.mjs [root...] -// -// KNOWN FALSE POSITIVES. Two shapes look like citations and are not, and both -// appear in real epic records: -// * example data inside a BDD scenario — "GIVEN a requirement whose code -// citation is `services/…/models.py:1477`" describes another workspace's -// file on purpose; -// * an illustrative quotation — prose showing how to write a good finding, -// quoting a path that need not exist. -// Neither is worth suppressing automatically: a rule broad enough to catch them -// would hide real rot. Read the failures before acting on them. -// -// Exits 0 when every citation resolves, 1 otherwise. Default roots: docs/ plus -// ARCHITECTURE.md if present. +// Resolve cited files in explicitly selected Markdown documents. +// Usage: node audit-citations.mjs --repository== +// Exits 0 for a passing check, 1 for findings or insufficient citations, +// and 2 for missing document targets, invalid source inventory, or refused prompt targets. import { execFileSync } from "node:child_process"; import { existsSync, readFileSync, readdirSync, statSync, realpathSync } from "node:fs"; import { join, resolve, relative, basename, isAbsolute } from "node:path"; -// An extension missing here is not reported as unresolved — it is not seen at -// all. On a .NET estate this printed "10/10 citations resolve" while silently -// skipping 710 of 720, which reads as a pass. Longest-first still holds. +// Unknown prefixed source extensions are reported, not silently skipped. const EXT = "heex|leex|eex|exs|tsx|yaml|proto|json|xslt|xml|jsp|xsl|mjs|cjs|ex|go|js|ts|yml|sh|py|rb|rs|java|kt|toml|sql|cs|vb|fs|php|swift|scala|erl"; -// Longest extensions first, and a boundary after — `.ex` must not match inside -// `.exs`, nor `.ts` inside `.tsx`. This is the first of the three failures. -// The boundary also refuses a dot followed by more name: the path is matched -// lazily, so `CODE:rel/env.sh.eex:45` used to stop at `env.sh` — a known -// extension followed by `.` — and report a correct citation as "no such file" -// while the `:45` fell off the match. A double extension is one file -// (`.sh.eex`, `.html.heex`); a trailing sentence period is still prose. -// `CODE: path` with a space is a rare deviation (2 instances in one corpus, -// RUN:2026-08-14) — tolerated so the citation is CHECKED rather than skipped. -// A citation may end at a NAME instead of a line — a test -// identifier survives edits to the file, a line number does not. Group 4 is -// that name; unchecked, `file.go:TestGoneForever` passed on file existence. -const PREFIXED = new RegExp(`(?:CODE|TEST): ?((?:[A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+:)?[A-Za-z0-9_./\\[\\]\\-]+?\\.(?:${EXT}))(?!\\.?[A-Za-z0-9])(?::(?:((?:\\d+(?:-\\d+)?)(?:,\\d+(?:-\\d+)?)*)|([A-Za-z_][A-Za-z0-9_]{2,})))?`, "g"); +// Consume optional navigation suffixes, but validate only the cited file. +const PREFIXED = new RegExp(`(?:CODE|TEST): ?((?:[A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+:)?[A-Za-z0-9_./\\[\\]\\-]+?\\.(?:${EXT}))(?!\\.?[A-Za-z0-9])(?::([^\\s\\x60<>|;)]*))?`, "g"); const UNKNOWN_PREFIX = /(?:CODE|TEST): ?[^\s`<>|;)]+/g; -// The full grammar, not the first two parts: a citation may list lines and -// ranges — file:N, file:N-M, file:N,M, file:N-M,P. A pattern holding only two -// groups matches every one of them and silently skips the rest; 188 citations -// in one corpus had 3+ parts, up to 9 (RUN:2026-08-14). -const BARE = new RegExp("`([A-Za-z0-9_./\\[\\]\\-]+\\.(?:" + EXT + ")):((?:\\d+(?:-\\d+)?)(?:,\\d+(?:-\\d+)?)*)", "g"); -// The ellipsis may sit mid-path, and -// the citation must END at a source file — an ellipsis inside /var/folders/…/ -// or a URL is prose. The narrower `CODE:...` form missed 22 real elisions. -// DOC: references point at documents and were checked by nothing until -// RUN:2026-08-14, when a sweep found one broken in 131 — a ledger citing a spec -// that had never existed under that name, while its siblings cited the real -// prompt file. Same shape as CODE:, so it gets the same treatment. -// An anchored form exists too — DOC:file.md#Section — and the section was -// checked by nothing until RUN:2026-08-14, when 17 of them turned out to hide -// one malformed compound anchor (`#2.1/#5`). -const DOCREF = /DOC: ?([A-Za-z0-9_./\-]+\.md)(?:#([^ )|`\u00b7]+))?/g; +// Bare path:locator citations also resolve only the file. +const BARE = new RegExp("`([A-Za-z0-9_./\\[\\]\\-]+\\.(?:" + EXT + ")):([^\\s`<>|;)]*)", "g"); +const DOCREF = /DOC: ?([A-Za-z0-9_./\-]+\.md)(?:#([^\s)|`\u00b7]+))?/g; const ELIDED = /(?:CODE:|`)(?:[A-Za-z0-9_.\\[\\]\-]+\/)*\.\.\.\/[A-Za-z0-9_.\/\\[\\]\-]*\.(?:exs|tsx|ex|go|js|ts|py|rb|rs|java|kt|sql|yml|yaml|json|sh|heex)\b/g; -// C8: a row naming a gap is not a citation. "there is no test_draft_service.py" -// is the most useful thing a derivation pass produces, and an audit that counts -// it as broken teaches the next pass to stop naming what is missing. -// Bare `not`/`never` are NOT in this list: alone they carry no absence meaning -// ("the handler is not used anymore; its logic moved to `CODE:new.go:900`"), yet -// inside the 60-char window they excused any failing citation trailing an -// unrelated negation — hiding real rot behind a stray "is not". Every word kept -// names absence directly; a deliberate gap still reads "no"/"there is no"/etc. -const ABSENCE = /\b(no|missing|absent|does not exist|there is no|without)\b[^.]{0,60}$/i; - const roots = process.argv.slice(2).filter((a) => !a.startsWith("--")); -// A vacuity floor the CALLER sets, because only the caller knows its corpus. A -// generic run requires at least one citation; a gate over a corpus that always -// carries citations passes --min=N, so a scan that silently matched almost -// nothing — the ".NET estate printed 10/10 while skipping 710" failure in its -// residual form, where the count itself is the tell — exits non-zero instead of -// reading as a clean pass. +// The minimum is a caller-supplied citation count, not semantic coverage. const minArg = process.argv.find((a) => a.startsWith("--min=")); const minCitations = minArg ? Math.max(1, parseInt(minArg.slice(6), 10) || 1) : 1; const targets = roots.length ? roots : ["docs", ...(existsSync("ARCHITECTURE.md") ? ["ARCHITECTURE.md"] : [])]; -// Refuse to audit the prompts. Teaching material deliberately -// quotes citations that do not resolve — an elided `CODE:.../job_processor.py` -// shown as the thing NOT to write, a template row citing `domain/user.ts`, a -// finding cited from the workspace it was found in. Run on `.claude/` this -// reports 3 broken and 2 elided, every one of them correct prose, and the -// obvious next move is to "fix" them, which deletes the lesson. -// -// Checked by hand on RUN:2026-08-14: 132 backticked paths across the prompts, -// 21 unresolved, and all 21 legitimate — generic templates, evidence from other -// repositories, and paths the skill *instructs a pass to create*. There is -// nothing here for this tool to find, so the refusal costs no coverage. The -// gate's own elided check excludes `.claude/` for the same reason; this is the -// standalone half of that guard. +// Prompt corpora contain deliberate examples; auditing them requires opt-in. const prompts = targets.filter((t) => { const p = t.replace(/^\.\//, ""); return p.startsWith(".claude") || p.startsWith(".modernpath/rdd/skills"); @@ -105,8 +33,7 @@ const prompts = targets.filter((t) => { if (prompts.length) { console.error( `refusing to audit ${prompts.join(", ")} — installed skills are teaching material, and their\n` + - "unresolvable citations are deliberate (bad examples, other repositories,\n" + - "prescribed outputs). Verified by hand RUN:2026-08-14: no real rot there.\n" + + "citations may be deliberate examples rather than claims about this checkout.\n" + "Pass --force-prompts only if you intend to read every hit before acting.", ); if (!process.argv.includes("--force-prompts")) process.exit(2); @@ -143,34 +70,27 @@ try { if (!statSync(root).isDirectory() || repositories.some(r => r.key === key || r.root === root)) throw new Error("repository keys and roots must be distinct directories"); let revision = "unversioned"; let files; + let committedFiles; if (existsSync(join(root, ".git"))) { const git = (...args) => execFileSync("git", ["-C", root, ...args], { encoding: "utf8", maxBuffer: 64 << 20, stdio: ["ignore", "pipe", "pipe"] }); revision = git("rev-parse", "HEAD").trim(); + committedFiles = new Set(git("ls-tree", "-r", "--name-only", "-z", revision).split("\0").filter(Boolean)); files = git("ls-files", "-z", "--cached", "--others", "--exclude-standard").split("\0").filter(Boolean).map(path => join(root, path)); } else { if (!declared.length) throw new Error("not a Git repository; declare every source root with --repository=key=directory"); files = walk(root, []); } files = [...new Set(files.filter(path => existsSync(path) && statSync(path).isFile() && inside(root, realpathSync(path))))]; - repositories.push({ key, root, revision, files }); + repositories.push({ key, root, revision, files, committedFiles }); } } catch (error) { console.error(`source inventory refused: ${error.message}`); process.exit(2); } -const lineCache = new Map(); -function lineCount(p) { - if (!lineCache.has(p)) { - try { lineCache.set(p, readFileSync(p, "utf8").split("\n").length); } - catch { lineCache.set(p, -1); } - } - return lineCache.get(p); -} - const resolutionErrors = new Map(); -// A suffix with multiple matches is ambiguous, not permission to pick the one -// whose line count happens to fit. Typed references resolve only exact paths. +// A path suffix with multiple matches is ambiguous. Typed references resolve +// only exact paths at the declared revision. function candidates(path, exactOnly = false) { const typed = path.match(/^([A-Za-z0-9_.-]+)@([A-Za-z0-9_.-]+):(.+)$/); let found; @@ -181,7 +101,16 @@ function candidates(path, exactOnly = false) { return []; } const exact = resolve(repo.root, typed[3]); - found = inside(repo.root, exact) && repo.files.includes(exact) ? [exact] : []; + if (!inside(repo.root, exact)) return []; + if (repo.committedFiles) { + if (!repo.committedFiles.has(relative(repo.root, exact))) { + resolutionErrors.set(path, "no such file at the cited revision"); + return []; + } + found = [exact]; + } else { + found = repo.files.includes(exact) ? [exact] : []; + } } else { const exact = repositories.flatMap(repo => repo.files.filter(file => relative(repo.root, file) === path)); found = exact.length || exactOnly ? exact : repositories.flatMap(repo => repo.files.filter(file => file.endsWith("/" + path))); @@ -194,8 +123,13 @@ function candidates(path, exactOnly = false) { return found; } +const missingTargets = targets.filter(target => !existsSync(target)); +if (missingTargets.length) { + console.error(`document inventory refused: missing target(s): ${missingTargets.join(", ")}`); + process.exit(2); +} + function markdownFiles(target) { - if (!existsSync(target)) return []; if (statSync(target).isFile()) return target.endsWith(".md") ? [target] : []; return readdirSync(target, { withFileTypes: true }).flatMap((e) => e.isDirectory() ? markdownFiles(join(target, e.name)) @@ -204,18 +138,12 @@ function markdownFiles(target) { const docs = targets.flatMap(markdownFiles).sort(); let ok = 0; -let gaps = 0; let examples = 0; const broken = []; const elided = []; -// A fenced block whose opening line carries `example-citation` is a VERBATIM -// DISPLAY of citations, not a set of claims: a client-facing document showing a -// real ledger row cites paths in the CLIENT's repository, which can never -// resolve here. The per-line marker would work but renders inside the code -// sample a client reads, so the opt-out moves to the fence's info string where -// it is invisible. Opt-in per block, never blanket — citations in unmarked -// fences are still audited (RUN:2026-08-17). +// Only explicitly marked teaching fences are exempt; ordinary code fences +// still contain auditable citations. function exemptFenceRanges(lines) { const ranges = []; let open = null; @@ -281,71 +209,30 @@ for (const doc of docs) { if (inExemptFence(m.index) || //.test(lines[lineNo - 1] ?? "")) { examples++; continue; } const found = candidates(m[1], true); if (!found.length) { broken.push({ doc, lineNo, path: m[1], why: resolutionErrors.get(m[1]) || "no such document" }); continue; } - if (m[2]) { - // A heading may hyphenate where the anchor spaces, and vice versa. - // Escape FIRST, then loosen: doing it the other way mangles the character - // class you just inserted, and "#Follow-Up" reported a missing section that - // was plainly there (RUN:2026-08-14). - const want = m[2].replace(/[.*+?^${}()|[\]\\]/g, (c) => "\\" + c).replace(/(?:\\?-|\s)+/g, "[-\\s]+"); - const re = new RegExp("^#{1,6} .*" + want, "mi"); - if (!found.some((f) => re.test(readFileSync(f, "utf8")))) { - broken.push({ doc, lineNo, path: `${m[1]}#${m[2]}`, why: "no such section" }); - continue; - } - } ok++; } } -// The absence exemption is applied ONLY to a citation that would otherwise fail. -// Applied up front it is a false-negative machine: on a real corpus it skipped -// 116 resolvable citations, because prose like "the mechanism has no test of any -// kind (`CODE:…/job_processor.py`)" says *no test*, not *no file* — the cited -// path exists and must still be checked. Excusing a gap must never be able to -// hide a citation that could have been verified. function check(doc, text, m) { - const [, path, spec, name] = m; + const [, path] = m; const lineNo = text.slice(0, m.index).split("\n").length; - // A document that TEACHES citation grammar must contain citations that do not - // resolve — that is the lesson, not rot (`docs/onboarding/05-contracts.md` §3 - // shows accepted and rejected forms). The same judgement the gate already - // makes for `.claude/` teaching material, narrowed from a whole tree to one - // line: an `` marker on the citing line opts that - // line out. Deliberately per-line — exempting the file would blind the audit - // to real rot in the same document, and this audit has caught real rot there - // (RUN:2026-08-17: two migration paths and a dead anchor). + // Explicit teaching examples are excluded from the checked denominator. if (//.test(text.split("\n")[lineNo - 1] ?? "")) { examples++; return; } const found = candidates(path); - // A named citation is verified by the name, not the position — that is the - // whole point of citing one. - if (name && found.length) { - if (found.some((f) => readFileSync(f, "utf8").includes(name))) { ok++; return; } - broken.push({ doc, lineNo, path: `${path}:${name}`, why: "no such test or symbol in the file" }); + if (!found.length) { + broken.push({ doc, lineNo, path, why: resolutionErrors.get(path) || "no such file" }); return; } - // Every part of a compound citation is a citation. The highest line any part - // names is what the file must reach. - const parts = spec ? spec.split(",") : []; - const hi = parts.reduce((a, p) => Math.max(a, ...p.split("-").map(Number)), 0); - const resolves = found.length && (!parts.length || found.some((f) => lineCount(f) >= hi)); - if (resolves) { ok++; return; } - - if (!resolutionErrors.has(path) && ABSENCE.test(text.slice(Math.max(0, m.index - 70), m.index))) { gaps++; return; } - - broken.push({ - doc, lineNo, - path: spec ? `${path}:${spec}` : path, - why: resolutionErrors.get(path) || (found.length ? `no candidate reaches line ${hi}` : "no such file"), - }); + ok++; } const total = ok + broken.length; -const belowFloor = minCitations > 0 && total < minCitations; -console.log(`${ok}/${total} citations resolve across ${docs.length} documents` + - (gaps ? ` (+${gaps} named gaps excused — a cited path stated as absent)` : "") + +const belowMinimum = total < minCitations; +console.log(`${ok}/${total} citations resolve to files across ${docs.length} documents` + (examples ? ` (${examples} teaching examples skipped; not checked citations)` : "")); +console.log("File resolution only; source contents and navigation suffixes are not checked."); if (elided.length) { console.log(`\n${elided.length} elided path(s) — a citation that resolves to nothing:`); @@ -355,10 +242,9 @@ if (broken.length) { console.log(`\n${broken.length} broken:`); for (const b of broken) console.log(` ${b.doc}:${b.lineNo} ${b.path} — ${b.why}`); } -if (belowFloor) { - console.log(`\nvacuity floor: ${total} citation(s) checked, below the required --min ${minCitations} —` + - " too little matched to be a real audit (a broken scan otherwise reads as a clean pass)"); +if (belowMinimum) { + console.log(`\ninsufficient citations: ${total} checked; --min requires ${minCitations}`); } -if (!elided.length && !broken.length && !belowFloor) console.log("no elided paths"); +if (!elided.length && !broken.length && !belowMinimum) console.log("no elided paths"); -process.exit(broken.length || elided.length || belowFloor ? 1 : 0); +process.exit(broken.length || elided.length || belowMinimum ? 1 : 0); diff --git a/skills/rdd-audit/audit-citations.test.mjs b/skills/rdd-audit/audit-citations.test.mjs index 4637ce1..6d99841 100644 --- a/skills/rdd-audit/audit-citations.test.mjs +++ b/skills/rdd-audit/audit-citations.test.mjs @@ -72,7 +72,7 @@ test("a nonempty corpus with no recognized references is not a passing audit", t f.file("report.md", "No traceable citations were emitted."); const result = f.run(`--repository=legacy=${join(f.root, "repo")}`, "report.md"); assert.equal(result.status, 1, result.stdout + result.stderr); - assert.match(result.stdout, /vacuity/); + assert.match(result.stdout, /insufficient citations/); }); test("the default single-repository audit still works from a nested directory", t => { @@ -94,7 +94,7 @@ test("unknown prefixed source extensions cannot disappear beside a valid citatio assert.match(result.stdout, /missing.unknown/); }); -test("exempt teaching examples cannot satisfy the checked-citation floor", t => { +test("exempt teaching examples cannot satisfy the checked-citation minimum", t => { const f = fixture(t); f.file("repo/code.xml", "one"); f.file("report.md", "CODE:missing.xml:2 \n"); @@ -107,3 +107,107 @@ test("exempt teaching examples cannot satisfy the checked-citation floor", t => assert.equal(mixed.status, 0, mixed.stdout + mixed.stderr); assert.match(mixed.stdout, /1\/1 citations resolve/); }); + +test("source citations resolve files regardless of navigation suffixes or contents", t => { + const f = fixture(t); + f.file("repo/subject.ex", "# REQ-EXAMPLE-001\n"); + f.file("repo/subject_test.go", "// REQ-EXAMPLE-001\n"); + f.file("report.md", [ + "CODE:subject.ex", + "CODE:subject.ex:validate/1", + "CODE:subject.ex:validator", + "CODE:subject.ex:Sample.Auth", + "CODE:subject.ex:900-999", + "CODE:subject.ex:0,2-1", + "TEST:subject_test.go", + "TEST:subject_test.go:TestParent/Child", + "`subject.ex:missing_symbol`", + ].join("\n")); + const result = f.run(`--repository=repo=${join(f.root, "repo")}`, "report.md"); + assert.equal(result.status, 0, result.stdout + result.stderr); + assert.match(result.stdout, /9\/9 citations resolve to files/); + assert.match(result.stdout, /source contents and navigation suffixes are not checked/); +}); + +test("navigation suffixes never rescue a missing source file", t => { + const f = fixture(t); + f.file("repo/subject.ex", "# REQ-EXAMPLE-001\n"); + f.file("report.md", "CODE:subject.ex\nCODE:missing.ex:validate/1\nTEST:missing_test.exs:TestParent/Child\n"); + const result = f.run(`--repository=repo=${join(f.root, "repo")}`, "report.md"); + assert.equal(result.status, 1, result.stdout + result.stderr); + assert.match(result.stdout, /1\/3 citations resolve to files/); + assert.match(result.stdout, /missing.ex.*no such file/); + assert.match(result.stdout, /missing_test.exs.*no such file/); +}); + +test("absence wording does not excuse missing files", t => { + const f = fixture(t); + f.file("repo/subject.py", "# REQ-EXAMPLE-001\n"); + f.file("report.md", "CODE:subject.py\nMissing validation in `CODE:absent.py:1`.\n"); + const result = f.run(`--repository=repo=${join(f.root, "repo")}`, "report.md"); + assert.equal(result.status, 1, result.stdout + result.stderr); + assert.match(result.stdout, /1\/2 citations resolve to files/); + assert.match(result.stdout, /absent.py.*no such file/); +}); + +test("plain gap descriptions are not supporting citations", t => { + const f = fixture(t); + f.file("repo/subject.py", "# REQ-EXAMPLE-001\n"); + f.file("report.md", "CODE:subject.py\nThere is no `test_missing.py`; verification remains unresolved.\n"); + const result = f.run(`--repository=repo=${join(f.root, "repo")}`, "report.md"); + assert.equal(result.status, 0, result.stdout + result.stderr); + assert.match(result.stdout, /1\/1 citations resolve to files/); +}); + +test("a missing document root cannot disappear beside a valid report", t => { + const f = fixture(t); + f.file("repo/subject.py", "# REQ-EXAMPLE-001\n"); + f.file("report.md", "CODE:subject.py\n"); + const result = f.run(`--repository=repo=${join(f.root, "repo")}`, "report.md", "missing-docs"); + assert.equal(result.status, 2, result.stdout + result.stderr); + assert.match(result.stderr, /missing-docs/); +}); + +test("revision-qualified files must exist in the commit regardless of working-tree changes", t => { + const f = fixture(t); + const repo = join(f.root, "repo"); + f.file("repo/subject.py", "# REQ-EXAMPLE-001\n"); + const git = (...args) => execFileSync("git", ["-C", repo, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }); + git("init"); git("add", "."); git("-c", "user.name=Test", "-c", "user.email=test@example.test", "commit", "-m", "fixture"); + const revision = git("rev-parse", "HEAD").trim(); + f.file("repo/subject.py", "changed contents\n"); + f.file("repo/untracked.py", "new file\n"); + const args = [`--repository=repo=${repo}`, "report.md"]; + + f.file("report.md", `CODE:repo@${revision}:subject.py\nCODE:untracked.py\n`); + let result = f.run(...args); + assert.equal(result.status, 0, result.stdout + result.stderr); + assert.match(result.stdout, /2\/2 citations resolve to files/); + + f.file("report.md", `CODE:repo@${revision}:untracked.py\n`); + result = f.run(...args); + assert.equal(result.status, 1, result.stdout + result.stderr); + assert.match(result.stdout, /no such file at the cited revision/); + + rmSync(join(repo, "subject.py")); + f.file("report.md", `CODE:repo@${revision}:subject.py\n`); + result = f.run(...args); + assert.equal(result.status, 0, result.stdout + result.stderr); + f.file("report.md", "CODE:subject.py\n"); + result = f.run(...args); + assert.equal(result.status, 1, result.stdout + result.stderr); +}); + +test("document citations resolve files without inspecting headings", t => { + const f = fixture(t); + f.file("repo/guide.md", "REQ-EXAMPLE-001\n"); + const args = [`--repository=repo=${join(f.root, "repo")}`, "report.md"]; + f.file("report.md", "DOC:guide.md#Trace completeness\nDOC:guide.md#missing-heading\nDOC:guide.md\n"); + let result = f.run(...args); + assert.equal(result.status, 0, result.stdout + result.stderr); + assert.match(result.stdout, /3\/3 citations resolve to files/); + f.file("report.md", "DOC:missing.md#Trace completeness\n"); + result = f.run(...args); + assert.equal(result.status, 1, result.stdout + result.stderr); + assert.match(result.stdout, /missing.md.*no such document/); +}); diff --git a/skills/rdd-build/SKILL.md b/skills/rdd-build/SKILL.md index 52de3ce..e155737 100644 --- a/skills/rdd-build/SKILL.md +++ b/skills/rdd-build/SKILL.md @@ -1,6 +1,6 @@ --- name: rdd-build -description: Execute the AI-owned TDD loop for one approved system requirement from TODO through current lower evidence and IN_REVIEW. Use for new or changed SR behavior after human entry approval. Repeat RED, GREEN, cleanup, lower verification, and separate affected-UR upper validation until the approved trace needs pass or an exact replanning condition is found. Use rdd-verify instead for confirmed as-built PENDING_VERIFICATION behavior. +description: Implement one approved SR from TODO through current lower evidence and IN_REVIEW using RED, GREEN, cleanup and regression checks. Use after normal development entry for new or changed behavior. Use rdd-verify for entered verification work and rdd-reverse-engineer-verify for eligible source-scoped baselines with existing proof. --- # Build one SR slice @@ -12,11 +12,15 @@ code, tests, and current records. ## Procedure -1. Orient and select exactly one approved `TODO` or `IN_PROGRESS` SR with - current planning and no active hold. Work on a reviewable feature branch and - preserve unrelated changes. -2. Before its first implementation iteration, establish every selected affected - UR's upper RED for the expected reason. Keep that evidence on the UR. +1. Check that current applied normal entry approval covers the whole selected + delivery scope, including the Epic when selected, under `PROCESS.md`. + Then select exactly one `TODO` or `IN_PROGRESS` SR with current planning + and no active hold. A reopened baseline without that approval needs + planning and entry first. Work on a + reviewable feature branch and preserve unrelated changes. +2. Before its first implementation iteration, establish upper RED for selected + UR scenarios requiring new evidence. Re-validation of previously proven + unchanged scenarios needs no new RED. Keep upper evidence on the UR. 3. Select one unmet approved SR clause, establish its focused lower RED for the expected reason, and link the stable test identity to the clause. 4. Implement the smallest behavior that makes the focused evidence pass. diff --git a/skills/rdd-build/agents/openai.yaml b/skills/rdd-build/agents/openai.yaml deleted file mode 100644 index 5a9bdd1..0000000 --- a/skills/rdd-build/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Build" - short_description: "Execute one red-first SR slice" - default_prompt: "Use $rdd-build to execute the next approved SR slice." diff --git a/skills/rdd-cold-review/SKILL.md b/skills/rdd-cold-review/SKILL.md index 303238c..3291923 100644 --- a/skills/rdd-cold-review/SKILL.md +++ b/skills/rdd-cold-review/SKILL.md @@ -11,11 +11,11 @@ in a consuming repository), versioned product sources, selected requirements, optional epic/specifications, technical reconnaissance, and repository state at the recorded revision. -The independent context is a recorded fact of the verdict, not a claim: the -verdict is recorded from that context, and a verdict recorded from the -authoring context is not a cold review. Run as a delegated pass, this skill -returns its findings and verdict and writes nothing to the store; the -orchestrating session records them (`PROCESS.md` §Delegated passes). The +Record the reviewer and independent review context with the verdict; an +author's self-review is not a cold review. Run as a delegated pass, this skill +returns its findings and verdict and writes nothing to the store. The +orchestrating session records them with reviewer attribution +(`PROCESS.md` §Delegated passes). The review audits the change the packet proposes, not the packet as a document. ## Procedure @@ -24,19 +24,21 @@ review audits the change the packet proposes, not the packet as a document. unstated author reasoning. 2. Verify the affected repositories, files, symbols, entry points, callers, writers, readers, and every changed control/data-flow hop. Where the packet - carries a state inventory, enumerate it: attack each cell and each - transition between concurrent writers in both directions, and file a row - the change touches that the inventory lacks. Where the change touches + carries a state inventory, check its writers, readers, concurrent updates, + failure behavior, and mitigations. Record missing affected state. Where the change touches state and the packet carries no inventory, that absence is the first - material finding. Where the change touches a surface a delivered - requirement owns, the packet names that record and the constraint it - carries; a surface with no named owner, or a constraint the change - contradicts without a scope decision, is a material finding. + material finding. Check applicable existing requirement ownership and + constraints. A contradiction with delivered acceptance needs a scope + decision; absence of an existing owner does not itself block new behavior. 3. Examine contracts, schemas, compatibility, persistence, integrations, failure propagation, retries, concurrency, security, and operational risks where applicable. 4. Assess feasibility, dependency order, SR boundaries, reuse of established patterns, testability, expected RED reasons, and proportional gates. + Check each planned RED failure reason against the code at the recorded + revision, including any planned temporary mutation for entered verification. + A case that would pass under its stated RED conditions is a testability + finding; do not defer that check to build. 5. Identify any product, architecture, acceptance, or scope choice that lacks human authority. 6. Record each finding with severity, direct source, owner, and disposition as @@ -46,24 +48,24 @@ review audits the change the packet proposes, not the packet as a document. question for that human, never a packet edit; a finding whose fix preserves a delivered acceptance or applies a stance the human has stated is not such a question — name the rule it applies instead. A `RESOLVED` disposition - names its kind — packet edit, scope action with its record, or decision - with its `USER:` source — and a packet edit only clarifies what the change - already contained: a resolution that adds an acceptance criterion, widens - a boundary, or adds a flow hop is a scope question returned to `rdd-plan`, - never a resolution. A fix you propose is a claim for the author to verify - at the revision, not an instruction; the round that follows re-verifies - it as it does a carried closure. + records the correction and evidence, or the scope decision and its `USER:` + source. Packet edits may clarify what the change already contained; no new + mechanism enters the packet during the review cycle. A fix needing a new + mechanism, acceptance criterion, wider boundary, or flow hop is a scope + question for `rdd-plan`, with its own reconnaissance as its own change. + Other changed scope or material decisions also return to `rdd-plan`. + Before marking a finding `RESOLVED`, reread every symbol, path, and test + named by its correction at the recorded revision. A fix you propose is a + claim for the author to verify through the same reconnaissance; the round + that follows re-verifies it as it does a carried closure. 7. Grade materiality by what the finding would change. A finding about the packet's wording, counts, or citations that alters none of the code, tests, interfaces, or risks is a note and never blocks; traceability is material only when a builder or a gate would act on the wrong citation - (`PROCESS.md` §Planning and readiness). A command, a pattern, or a test - name the packet need not carry is audited by dropping it: the finding is a - note that the line goes, never a blocker on its syntax. -8. Bound the rounds: at most two on one change. On a second round whose new - blocking findings are about the packet rather than the change, return - `FAIL` with the instruction to cut the packet, not to expand it. Do not - start a third round: stop and hand what is known to a human. + (`PROCESS.md` §Planning and readiness). +8. Run at most two rounds on the selected planning scope. After a second + failed round, report the remaining material findings to the human; + do not start a third round automatically. 9. Return the cold-review trace gate `PASS` only when the material-finding rule in `PROCESS.md` is satisfied. Otherwise return `FAIL` with exact blockers. @@ -76,9 +78,8 @@ verdict as entry approval. ## Report -Lead with material findings, then state the round number, the context the -verdict is recorded from, the reviewed fingerprints, finding dispositions -(notes separated from blockers), which findings fall on mechanisms an earlier -round's resolutions introduced, trace-gate verdict, and the exact handoff: -`rdd-plan` after a failure, `rdd-entry-review` after a current pass, or the -human after a bounded third round. +Lead with material findings, then state the round number, reviewer and review +context, the reviewed fingerprints, finding dispositions +(notes separated from blockers), trace-gate verdict, and the exact handoff: +`rdd-plan` after the first failure, `rdd-entry-review` after a current pass, +or the human after a second failed round. diff --git a/skills/rdd-cold-review/agents/openai.yaml b/skills/rdd-cold-review/agents/openai.yaml deleted file mode 100644 index b01f67b..0000000 --- a/skills/rdd-cold-review/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Cold Review" - short_description: "Audit a requirement plan independently" - default_prompt: "Use $rdd-cold-review to audit this planning packet independently." diff --git a/skills/rdd-completion-review/SKILL.md b/skills/rdd-completion-review/SKILL.md index 8b244d1..4f9c94d 100644 --- a/skills/rdd-completion-review/SKILL.md +++ b/skills/rdd-completion-review/SKILL.md @@ -14,11 +14,19 @@ records, and derived views. 1. Treat completion as unproven. Audit every scoped requirement clause, acceptance scenario, declared relation, gate, evidence result, and - completion condition against direct current sources. + completion condition against direct current sources. Already DONE members + are proof dependencies; keep them DONE when their evidence is current and + exclude them from new acceptance transitions. Obtain an independent code + review of the built change for Epic scope. For single-SR scope, obtain one + when required by project gates or requested by the user. Use a context + independent of implementation; record the reviewer, reviewed revision, + findings, and verdict separately from planning review. Verify fixes against + their commits and test evidence. 2. Stop for any `DERIVED` dependency, candidate link counted as authoritative, - stale or inherited-unverified evidence, missing RED observation, material - finding from the packet's cold review or from a review of the change, - undisclosed gap, or incomplete reconciliation. + stale or inherited-unverified evidence, missing required RED observation, + missing required independent code review, unresolved material finding from + planning or implementation review, undisclosed gap, or incomplete + reconciliation. 3. If the pre-delivery audit passes, deliver through the project's authorized integration path while keeping awaiting entities `IN_REVIEW`. 4. Re-run or confirm evidence against the delivered revision — the revision diff --git a/skills/rdd-completion-review/agents/openai.yaml b/skills/rdd-completion-review/agents/openai.yaml deleted file mode 100644 index 6d86983..0000000 --- a/skills/rdd-completion-review/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Completion Review" - short_description: "Audit delivery and apply completion" - default_prompt: "Use $rdd-completion-review to audit and complete this delivered scope." diff --git a/skills/rdd-deliver/SKILL.md b/skills/rdd-deliver/SKILL.md index 15843a3..e56bf2f 100644 --- a/skills/rdd-deliver/SKILL.md +++ b/skills/rdd-deliver/SKILL.md @@ -1,6 +1,6 @@ --- name: rdd-deliver -description: Drive an Epic or single-SR scope through the complete requirement-driven delivery loop. Use when work is requested end to end rather than as one explicitly bounded process pass. Sequence discovery or confirmation, planning, cold review, human entry, red-first execution or as-built verification, delivery, reconciliation, human completion, and triage until the selected scope is DONE or OBSOLETE, or an exact human or external prerequisite prevents further progress. +description: Drive selected requirements through the applicable delivery path. Use for end-to-end work including normal planning, entry, red-first development and completion, or existing-proof verification and acceptance of an eligible source-scoped baseline. Stops at an unmet human or external prerequisite. --- # Deliver requirement scope end to end @@ -12,17 +12,29 @@ all semantics; this skill owns phase order and continuation. ## Run the loop +For a source-scoped published baseline still in PENDING_VERIFICATION, take the +separate rdd-reverse-engineer-verify → rdd-reverse-engineer-accept path. Its +single reviewed human decision applies verified and delivered proof directly +to DONE. Normal planning, entry, RED/GREEN and completion below apply only after +an explicitly scoped handoff for missing tests or changed behavior. Reopened +requirements remain normal development work. + 1. Reconcile authoritative state, answered gates, evidence validity, and projections. Fix state disagreement before selecting work. -2. Freeze the selected Epic or single-SR scope and find its earliest unmet +2. Freeze the selected scope under `PROCESS.md` and find its earliest unmet prerequisite. Never start from the most convenient phase. 3. If input is not authoritative or is `DERIVED`, apply `rdd-discover` and its confirmation gate. Continue only with confirmed requirements and relations. -4. Apply `rdd-plan`, then `rdd-cold-review`, then `rdd-entry-review`. Repeat from - the earliest stale or failed pass until the exact selected scope is `TODO`. +4. For active work lacking current entry approval, apply `rdd-plan`, then + `rdd-cold-review`, then `rdd-entry-review` until entry is applied to those + items as `TODO`. Resume already-entered work at its current phase; unchanged + DONE dependencies do not repeat entry. Entry approval must cover the whole + selected delivery scope, including the Epic when selected, before step 5. 5. Run the AI TDD inner loop below. Apply `rdd-build` to changed SRs and - `rdd-verify` to human-confirmed as-built URs or SRs. Continue until every - selected requirement satisfies its applicable trace and is `IN_REVIEW`. + `rdd-verify` to entered verification work establishing regression-sensitive + evidence for existing behavior. Continue until every selected requirement + has a current passing trace and is `IN_REVIEW` or already `DONE`. Keep + unchanged DONE members as proof dependencies, without reaccepting them. 6. Apply `rdd-completion-review` to audit, deliver, recheck the delivered revision, reconcile records, run the completion trace gate, and apply the human completion answer. @@ -31,14 +43,14 @@ all semantics; this skill owns phase order and continuation. invalidates. At an exact `OPEN` human gate, present its brief and linked list of relevant -working-set files before asking and wait, following `PROCESS.md` §Gates. If an attributable -answer is already available, apply it and continue. Never infer or supply the -answer. +working-set files before asking and wait, following `PROCESS.md` §Gates. If an +attributable answer is already available, apply it, report, and wait for the +human to resume. Never infer or supply the answer. ## Run the AI TDD inner loop -After entry approval, iterate without human input while the approved fingerprint -remains unchanged: +When the human resumes after applied entry approval, iterate without further +human input while the approved scope remains unchanged: 1. Evaluate every selected UR upper trace and SR lower trace. Establish any required initial RED observations. @@ -47,8 +59,9 @@ remains unchanged: 3. Rerun affected UR scenarios and update their separate upper evidence. 4. Repeat for any failing or stale approved trace. Do not stop after the first GREEN result or completed SR while another selected trace remains unmet. -5. Move eligible requirements to `IN_REVIEW` only after all applicable trace - gates pass. +5. Move eligible active requirements to `IN_REVIEW` only after all applicable + trace gates pass. Previously DONE members retain their state when their + proof is current; invalidated proof returns through `rdd-triage`. If all planned SR lower traces pass while a UR upper trace still fails, diagnose the mismatch. Continue the loop for an implementation defect within approved diff --git a/skills/rdd-deliver/agents/openai.yaml b/skills/rdd-deliver/agents/openai.yaml deleted file mode 100644 index 1355473..0000000 --- a/skills/rdd-deliver/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Deliver" - short_description: "Run requirement delivery through DONE" - default_prompt: "Use $rdd-deliver to take the selected requirement scope through the complete controlled delivery loop." diff --git a/skills/rdd-discover/agents/openai.yaml b/skills/rdd-discover/agents/openai.yaml deleted file mode 100644 index 45a1298..0000000 --- a/skills/rdd-discover/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Discover" - short_description: "Discover and source product intent" - default_prompt: "Use $rdd-discover to source and classify this product intent." diff --git a/skills/rdd-entry-review/SKILL.md b/skills/rdd-entry-review/SKILL.md index 1c32f25..ea2cab2 100644 --- a/skills/rdd-entry-review/SKILL.md +++ b/skills/rdd-entry-review/SKILL.md @@ -35,7 +35,9 @@ packet, cold-review findings, current gate records, and relevant sources. and report an answer that is recorded but not yet applied as exactly that. 6. Move approved named `PROPOSED` or `PENDING_VERIFICATION` requirements and any named proposed epic to `TODO`. Otherwise retain the strongest honest - state and route requested changes. + state and route requested changes. Report any remaining entry approvals + needed for the selected delivery scope; partial approval does not permit + development to start on the approved subset. 7. Report and stop. The entry pass ends with the applied transitions, not with the first build step: the answer was a decision about the gate, not an instruction to build (`PROCESS.md` §Gates). The build begins with a diff --git a/skills/rdd-entry-review/agents/openai.yaml b/skills/rdd-entry-review/agents/openai.yaml deleted file mode 100644 index 5b4296f..0000000 --- a/skills/rdd-entry-review/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Entry Review" - short_description: "Evaluate and apply the entry gate" - default_prompt: "Use $rdd-entry-review to evaluate this scope for implementation entry." diff --git a/skills/rdd-plan/SKILL.md b/skills/rdd-plan/SKILL.md index f6a6071..4b456f9 100644 --- a/skills/rdd-plan/SKILL.md +++ b/skills/rdd-plan/SKILL.md @@ -16,23 +16,20 @@ scope, Item ownership, and Planning and readiness sections of `PROCESS.md`. authoritative. Take the scope from the stored relation graph — declared members, required SRs, gates — never from a keyword search over records. Stop at the confirmation gate for `DERIVED` requirements or candidate-only - links. Then take the constraints from the ledger: search the records for - every verb, symbol, and path the change touches, and for each surface - name the delivered requirement the search returns as its owner — the - record whose acceptance and tests hold the rule the change meets — and - carry that acceptance into the packet as a constraint with its record id. - An owner recalled rather than found is a surprise waiting for the review. - A change that contradicts one is a scope question for step 6 (amend or - supersede the record), never a surprise in review. + links. Search the records for requirements constraining affected behavior + and verify each match against its content and declared relations. Carry + applicable delivered acceptance into the packet. Record surfaces with no + existing owner without inventing one. A change to existing acceptance + is a scope decision for step 6. 2. Choose epic scope or single-SR scope using `PROCESS.md`. Do not invent epic membership or a UR link to make the graph appear complete. 3. Create or update the selected item content: sourced UR outcomes and inline scenarios when user behavior is in scope, and thin testable SRs for system behavior. 4. Perform technical reconnaissance at a named repository revision. Read the - project's generated system documentation for the owning subsystem before - the code and cite it as `DOC:`; where it and the code disagree, the code - at the revision wins and the packet says so. Record the affected surface, + project's available system documentation for context and cite relevant + sources as `DOC:`. Check claims about existing behavior against code; + differences from intended behavior remain findings. Record the affected surface, control/data flow, contracts, reuse targets, dependencies, risks, test infrastructure, failure modes, and unknowns. Inventory the surface by what depends on the invariant the change alters, not by the @@ -46,26 +43,27 @@ scope, Item ownership, and Planning and readiness sections of `PROCESS.md`. after the change and each write shape it admits — a birth, an edit of an open row, an edit of a settled row, a row born before the change — the readers that branch on it, what a crash mid-write leaves, what makes it - stale, and recovery. End every mitigation cell with - `closed` (an acceptance criterion and a RED cover it), `residual` (a named - risk no criterion asserts), or `decided` (a `USER:` line); `backlog` is not - a closing word while a criterion asserts the cell. Audit the packet against - the inventory before handing it over: a cell the packet leaves open is a - finding filed now, not one the reviewer files later. A value the packet + stale, and recovery. Record planned mitigations, their supporting criteria + or decisions, and unresolved risks. Check the inventory for uncovered + acceptance before handing it over. A value the packet states — a limit, a timeout, a constant — is read at the call site that applies it, not at its definition: a defined value may be unused, or one of - several the code selects between. Keep the packet within the bound in - `PROCESS.md`: a single-requirement packet is at most one page. + several the code selects between. Keep the packet focused on facts the + builder and gates need; do not split behavior to meet a document length limit. 5. Enrich every selected SR with its implementation context, explicit change boundary, and lower-RED strategy. Define a separate upper-RED strategy for - every selected UR. A lower-RED strategy names the test file the case - lives in, the behaviour it asserts, and why it fails at the revision — no - command, pattern, or test name: the command is evidence at the RED commit, - where running it is the verification. A migration or a schema change is - production: it lands with the GREEN it serves, never with a RED, and a - case that needs it fails at the revision because it is absent. Every - planned RED case must fail today for the stated reason; a case that would - pass on the current code is not evidence. For a + each selected UR scenario requiring new evidence. Re-validating unchanged, + previously proven behavior needs no new RED. A lower-RED strategy names + the planned test file, the behavior it asserts, and the expected failure. + Every planned RED case for new or changed behavior must fail against the + code at the planning revision for the stated reason; a case that would + already pass cannot serve as RED evidence. Check that reason against the + current code during planning. + Planned commands and test identities are proposals; actual commands and + outcomes become evidence when executed at the RED revision. A migration or + schema change that satisfies the test lands with GREEN. For entered + verification of existing behavior, plan the safe temporary mutation or + equivalent targeted failure described in `rdd-verify`. For a diagnosed, bounded defect the failing test may already exist on a branch as a `RUN:` source — the defect lane in `PROCESS.md` §Entry packet — cite it, and plan the SR's own lower RED to be re-established after entry. @@ -78,15 +76,16 @@ scope, Item ownership, and Planning and readiness sections of `PROCESS.md`. about what changes for the product, the identifier a trailing breadcrumb. Record blockers, conflicts, gaps, and deferrals rather than guessing. 7. Assemble Entry-packet items 1–6 and the product-language brief. Reconcile - planning records — every citation, mechanism, and inventory row the packet - will carry is in it now — then hand off to `rdd-cold-review` for item 7. A - mechanism a review finding later needs is not added here: it is a scope - question routed through step 6, and the packet returns to step 4 for that - mechanism's own reconnaissance. A resolution edit — a sentence, a symbol, - a test name — re-enters step 4 for what it names: read every symbol, path, - or test it names at the revision before the disposition is recorded, and - treat a fix the reviewer proposed as a claim verified the same way as a - carried closure, not as an instruction. + planning records, then hand off to `rdd-cold-review` for item 7. A resolution + edit re-enters step 4 for what it names: reread every symbol, path, and test + it names at the recorded revision before marking the finding `RESOLVED`. + Verify a fix proposed by the reviewer in the same way as a closure carried + from an earlier round. A new mechanism needed to resolve a review finding + is not added during the review cycle: route it as a scope + question through step 6 and plan it as its own change with its own + reconnaissance in step 4. Packet edits may clarify what the change already + contained. Route other changes to approved scope or material decisions + through step 6. ## Report diff --git a/skills/rdd-plan/agents/openai.yaml b/skills/rdd-plan/agents/openai.yaml deleted file mode 100644 index af1fd3c..0000000 --- a/skills/rdd-plan/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Plan" - short_description: "Plan a controlled requirement trace" - default_prompt: "Use $rdd-plan to prepare this requirement for entry review." diff --git a/skills/rdd-reverse-engineer-accept/SKILL.md b/skills/rdd-reverse-engineer-accept/SKILL.md new file mode 100644 index 0000000..afb313e --- /dev/null +++ b/skills/rdd-reverse-engineer-accept/SKILL.md @@ -0,0 +1,98 @@ +--- +name: rdd-reverse-engineer-accept +description: Obtain and apply one human decision for an exact verified and delivered reverse-engineered baseline, or recover its existing gate and receipt. Use with a verification packet or known acceptance gate; preserves compliance approval and normal development gates. +--- + +# Accept verified existing behavior + +## Purpose + +Apply one reviewed human decision from PENDING_VERIFICATION directly to DONE. +This uses the dedicated acceptance operation, not normal development entry or +completion gates. Compliance draft/approved state is unchanged. + +## Inputs and prerequisites + +Read the project `AGENTS.md`, canonical `PROCESS.md` "As-built verification and +acceptance", and the consuming project's sanctioned CLI procedure. In ModernPath, +use the installed `mp-process-cli` skill and `.modernpath/cli-reference.md`. + +For new acceptance, retain the verification packet: typed proof, returned proof +digest, exact pending scope, complete SR lower and independent UR upper proof, +and separate per-repository integration observations. Already DONE required SRs +are proof dependencies, not additional acceptance targets. For recovery, retain +the gate ID, exact opening/application inputs and stable keys, and any actual +human answer/source already provided. Prior permission to reverse-engineer or +implement tooling is not acceptance of the baseline. + +## Resume checks + +When a gate exists or an answer/application may already have succeeded, read its +status before previewing proof, opening a gate or asking the human again. + +| Observed state | Next action | +|---|---| +| No existing gate, current eligible verification packet | Follow the new-acceptance steps below | +| Open gate, current proof | Reuse its stored scope and brief; obtain the answer only if the user has not already given it for this packet | +| Approved answer, current proof, no applied receipt | Apply the retained exact input; do not ask again | +| Rejected answer, no applied receipt | Report rejection and unchanged lifecycle; do not promote | +| Applied receipt | Report the historical decision, receipt and current lifecycle/compliance states. Do not reapply it or send DONE targets through baseline verification. If current required evidence is invalidated, hand that finding to `rdd-triage` | +| Pending targets with changed pins or stale proof, no applied receipt | Retain the old gate's status and return to verification for a fresh packet. Follow the consuming project's documented CLI recovery or replacement procedure before fresh human review; never reuse the old answer for changed proof | +| Status unavailable | Report the read/tooling gap; do not assume no gate exists or invent a new key | + +If the opening response was lost before retaining the gate ID, retry the exact +opening input/key to recover that gate, then follow its returned state. + +For recovery of the same packet, reuse the stored gate and stable retry keys. +After a lost response, retry identical input only if the status read shows that +application still needs recovery. A successor packet needs a new gate and keys +through the documented replacement procedure; changed input under an existing +key conflicts. If a required recovery or replacement operation is unsupported, +report the tooling gap through the sanctioned channel and stop that acceptance +attempt. Do not invent parameters or substitute a generic gate. + +## Steps + +1. **Use the verified packet.** Require complete applicable proof and the exact + pending scope. Use the retained eligibility result when it describes this + packet; the sanctioned opening operation rechecks it. A known gap, changed + pin or unmerged revision returns to `rdd-reverse-engineer-verify`. Do not + recollect unchanged evidence merely to open a decision. +2. **Open and present the decision.** Supply the typed proof, proof digest, + stable opening key and human brief defined in `PROCESS.md`. Show the exact + requirements becoming DONE, evidence identities, coverage limits, risk and + recommendation, with links to relevant packet files. State that compliance + approval is unchanged. Opening a gate is not a human answer. Present the + current decision files before asking. +3. **Record the human answer.** Obtain one explicit attributable accept/reject + decision for that exact packet unless it is already present in the session. + Submit it through the existing reviewed answer mechanism with both gate and + proof fingerprints and the USER source. The sanctioned operation rechecks + proof here. + Rejection ends with a report and grants no promotion. +4. **Apply and report.** Apply an approved answer through the dedicated guarded + operation using the exact proof/gate fingerprints and a stable application + key. It rechecks proof, atomically moves exactly the pending named scope to + DONE, records lifecycle events, closes the applied decision and retains a + receipt. Never use generic author/advance or fabricate RED for this edge. + ModernPath permits an authorized applier other than the answerer; retain both + identities in the receipt. Application cannot change the approved scope. + Read the receipt and lifecycle/compliance states from the successful apply + response. Do not add status/list/preview calls or replay the write merely to + repeat that confirmation. Use a status read when the response is missing, + incomplete or contradictory, or when recovering an interrupted operation. + +## Outputs and handoff + +Report the actual human answer/source, recorded versus applied state, receipt +identity, exact named scope, proof currency and unchanged compliance status. +An answer without an applied receipt is pending application, not DONE. Historical +receipts remain readable after later drift without proving current evidence. +Drift in a receipt's proof pins does not itself change lifecycle state. Route +an established invalidation through `rdd-triage`, retaining the receipt as historical evidence; +normal development resumes according to the item's entry approval and state. + +After applying a human answer, report and wait as required by `PROCESS.md`, +including during the complete loop. Merge, publication and deployment need their +own authority. Missing operations go to the sanctioned tooling-gap channel, +not raw API/store writes. diff --git a/skills/rdd-reverse-engineer-verify/SKILL.md b/skills/rdd-reverse-engineer-verify/SKILL.md new file mode 100644 index 0000000..0e09c55 --- /dev/null +++ b/skills/rdd-reverse-engineer-verify/SKILL.md @@ -0,0 +1,84 @@ +--- +name: rdd-reverse-engineer-verify +description: Verify a published reverse-engineered baseline using existing captured sources, semantic assertions, genuine execution reports and repository integration proof. Use before human acceptance; missing tests or behavior require normal development, and this skill grants no approval. +--- + +# Verify an existing baseline + +## Purpose + +Build an exact eligibility packet for existing behavior. This pass records real +evidence and gaps; it changes no product/test code, requirement lifecycle or +compliance approval and fabricates no RED or PASS. + +## Inputs and prerequisites + +Read the project `AGENTS.md`, canonical `PROCESS.md` "As-built verification and +acceptance", and the consuming project's sanctioned CLI procedure. In ModernPath, +use the installed `mp-process-cli` skill and `.modernpath/cli-reference.md`. + +Start from the publication packet: exact requested UR/SR identities, captured +source/run identities, persisted citations and publication receipts. Acceptance +targets must be PENDING_VERIFICATION with persisted source-scoped baseline provenance. Include +every required confirmed SR of each selected UR; already DONE SRs may remain +proof dependencies without being accepted again. A standalone SR needs no +invented parent or Epic. Individual DERIVED confirmation alone does not confer +eligibility for this path. Entered or defect-reopened work uses normal development. + +## Resume checks + +Read retained source, execution, integration and preview identities before +collecting again. Reuse genuine current evidence for the same captured snapshot; +rerun only what is missing, stale or invalid. Preserve stable evidence keys and +returned report/result IDs and digests. Resolve conflicts before retrying. + +If a gate for this scope exists and its answer/application status is unknown, +hand its ID and retained inputs to `rdd-reverse-engineer-accept` for recovery +before collecting evidence. A known stale, unapplied gate does not repeat that +handoff: continue verification of its pending targets and retain the old gate +status for successor review. An applied receipt is historical evidence; do not +preview DONE targets as pending work. Established evidence invalidation routes +through `rdd-triage`, not back through baseline acceptance. + +## Steps + +1. **Define the denominator.** Read every active criterion for the selected + requirements and required SR dependencies. Evaluate each UR's own upper + scenarios independently. Record omissions explicitly. +2. **Inspect semantic proof.** Resolve captured code/test citations by exact ID, + revision and hash through the supported source reader. Map each criterion to + a meaningful assertion and the production subject it exercises. Bind the + executed name to its registered TestCase or captured citation's `test_case_ref`. + A name, CI badge, self-generated assertion, or unrelated passing test in the + same file is insufficient. Add missing citation identities only through + sanctioned fingerprinted authoring, then refresh the affected packet. +3. **Retain genuine execution.** Run existing tests at the exact captured revision + or inspect a genuine retained current report. Record command, environment, + named outcomes and exact source/test/report identities. CI reports retain + provider, repository, run, job, attempt and tested commit. Record per-clause + results through the evidence store: LOWER for SRs, UPPER for URs. Never reuse + an SR pass as UR proof or label an unexecuted test as passing. +4. **Retain integration proof.** For each repository, use a genuine current + integration observation or the supported collector, which fetches the remote + default branch and checks the tested clean revision and captured snapshot at + its tip. Preserve the returned observation and digest across identical + retries. Passing branch tests alone are insufficient. Delivery here means + observed repository integration, not deployment or live CI monitoring. + Record the observed remote. ModernPath's collector reads the checkout's + `origin`; it does not bind that setting to an independently declared expected + repository. Disclose this limitation in the proof packet. +5. **Preview exact proof.** Submit the typed proof to the sanctioned eligibility + evaluator. Missing, contradictory, stale, revoked or inaccessible evidence stays a gap. Adding + tests or changing behavior requires an explicitly scoped handoff to normal + planning/build/verify; do not repair product/test code in this pass. + +## Outputs and handoff + +Retain the exact proof input and returned digest/eligibility, criterion coverage, +all gaps, source/execution/CI/integration identities, stable retry inputs and +disclosed limits. An eligible packet goes to `rdd-reverse-engineer-accept`; an +incomplete packet names what evidence or development work remains. Preview alone +changes no lifecycle or compliance state. + +If a required operation is missing, file the tooling gap through the sanctioned +channel. Do not call the API or edit the store directly as a workaround. diff --git a/skills/rdd-reverse-engineer/SKILL.md b/skills/rdd-reverse-engineer/SKILL.md index 4e64574..cdb7d1d 100644 --- a/skills/rdd-reverse-engineer/SKILL.md +++ b/skills/rdd-reverse-engineer/SKILL.md @@ -1,248 +1,194 @@ --- name: rdd-reverse-engineer -description: Onboard an existing system from code and documentation. Ask whether to establish a usable as-built baseline or create DERIVED additions for review; inventory declared repositories, derive grounded URs/SRs with citations and relationships, publish through the sanctioned store workflow, and verify read-backs. Use for initial adoption or additional reverse-engineering, not implementation or verification. +description: Derive and publish source-scoped requirements from existing code and documentation, as an authorized baseline or DERIVED proposals. Use for initial adoption or additional reverse-engineering; verification and acceptance belong to their dedicated skills. --- # Reverse-engineer a usable requirement base -Read the project `AGENTS.md` and canonical `PROCESS.md`. This skill applies its -source-scoped baseline and DERIVED rules; it never changes product code or -turns code inspection into passing verification evidence. - -## Connect, inspect, then ask once - -1. Establish the target system and workspace binding through the sanctioned - tool. Synchronize documentation locally. Read the authoritative requirement - corpus and current fingerprint; directories and cached exports are not proof - the system is empty. Do not change a different system's records. -2. Declare every repository with a stable key and local root. The parent may be - non-Git; a Git worktree may have a `.git` file. Inventory tracked/unignored - files or explicitly scoped non-Git files. Include configuration and legacy - templates such as XML, JSP, XSL and XSLT, not just modern source extensions. - Report generated/vendor/secret exclusions and unsupported classes explicitly. -3. Pin repository revision, dirty state, exact paths/sizes/digests and synchronized - document identities/versions/digests. Exclude credentials and private workspace - metadata. Show the source scope and existing corpus counts. -4. Present the source-scoped authorization brief and linked list of relevant - inventory and authorization files before asking which result the user wants, - following `PROCESS.md` §Gates and explaining both consequences: - - **Baseline ready for use** (recommend for an empty corpus): publish grounded - as-built URs/SRs and their graph to Base, visible in Ledger and System → - Requirements as **Baselined — not verified**. The choice authorizes this - source-scoped run, not compliance approval, delivery entry or DONE. - - **DERIVED additions for approval** (recommend when requirements exist): - leave the existing corpus untouched and put proposed requirements/links in - System → Requirements, awaiting exact later approval and absent from Ledger. - This does not require a delivery Epic. -5. Record the explicit attributable mode/source authorization through the - supported operation. Do not silently choose, rebaseline existing rows or claim - the user reviewed not-yet-generated statements. Resume an already authorized - unchanged run without asking again; materially changed sources or corpus - require fresh scope, not an expanded retry. - -In ModernPath workspaces, read `mp-process-cli` for the concrete command sequence -and `.modernpath/cli-reference.md` for flags and payload contracts. Use the -source-scoped onboarding operations, not generic requirement birth with a forced -status. If necessary server/tool support is absent, report that exact gap. -Do not substitute raw API writes or a task-ledger sync. - -## Recover behavior with explicit denominators - -Work a coherent bounded context at a time, repeating these passes: - -| Pass | Inspect | Produce | +## Purpose + +Establish grounded URs/SRs and their source relationships within the agreed +scope. Baseline publication creates PENDING_VERIFICATION requirements in Base; +DERIVED publication creates candidates for later review. Neither creates test +PASS, compliance approval, delivery entry or DONE. Change no product/test code +and execute no untrusted repository code during this pass. + +## Inputs and prerequisites + +Read the project `AGENTS.md` and canonical `PROCESS.md` +(`.modernpath/rdd/PROCESS.md` in a consuming workspace). In ModernPath, read +the installed `mp-process-cli` skill for the onboarding sequence and +`.modernpath/cli-reference.md` for the installed command contracts. + +Establish the target system, requested behavior/context scope, source roots and +whether state is store-backed or file-backed. Prefer fresh synchronized local +documents: check freshness, search/read local files, and refresh only missing or +stale exports. Use live reads for missing material or a current authoritative +answer; the authoritative source wins a disagreement. Always read the authoritative +requirement corpus and fingerprint through the sanctioned tool before authorizing +a run. An empty directory or cache does not prove an empty system. + +## Resume checks + +If a run already exists, read its authorization, captured sources and group +receipts before collecting or publishing again. Reuse unchanged authorization, +keys and prepared inputs; reconcile acknowledged receipts with the unpublished +remainder. Retry identical input only when recovery requires it. A conflict is +not permission to invent a new key or overwrite an existing requirement. + +Resume against the run's captured source identities. Reconcile corpus changes +against its own receipts; external changes or materially changed source scope +require fresh scope authorization. Never replace unavailable historical evidence +with latest code or ask again for an unchanged authorized run. + +## Steps + +### 1. Inventory and authorize the source scope + +Declare each repository with a stable key and local root. Git worktrees and +non-Git roots are valid. Inventory tracked/unignored files or explicitly scoped +non-Git files, including configuration and legacy XML/JSP/XSL/XSLT templates. +Record paths, sizes, digests, revision, dirty state and document identities, +versions and digests. Report generated/vendor/secret exclusions and unsupported +classes; exclude credentials and private workspace metadata. + +Show the existing corpus counts, source scope, authorization brief and relevant +inventory files. Obtain an explicit attributable mode choice unless the session +already contains that exact authorization: + +- **Baseline ready for use:** grounded as-built requirements and confirmed links + enter the authoritative corpus in Base as PENDING_VERIFICATION. + Recommend this for an empty corpus. It authorizes source-scoped publication, + not acceptance of statements that have not yet been generated. +- **DERIVED additions for approval:** distinct proposed requirements and links + await exact later review, separate from the confirmed corpus. Existing + governed content remains unchanged. Recommend this when requirements already exist. + +Record the chosen mode/source authorization through the sanctioned operation. +Do not substitute generic requirement birth with a forced status, raw API writes +or retired task-ledger synchronization. Report missing tooling through the +project's sanctioned channel. Do not change another system's records. + +### 2. Capture sources and recover behavior + +Capture authorized bytes before publishing references. Capture needs neither +provider OAuth nor FileAnalysis and must not replace a connected repository's +latest selection. Keep Git revision separate from dirty snapshot digest. File +citations identify repository, revision, exact path, digest, optional locator +and immutable source ID; document citations identify the authorized revision. + +Work one coherent bounded context at a time, inspecting these perspectives: + +| Perspective | Inspect | Recover | |---|---|---| -| Domain | schemas, migrations, constraints, existing analysis | aggregates, invariants and ownership | -| Surfaces | views, actors, role gates, entry points | user journeys and actor/outcome URs | -| Behavior | implementation paths, normal and refusal cases, tests | independently meaningful SRs, UR scenarios and evidence | -| Recovered design | the complete context map and checked documents | system-level architecture/integration/data-flow notes | - -Enumerate routes/RPCs, jobs/events/webhooks, CLI and agent-tool surfaces, data -models, access controls, client flows, integrations and tests. A genuinely absent -class is stated as inapplicable. Draw contexts by aggregate ownership, not route -layout. Read existing knowledge and human guides as orientation, then confirm -claims against code. Unconfirmed intent and contradictory behavior remain open -questions; a dead path is a finding, not shipped behavior. - -A requirement states behavior a change could breach, not how functions happen -to be arranged. Derive both what an entry point does and what it refuses. Include -the implementation behind entry points. Do not invent intent from a constant or -write one row per function. URs need actor, outcome, inline acceptance scenarios -and sources; SRs need a boundary, behavior, source and meaningful criteria. -Criteria describe expected observations; they do not claim a test ran. - -Join both sides: UR journeys to serving SRs, and SRs to implementing code and -existing test identities. Produce a join report naming views calling nothing -and endpoints no view reaches, alongside missing joins and optional relation rationales. -Do not infer relations merely from prose mentioning an ID. Do not create Epics -as discovery folders. Where the user explicitly wants a real grouping, persist -its intended UR/SR members and verify both membership counts. - -## Capture, publish, read back - -Capture authorized bytes before publishing references. New systems need not -have provider OAuth or FileAnalysis records. A source snapshot is not an AI -analysis request and must not replace a connected repository's latest selection. -Keep Git revision separate from dirty snapshot digest. A file citation names -repository key, revision, relative path, digest, optional locator and immutable -source identity. A document citation names the authorized document revision. -Ambiguous basenames and unresolved evidence are not valid authority. - -Publish each coherent group atomically and read its receipt back: - -- **Baseline:** create new grounded requirements as PENDING_VERIFICATION in Base - with confirmed canonical UR–SR and SR–code/test relationships. Reuse only exact - unchanged existing identities. No row/context approval round follows. -- **DERIVED:** create new distinct candidate IDs, proposed scenarios/criteria, - sources, proposed relations, conflicts, consequences and a confirmation brief. - Comparisons to existing requirements use exact typed identities and show - current versus proposed content. Never overwrite existing approval/content. -- **Exceptions:** insufficient provenance remains explicitly DERIVED; do not - invent edges to meet a count. Report partial baseline output and remainder. - Candidate test stubs and edges remain review-only and cannot count as ordinary - tests, coverage, execution assignments or release snapshot content. - -Keep stable run/group keys and input fingerprints. After interruption, query -receipts before retrying identical input. A conflict requires reconciliation, -not generating a new key to defeat the check. Read captured historical evidence -by identity; do not silently replace an unavailable source with latest code. - -In a store-backed workspace, the store is the sole authority. Do not recreate -retired `tasks/*-REQUIREMENTS.md`, `WORKLIST.md` or mirrored `file-state/` files -to make old synchronization work. In a file-backed workspace, use the canonical -`file-state/` shapes and preserve the same authorization/receipt semantics; -if tooling cannot enforce baseline authority, report the limitation rather than -silently assigning PENDING_VERIFICATION. - -## Exact candidate review - -Prepare the exact typed UR/SR selection and separately named proposed links. -Preview the current content, evidence, comparisons and transitions at one graph -fingerprint. Present the decision brief and linked list of current preview -files before asking for approval, following `PROCESS.md` §Gates. One human action may approve all named requirements and -links; neither an Epic nor an open delivery release is required. Omitted links stay -candidate and may be accepted later without reopening accepted requirements. - -Route explicit decisions only: +| Domain | Schemas, migrations, constraints, analysis | Ownership, aggregates and invariants | +| Surfaces | Actors, views, role gates, entry points | User journeys and actor/outcome URs | +| Behavior | Implementation, refusal paths, tests | SRs, criteria and existing test identities | +| Design | Relevant context map and documents | Source-backed design findings within scope | + +Enumerate applicable routes/RPCs, jobs/events/webhooks, CLI/agent-tool surfaces, +data models, access controls, client flows, integrations and tests. Record absent +classes as inapplicable. Use aggregate ownership to draw contexts. Guides and +analysis orient the work; code establishes implemented behavior. Unconfirmed +intent, contradictory behavior and dead paths remain questions or findings. + +State behavior a change could breach, including refusal cases and implementation +behind entry points. Do not write one requirement per function or invent intent +from a constant. URs need actor, outcome, inline scenarios and sources; SRs need +a boundary, behavior, meaningful criteria and sources. Criteria claim no test ran. +For NFRs, check existing ownership and read complete configuration expressions +and units; bare thresholds without confirmed intent remain questions or DERIVED +exceptions, never invented targets or measurements. + +Join UR journeys to serving SRs and SRs to code/test identities. Report missing +joins, views calling nothing, endpoints no view reaches and justified absent +relations. Do not infer edges from prose mentions or invent parents. Create an +Epic only when the user requested a real grouping, with exact UR/SR memberships. +Verify the persisted member identities and both UR and SR counts against that scope. + +For a full-system adoption or requested design-document output, use +[recovered documents](references/recovered-documents.md). A narrow requirement +run only maintains documents relevant to that scope; it does not require a new +system-wide document set. + +### 3. Prepare the complete batch, then publish + +Prepare the full requested scope locally before the first requirement +publication: URs, SRs, scenarios, criteria, citations and relationships, with +stable run/group keys and input fingerprints. Check duplicates, exact existing +identity reuse, unresolved citations and cross-context joins across the batch. +These reusable inputs are staging artifacts, not another requirement store. + +Publish coherent atomic groups of related requirements. Split only for supported +limits or dependencies, sending referenced parents before dependent groups. +Read and retain each returned group receipt; perform a consolidated record +read-back and audit after the batch. Do not alternate deriving and publishing +one row at a time. +Atomicity is per group; report any unpublished groups explicitly. + +Apply the authorized mode: + +- **Baseline:** new grounded rows become PENDING_VERIFICATION in Base with + confirmed UR–SR and SR–code/test relationships. Reuse only exact unchanged + identities. No row/context approval round follows publication. +- **DERIVED:** publish distinct candidate IDs, proposed criteria/links, sources, + conflicts, consequences and a confirmation brief. Compare exact typed existing + identities and current/proposed content without overwriting approved content. +- **Insufficient provenance:** keep the row explicitly DERIVED with its reason + and candidate packet. Do not invent edges to meet a count. Candidate test stubs + and links count as neither ordinary tests nor execution/release coverage. + +In store-backed workspaces, use typed `parent_external_ids` and code/test +citations; retain returned trace IDs and authority. Never recreate retired +`tasks/*-REQUIREMENTS.md`, `WORKLIST.md` or mirrored file-state ledgers. For an +existing file-backed workspace only, use [file-backed formats](references/file-backed.md). + +### 4. Audit the persisted result + +Use [coverage and citation checks](references/coverage.md) for the distinct +measurements and failure conditions. Citation resolution, extraction coverage, +governed linkage and verified behavior are separate claims. Neither a passing +citation checker nor source-file coverage proves behavioral coverage. + +Read back exact IDs, lifecycle/release, citations, relationship authority, test +artifacts and any requested Epic memberships from the authoritative store. In +a file-backed project, verify the versioned records and their receipt/revision; +in a store-backed project, use the sanctioned read-back operation and projections. +For ModernPath, check Ledger and System → Requirements against the receipts. +For DERIVED, verify candidate records contain the proposals while confirmed +records and governed counts remain unchanged. Report +created, reused, baselined, derived, rejected and unresolved counts separately. + +### 5. Confirm candidates only when requested + +This step applies to DERIVED rows whose exact confirmation is part of the task, +not to ordinary baseline publication. Preview typed UR/SR identities and separately +selected proposed trace IDs at one current graph fingerprint. Present the brief, +current/proposed content, evidence, consequences and relevant preview files. +One human action can decide all named rows and links; no Epic or delivery release +is needed. Omitted links remain candidate and can be decided later. + +Record the explicit attributable decision and idempotent receipt: - accept as-built → Base/PENDING_VERIFICATION; -- accept desired intent → PROPOSED, eligible for normal delivery planning; -- reject → OBSOLETE, no relationship publication; +- accept desired intent → PROPOSED for normal delivery planning; +- reject → OBSOLETE, without publishing relationships; - defer → unchanged DERIVED. -Changed content/relationships invalidate the preview. Refresh it; never retry -an old human decision against new content. Record typed requirement/link -decisions and an idempotent receipt. Approval is additive, not replacement, -compliance approval, behavioral verification, entry approval or DONE. - -## Relation serialization - -Store-backed onboarding uses the sanctioned typed group contract: an SR's -`parent_external_ids` names exact UR parents; typed code/test citations create -the corresponding proposed or baseline source links. The server returns exact -trace IDs and authority. Candidate decisions select those trace IDs separately. -Do not put prose relation clauses into store fields and assume they create edges. - -For an existing **file-backed legacy ledger only**, retain these importer shapes: - -``` -Proposed relations (CANDIDATE): requires SR-KERNEL-030, SR-KERNEL-031. -``` - -``` -Proposed relations (CANDIDATE): serves UR-KERNEL-002. -``` - -``` -- **UR:** UR-KERNEL-002 -``` - -`requires` names rows that take this row as parent; `serves` names its parent. -A dedicated UR field takes precedence over a packet sentence. Mere mentions of -IDs create no relation. An unknown target is a reported defect, not a dropped -edge. An explicit empty typed relation set plus rationale is valid; never invent -a parent to satisfy a count. These legacy forms do not authorize promotion or -recreation of retired store-backed task ledgers. - -## D1. Recovered system-document output contract - -Read maintained `docs/guides/` first as a human lens, not evidence of implemented -behavior. Preserve guide provenance separately from derived findings. Reuse or -extend existing documents before creating a competing account. Produce the -following system-wide set once, with verified code/config citations: - -| Document | Content | -|---|---| -| `docs/03-architecture.md` | Subsystems, interfaces, stores and representative request flow | -| `docs/20-deployment-topology.md` | Runtime locations and boundaries; explicitly fold into architecture for a single stack | -| `docs/21-integrations.md` | Direction, protocol and failure behavior, including unreachable dependencies, for each external system | -| `docs/22-cross-cutting.md` | Auth, tenancy, secrets, observability and resilience enforcement points | -| `docs/23-data-flow.md` | Origins, transformations, destinations and trust boundaries | - -An existing `ARCHITECTURE.md` or `architecture.md` can satisfy the architecture -role; adopt it explicitly and verify the document collector recognizes its path. -Use the sanctioned document publication route and verify its store readback. -These are derived design documents, not a second requirement store. - -## D2. Observed decision records — `docs/adr/NNNN-.md` - -Key by slug and preserve existing ADRs. New recovered decisions carry status -`observed`, never fabricated ratification. A code/config citation establishes -what choice was implemented, not that a human accepted it. - -## D3. NFRs (legacy file-backed path: `tasks/NFR-REQUIREMENTS.md`) - -In a **store-backed** workspace, publish NFRs as ordinary typed requirements -through the authorized run. Never create the path in this heading there. It is -the compatibility contract for workspaces whose authoritative ledger already -uses that file-backed format; canonical file-state workspaces use their selected -`file-state/` serialization instead. - -Use context IDs such as `REQ-NFR-NNN` and the categories performance, scalability, -availability, security, privacy, operability, maintainability and compatibility. -Check existing requirement ownership before deriving another row. A bare timeout, -pool size, retry count or threshold with unconfirmed intent stays a question or -DERIVED exception, not an invented target or measured result. Key repeated -findings by exact source/symbol. For numeric configuration, read the whole expression -and its units before interpreting it; a partial grep hit is not a value. -Before finishing, check the document set, every -integration's failure behavior, observed ADR provenance, NFR questions and actual -publication readbacks. A file existing locally does not prove it reached the UI. - -## Audit and finish - -Invoke `rdd-audit` over exact outputs and declared repositories. Measure both -directions: inventory units without requirements and requirement references -outside inventory. Use the authoritative store projection, not empty retired -ledgers. Distinguish **candidate extraction** from **governed coverage**, and both -from **verified behavior**. Zero recognized citations over nonempty input is a -failed measurement, not 100% coverage. - -Keep re-runnable enumeration/matching scripts and their actual output. Report -N/N by denominator class and repository/context, exclusions and every miss. -The audit script exits non-zero below the floor; retain its verbatim output and -exit code, not just an agent's summary. Run the same measurement before and after; -rank uncovered directories and untraced test files to choose the next scope. -The extraction floor is 90% of each applicable behavior class and 60% of eligible -source files cited or explicitly dispositioned; target complete coverage. -No row budget replaces behavioral granularity. Below the floor is incomplete, -never silently truncated. A requested full sweep continues across remaining -contexts while authority and source scope stay unchanged, with no per-context -baseline reapproval. - -Read back exact UR/SR IDs, lifecycle/release, citations, relationship authority, -test artifacts and optional Epic memberships. For baseline, verify Ledger and -System → Requirements agree with the receipt. For DERIVED, verify candidate -review contains them while governed views/counts remain unchanged. Report -created/reused/baselined/derived/rejected/unresolved counts separately. - -Adopt existing design documents before creating competing ones. Recovered -architecture, deployment, integrations (including failure behavior), cross-cutting -concerns and data flow are system-wide, not per-context duplicates. Observed -ADRs are labelled observed, not ratified. NFRs use the same store and authority -as other requirements; bare thresholds with unknown intent remain questions. - -Onboarding ends with a usable base or a clearly reviewable candidate set and an -honest remainder. Normal `rdd-plan`/entry review and `rdd-verify` own subsequent -verification; reverse-engineering itself changes no implementation, executes no -untrusted code and creates no passing test result or DONE state. +Changed content or relationships require a new preview and reviewed decision. +Confirmation is additive; it is not replacement, compliance approval, test PASS, +delivery entry or DONE. + +## Outputs and handoff + +Retain the authorized scope and source/run identities, prepared batch and group +keys, publication receipts, exact persisted IDs/links, coverage scripts/reports, +and all gaps or unpublished groups. Include design documents only when in scope. +Unresolved in-scope work and unchecked coverage remain incomplete. Continue a requested full +sweep across remaining authorized contexts without per-context reapproval. + +Finish with a usable baseline or a reviewable candidate set and an honest +remainder. Existing-proof verification of published baselines belongs to +`rdd-reverse-engineer-verify`; its eligible packet then goes to +`rdd-reverse-engineer-accept`. Missing tests or changed behavior require an +explicitly scoped normal-development handoff. diff --git a/skills/rdd-reverse-engineer/agents/openai.yaml b/skills/rdd-reverse-engineer/agents/openai.yaml deleted file mode 100644 index 38d5bbf..0000000 --- a/skills/rdd-reverse-engineer/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Reverse-Engineer" - short_description: "Onboard an as-built baseline or DERIVED proposals" - default_prompt: "Use $rdd-reverse-engineer to onboard this system, asking whether to establish a usable baseline or propose DERIVED additions." diff --git a/skills/rdd-reverse-engineer/references/coverage.md b/skills/rdd-reverse-engineer/references/coverage.md new file mode 100644 index 0000000..c714158 --- /dev/null +++ b/skills/rdd-reverse-engineer/references/coverage.md @@ -0,0 +1,50 @@ +# Coverage and citation checks + +Use these checks for the exact authorized repositories and behavior scope. +Retain the frozen inventory and persisted read-back used for each measurement. +A narrow request is measured over that scope; a full sweep must include every +authorized context. Do not shrink a denominator to make a result pass. + +## Citation validity + +Use `rdd-audit` and its supplied `audit-citations.mjs` for citations in recovered +local documents. It checks cited file resolution and a minimum recognized +citation **count** (`--min=N`). It does not enforce percentage coverage. Historical +source availability is checked through the sanctioned immutable source reader; +store citations and links use the store's typed contract, not a retired ledger scan. + +Unresolved or ambiguous citations fail this check. Zero recognized citations over +nonempty expected input is a failed measurement, not 100% coverage. Report a +missing local-document corpus as not applicable when only store records are in +scope; still validate their captured identities and links. + +## Extraction and source coverage + +Define each inventory's unit, scope and enumeration method before counting it. +Use the frozen inventory and authoritative read-back. Retain enumeration and +matching scripts and their actual output when used; these are audit artifacts, +not product tests or another requirement store. + +Record stable unit identities and mappings so the checker can report: + +| Measurement | Denominator | Numerator / required result | +|---|---|---| +| Requirement extraction | Enumerated in-scope items, such as routes or jobs | Account for every item as extracted, already covered, excluded with a reason, or unresolved; cite the supporting records | +| Source disposition, per repository | Eligible inventory files after documented exclusions | Distinct files cited by persisted rows, excluded with a reason, or unresolved | +| Governed and candidate linkage | The same inventory and mappings | Separate counts for confirmed links, candidate links and their overlap; no invented promotion | +| Reverse mapping | Every persisted requirement/source reference in the batch | Resolve inside authorized inventory or to an explicitly authorized existing identity | + +State absent surfaces as inapplicable only after checking; unexplored surfaces +remain unresolved. A file disposition does not establish behavioral coverage, +and candidate links do not establish governed or verified behavior. Counts and +percentages describe the inventory; they do not define a passing gate. + +Missing denominators, unresolved mappings, and inputs that do not match the +authorized inventory/read-back are incomplete measurements. Validate any checker +against known-good and known-bad inputs. Keep its command, output and exit code; +a successful citation audit cannot substitute for checking inventory completeness. + +Report counts with their denominators, exclusions, unresolved references and +uncovered items for each inventory. Unresolved in-scope work remains incomplete. +Preserve meaningful requirement granularity and finish the requested authorized +scope; a row count is not permission to truncate a full sweep. diff --git a/skills/rdd-reverse-engineer/references/file-backed.md b/skills/rdd-reverse-engineer/references/file-backed.md new file mode 100644 index 0000000..0603380 --- /dev/null +++ b/skills/rdd-reverse-engineer/references/file-backed.md @@ -0,0 +1,34 @@ +# File-backed compatibility + +Read this only when the workspace declares file-backed state. Store-backed +workspaces must not recreate retired task ledgers or mirrors of store records. +Canonical file-state workspaces use the selected `file-state/` serialization. +Preserve source-scoped authorization and receipt semantics; if the tooling cannot +enforce baseline authority, report the limitation rather than silently assigning +PENDING_VERIFICATION. + +For an existing legacy file ledger, retain these importer shapes: + +``` +Proposed relations (CANDIDATE): requires SR-KERNEL-030, SR-KERNEL-031. +``` + +``` +Proposed relations (CANDIDATE): serves UR-KERNEL-002. +``` + +``` +- **UR:** UR-KERNEL-002 +``` + +`requires` names rows that take this row as parent; `serves` names its parent. +A dedicated UR field takes precedence over a packet sentence. Mere ID mentions +create no relation. Report unknown targets rather than dropping edges. An +explicit empty relation set with rationale is valid; never invent a parent. +These formats do not authorize promotion. + +Use `tasks/NFR-REQUIREMENTS.md` only where it is already the authoritative legacy +NFR ledger. Canonical file-state workspaces keep NFRs in their selected shapes; +store-backed workspaces publish NFRs as ordinary typed requirements. Preserve +existing identity conventions, such as `REQ-NFR-NNN`, and check ownership before +adding rows. diff --git a/skills/rdd-reverse-engineer/references/recovered-documents.md b/skills/rdd-reverse-engineer/references/recovered-documents.md new file mode 100644 index 0000000..b570e8c --- /dev/null +++ b/skills/rdd-reverse-engineer/references/recovered-documents.md @@ -0,0 +1,48 @@ +# Recovered design documents + +Use this reference for a full-system adoption or when design-document recovery +is included in the requested scope. For a narrow behavior/context request, only +update relevant existing documents and report out-of-scope areas; the full set +below is not an exit requirement for that run. Do not expand source authorization +to complete a template. + +Read maintained project guides, where available, as a human lens and preserve +their provenance separately from code-derived findings. Adopt or extend existing documents before +creating competing accounts. Verify code/config citations and distinguish +implemented behavior from unconfirmed intent. + +## Full-system output roles + +Produce one system-wide account per applicable role, not per-context duplicates. +These paths are defaults; adopt established equivalents explicitly and verify +the sanctioned document collector recognizes them. + +| Default path | Content | +|---|---| +| `docs/03-architecture.md` | Subsystems, interfaces, stores and representative request flow; an existing `ARCHITECTURE.md` or `architecture.md` can satisfy this role | +| `docs/20-deployment-topology.md` | Runtime locations and boundaries; explicitly fold into architecture for a single stack | +| `docs/21-integrations.md` | Direction, protocol and failure behavior for external systems, including unreachable dependencies | +| `docs/22-cross-cutting.md` | Auth, tenancy, secrets, observability and resilience enforcement points | +| `docs/23-data-flow.md` | Origins, transformations, destinations and trust boundaries | + +Use the project's document publication route and verify the published revision +and content. For a file-backed project, read the versioned published documents; +for a store-backed project, use the sanctioned read-back operation. A local +draft does not prove publication. Recovered documents are derived design +sources, not a second requirement store. + +## Observed decisions and NFRs + +Preserve existing ADRs; key recovered records by slug under the established ADR +location, defaulting to `docs/adr/NNNN-.md`. New recovered decisions are +`observed`, never fabricated ratification. A code citation proves an implemented +choice, not human acceptance. + +Derive in-scope NFRs through the same authorized requirement route. Consider +performance, scalability, availability, security, privacy, operability, +maintainability and compatibility without duplicating existing ownership. Bare +configuration values with unknown intent remain questions or DERIVED exceptions. +Check the full expression and units before interpreting a numeric value. + +Before reporting, account for the requested document roles, relevant integration +failure behavior, observed ADR provenance, NFR questions and publication receipts. diff --git a/skills/rdd-start/SKILL.md b/skills/rdd-start/SKILL.md index 1a25edd..06a8f1d 100644 --- a/skills/rdd-start/SKILL.md +++ b/skills/rdd-start/SKILL.md @@ -1,6 +1,6 @@ --- name: rdd-start -description: Enter a delivery session — verify the process-store binding and active release, reconcile answered gates, take or prompt for the work scope, and route to the phase the loop actually needs, holding commit and check discipline for the whole session. Use at the start of any product-work session; when asked to start, continue, or pick up requirement-driven work; and whenever the question is what to work on next, where the loop stands, what is waiting on a decision, or what is blocked. Not a substitute for any phase skill. +description: Enter a delivery session — verify the process-store binding and applicable release, reconcile answered gates, take or prompt for the work scope, and route to the phase the loop needs. Use at the start of product work and when asked to continue, choose work, report pending decisions, or identify blockers. Not a substitute for any phase skill. --- # Start a delivery session @@ -23,15 +23,17 @@ when local documents lack the information or you need an up-to-date answer. confirm it is reachable. In a store-backed repository, confirm the binding identity from the store itself, never from a number quoted in instructions; report binding drift as a defect, not a variance. -2. Confirm the release registry holds exactly one active release with a - `USER:` source. No active release, or more than one, stops selection until - a human answers. +2. For normal delivery selection, confirm exactly one active release with a + `USER:` source. Candidate confirmation and source-scoped baseline work do + not require an active delivery release. Report release problems without + withholding the pending-decision projection from an orientation request. 3. Reconcile answered human gates and apply their consequences, then list the pending human decisions — only `OPEN` human gates with current passing prerequisites. -4. Refresh the session's working-set snapshots and check each file's snapshot - header against the store revision. A stale snapshot is refreshed, never - edited. +4. In a store-backed project, refresh working-set snapshots and check their + headers against the store revision; never edit a stale snapshot. In a + file-backed project, read the authoritative versioned records and regenerate + any derived projections from them. 5. Count the suspended selections. More than one is a preflight fact: report each with its suspended status and reason, and name the mitigation — resume one, release one — before selecting new work. @@ -47,12 +49,15 @@ An unmet preflight fact is the report. Do not select work past it. ## Take the scope -Accept the work scope as the argument: an Epic id, a single SR id, or a raw -request. Without one — including when the request is an orientation question -rather than a scope — answer from the store: read the pending human decisions -and the routed `PROPOSED`/`TODO` queue through the store's own projection -read, present them, and ask the human to choose. Never pick a release -commitment silently. +Accept the work scope as the argument: an Epic id, a single SR id, an exact +UR/SR set for candidate or baseline work, a source inventory for onboarding, +or a raw request. +Without one — including when the request is an orientation question +rather than a scope — answer from the store: read pending human decisions, +current and suspended selections, and routed work across all supported phases. +Include `PENDING_VERIFICATION` baselines awaiting proof or acceptance and +interrupted gate applications needing recovery. Present the projection and +ask the human to choose. Never pick a release commitment silently. Version control, change lists, and the working tree describe the repository, not the loop. They are never the source for what to do next; a session that @@ -66,9 +71,11 @@ awaiting-acceptance bucket dwarfs its ready bucket is a finding about where the loop is stalled — report it as one rather than leaving the reader to count rows. -Freeze the selection per `PROCESS.md` work scope and record it in the -work-selection record. Packet depth is proportional to the frozen scope; no -packet item may be omitted. +For normal delivery, freeze the Epic or single-SR selection in the existing +work-selection record. For candidate and baseline work, retain the exact scope +in the applicable authorization, run and decision records. For normal planning, +entry-packet depth is proportional to the frozen scope; no required item may +be omitted. ## Hold the session discipline @@ -92,8 +99,6 @@ These rules bind every subsequent phase in the session: - timebox the diagnosis of a tooling failure; when the box closes, surface the gap through the project's channel and continue on a read-only path or stop. Never mutate a shared store to test a hypothesis; -- a direction the human has given twice is a decision: record its `USER:` - source and proceed on it rather than re-planning around it; - commit at waypoints — specification, expected RED, GREEN, cleanup, reconciliation — with RED evidence committed before the change that satisfies it, so red-first is auditable in history; @@ -107,7 +112,15 @@ These rules bind every subsequent phase in the session: Select the earliest unmet prerequisite for the frozen scope and hand off to its skill: `rdd-discover`, `rdd-plan`, `rdd-cold-review`, `rdd-entry-review`, `rdd-build`, `rdd-verify`, `rdd-completion-review`, or `rdd-deliver` for the -complete loop. +complete loop. Source-inventory onboarding uses `rdd-reverse-engineer`. + +For genuine source-scoped baseline requirements still in PENDING_VERIFICATION, +route to rdd-reverse-engineer-verify without development entry. When a dedicated +current exact-proof decision names the complete selected scope, route to +rdd-reverse-engineer-accept. Holds, suspension, blockers and DERIVED confirmation +retain precedence. Mixed scopes remain explicit; do not silently change the +selection or apply normal RED requirements to this dedicated path. Provenance +alone never reroutes an entered or defect-reopened item. A pass ends with its report. Enter the next phase only when the human asks for it, or when the request at session entry was the complete loop and the @@ -116,7 +129,7 @@ boundary carried no human answer. ## Report Report the store binding and how it was confirmed, the active release and its -source, pending human decisions, the frozen scope and fingerprint, and the +source when applicable, pending human decisions, the frozen scope and fingerprint, and the phase entered — or the exact preflight fact that stopped the session. Repository and process work that carries no requirement record — tooling, diff --git a/skills/rdd-start/agents/openai.yaml b/skills/rdd-start/agents/openai.yaml deleted file mode 100644 index 58bcbe2..0000000 --- a/skills/rdd-start/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Start" - short_description: "Enter a session: preflight, scope, route" - default_prompt: "Use $rdd-start to begin requirement-driven work on this scope." diff --git a/skills/rdd-triage/SKILL.md b/skills/rdd-triage/SKILL.md index e8b4eb4..c49c0d1 100644 --- a/skills/rdd-triage/SKILL.md +++ b/skills/rdd-triage/SKILL.md @@ -28,11 +28,13 @@ order. 5. For feedback, determine whether one standalone or UR-linked SR can address it without changing user outcome, acceptance, or a cross-cutting decision. Otherwise route it to epic-scoped planning. - A delivered item found defective, or whose decision was reversed, is - routed to an attributable demotion of that item (`PROCESS.md` - §Attributable demotions) — to `IN_PROGRESS` for a defect, to `PROPOSED` - for a reversed decision — with its `USER:` source and the linked defect or - decision, never to a duplicate requirement or a hand-edited status. + Reopen delivered work under the same identity (`PROCESS.md` §Attributable + demotions). Observed evidence invalidation is an automatic transition with + agent/check attribution and factual sources; human-directed demotion uses + a human gate and its `USER:` source. A reversed decision returns work to + `PROPOSED`. A defect or invalidated required evidence returns affected + requirements and Epics to `IN_PROGRESS`. Preserve prior acceptance receipts; + reopening does not waive the entry prerequisites for changing code or tests. 6. Re-evaluate stale gates and evidence, then reconcile authoritative records, release scope, work selection, and derived views. Never promote to `TODO` without the strict entry gate. diff --git a/skills/rdd-triage/agents/openai.yaml b/skills/rdd-triage/agents/openai.yaml deleted file mode 100644 index 975a7a9..0000000 --- a/skills/rdd-triage/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Triage" - short_description: "Route discoveries and user feedback" - default_prompt: "Use $rdd-triage to classify and route these discoveries." diff --git a/skills/rdd-verify/SKILL.md b/skills/rdd-verify/SKILL.md index 5b96891..756e5eb 100644 --- a/skills/rdd-verify/SKILL.md +++ b/skills/rdd-verify/SKILL.md @@ -1,9 +1,9 @@ --- name: rdd-verify -description: Verify human-confirmed PENDING_VERIFICATION URs and SRs against real behavior, add missing tests, and advance only evidence-backed state. Use after an as-built requirement has been confirmed and needs current UR upper or SR lower evidence. Repeat verification inside the AI TDD loop without bypassing approval or delivery. Never use for DERIVED requirements or new behavior; run confirmation or the normal red-first build loop instead. +description: Establish regression-sensitive UR upper or SR lower evidence for existing behavior after normal development entry, adding or strengthening tests as needed. Use for approved TODO or IN_PROGRESS verification work. Eligible source-scoped baselines with existing proof use rdd-reverse-engineer-verify; DERIVED candidates require confirmation and changed behavior uses rdd-build. --- -# Verify confirmed as-built requirements +# Verify entered existing-behavior work Turn behavior described from shipped code into current direct UR upper or SR lower evidence. @@ -15,29 +15,32 @@ completion meanings. ## Keep the transition honest -This skill verifies confirmed as-built behavior. It does not grant human -approval or prove delivery. +This skill verifies existing behavior after normal entry. Eligible source-scoped +baselines with existing proof use `rdd-reverse-engineer-verify` instead. Test +additions or behavior changes on that path require an explicit normal-development +handoff. This skill does not grant human approval or prove delivery. - Never run this skill for a `DERIVED` requirement. `DERIVED` means no human has confirmed that the requirement exists; its proposed links are candidate context and all downstream work is held. Apply its confirmation gate first. -- `PENDING_VERIFICATION` means the requirement and as-built description were - already confirmed, but current direct test evidence is missing. It still - needs human entry approval and must become `TODO` before tests change. +- Before tests change, current applied entry approval must cover the whole + selected delivery scope under `PROCESS.md`, including the Epic when selected. + The requirement being verified must be `TODO` or `IN_PROGRESS`. - For an SR, record `LOWER_VERIFIED` and move it to `IN_REVIEW` only when its lower trace is current. For a UR, record `UPPER_VALIDATED` and move it to `IN_REVIEW` only when its upper trace and required-SR conditions are current. - Never move a requirement to `DONE` from test evidence alone. `DONE` also requires the applicable approval, authoritative-source delivery, and reconciliation conditions. -- If the implementation contradicts the row, record the discovery and route a - separate red-first change. Do not silently change behavior during a - verification pass. +- If the implementation contradicts approved behavior, retain the failing + evidence and hand the same entered SR to `rdd-build`. Route through planning + only when satisfying it requires changed scope or a material decision. Do + not silently change behavior during a verification pass. ## Enter through the same gate as any other change -A `PENDING_VERIFICATION` row is a description someone accepted. It is not an -entry permit, and this skill adds tests — which is implementation. +An authoritative as-built requirement is not itself permission to change tests. +For this normal-development path, apply the entry gate before adding tests. If the row is `DERIVED`, if a requirement it actually depends on is `DERIVED`, or if an applicable relation is candidate-only, stop. Do not inspect tests as @@ -67,13 +70,14 @@ introduces a cross-cutting decision, return it to Epic-scoped planning. In either scope, fulfill the current planning, reconnaissance, cold-review, test-strategy, work-selection, and entry-brief facts. -Then obtain strict human entry approval for every selected requirement and -Epic. An already approved related entity does not return to `TODO` merely -because another requirement starts. Move the selected requirement to `TODO` -before changing a test. If the Entry packet is incomplete or the entry answer -is absent, stop and route the entry first. -Verification outside the authoritative work selection is invisible to planning, -and a test written before the gate cannot be traced to approved intent. +Check the existing entry approval for the exact selected scope. Reuse current +applied approval and preserve `TODO` or `IN_PROGRESS`; resuming verification +does not reopen entry or move work backwards. If entry is missing or stale, +route to planning and entry before changing tests. Missing entry does not +authorize an additional demotion or a hand-edited status. +Verification stays within the authoritative work selection. The diagnosed-defect +exception in `PROCESS.md` permits a failing test before entry; it does not +authorize this verification pass or implementation. ## Establish the evidence bar @@ -121,7 +125,7 @@ assertion remains unverified. leave it at the strongest supported non-final state. 7. Repeat for every approved scenario or clause lacking current evidence. Do not request human input for an evidence failure within the approved - fingerprint. Route changed intent or scope through `rdd-triage`; record an + scope. Route changed intent or scope through `rdd-triage`; record an external impediment as a blocker. 8. Run the project's deterministic process checks. Deliver and reconcile before soliciting completion acceptance; only the subsequent human gate may move a @@ -154,10 +158,12 @@ assertion remains unverified. Do not weaken a test to promote a row. -- If the row is only an inference that no human confirmed as a requirement, - move it to `DERIVED`, record candidate links, and emit its confirmation gate. -- If the implementation cannot satisfy the row, record the contradiction and - route the required new or changed SR through planning. +- If the row lacks authoritative requirement support, stop verification and + route the inconsistent authority through `rdd-triage`. Do not silently rewrite + its lifecycle, approvals, or relationships. +- If the implementation contradicts approved behavior, retain the failing + evidence and hand the same entered SR to `rdd-build`. Route through planning + only when satisfying it requires changed scope or a material decision. - If verification needs unavailable infrastructure, keep the row `PENDING_VERIFICATION` before entry; after entry, use `BLOCKED` and record the suspended `TODO` or `IN_PROGRESS` state. diff --git a/skills/rdd-verify/agents/openai.yaml b/skills/rdd-verify/agents/openai.yaml deleted file mode 100644 index 048dfd8..0000000 --- a/skills/rdd-verify/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "RDD Verify" - short_description: "Verify confirmed as-built requirements clause by clause" - default_prompt: "Use $rdd-verify to turn confirmed PENDING_VERIFICATION requirements into current, direct verification evidence."