specgate/docs v0.20.0

Your team's first pull request with Specgate#

For the people who write the pull request and for the people who review it. It assumes the repository has already run specgate init; if it has not, the Quickstart gets it there in ten minutes.


Once per repository#

bash
specgate init        # adopts the existing code; writes spec.md and the matrix
specgate ci init     # the gate as a CI job — the provider is detected from
                     # .github/, .gitlab-ci.yml, … or the origin remote;
                     # with neither yet, add --provider github|gitlab|azure|jenkins
git add -A && git commit -m "chore: adopt Specgate"

The CI job runs specgate check on every pull request — the specification, then your tests — after setting up what the project needs: a JDK for a pom.xml or build.gradle, npm ci for a lockfile. It is the check you run on your machine, so a green there is a green in CI. It runs the test_cmd you configured (specgate config set test_cmd …), or the one it detects; with neither, it runs validate . --strict alone and ci init says so.


The author: one requirement, one pull request#

bash
specgate status                                   # what is open, and the next command
specgate new "Customers download invoices as PDF" # spec section + scenario + row

new writes three things. Edit two of them:

  1. spec.md, the ## REQ-NNN section — replace the generated sentence with the obligation: what must hold, when, and how someone would observe it. One requirement, one obligation. done refuses the requirement while the generated sentence is still there (requirement_template_obligation).
  2. features/<name>.feature — replace the three <placeholders> with a concrete Given / When / Then. Real values, not "valid data".
  3. docs/specs/traceability.md — do not touch it. It is generated.

Then write the test, and mention the requirement in it. The mention is the link; there is nothing else to declare:

js
// REQ-007 SCN-007 — customers download invoices as PDF
test("a paid invoice downloads as a PDF", () => { /* … */ });

Write the code, then close the requirement:

bash
specgate done REQ-007     # runs the gate for it first; writes nothing if it fails
specgate check            # the whole gate, the one CI runs

Commit everything check touched — spec.md, the feature file, the tests, the code and docs/specs/traceability.md. A matrix left behind is the most common red build on a first PR (see matrix_stale below).

Fixes and refactors#

A bugfix or a refactor that does not change contracted behaviour needs no new requirement. The gate runs on every pull request, but it only asks for what a delivered requirement owes; a PR that adds none owes nothing new.

If the fix changes what a delivered requirement promises, change its spec.md section and scenario in the same PR. For a larger change to behaviour that already shipped, use a change.


The reviewer: what to read, what to skip#

The gate already proved the mechanical part: every delivered requirement has a scenario, the scenario has real steps, a test names it, and the files the matrix points at exist. Do not re-check that by hand. Spend the review on what no tool can judge:

ReadAsk
The ## REQ-NNN section in spec.mdIs it one obligation? Could two people test it and agree? Is it what the ticket asked for?
The scenarioDo Given / When / Then describe this behaviour with real values, or a generic happy path? Is the interesting edge case missing?
The test that mentions REQ-NNNDoes it assert what the scenario's Then says — or only that nothing throws? A test that mentions the ID and checks nothing passes the gate.
The status changespecgate:trace … status=Implemented in spec.md. Only on a requirement whose code is in this PR.

Skip docs/specs/traceability.md. It is generated from the files above, and CI fails when it is out of date, so a diff there is a consequence, not a decision.

The one thing the gate cannot catch is a test that names a requirement and does not test it. That is the reviewer's job, and it is the most valuable five minutes of the review.


When check fails#

Every failure says what is wrong and how to fix it, and most carry a code in brackets you can search for. The ones a first PR meets:

scenario_placeholder_step#

text
✖  features/invoices.feature:4 unfilled placeholder in "given <the state before the action>" … [scenario_placeholder_step]

The scenario still has the <placeholders> new wrote. A Draft requirement may keep them; one being delivered may not, because Cucumber reports a scenario of placeholders as 0 steps · exit 0. Write the real steps.

matrix_stale#

text
  ✖  docs/specs/traceability.md no longer matches spec.md, the feature tags and the tests.
     Run `specgate matrix` and commit the result — `specgate check` does it for you.

Only in CI: a test or a tag changed and the regenerated matrix was not committed. Run specgate check locally and commit traceability.md.

[TDD-1] — delivered without a test#

text
[TDD-1] Test artifact is TBD but status is 'Implemented' (scenario: SCN-007)

The requirement is past Draft and no test mentions it — usually the test was renamed or deleted. Mention REQ-007 in the test that covers it, or move the status back to Draft in spec.md.

declared_artifact_missing#

text
✖  docs/specs/traceability.md REQ-007's test artifact `test/invoice.test.js` does not exist. [declared_artifact_missing]

A file the requirement points at explicitly is gone — a path written in its specgate:trace comment (test='…', artifact='…'), or in a hand-kept matrix. Restore it, or fix the path. A test linked only by mentioning the requirement does not produce this: delete that test and you get [TDD-1] instead.

requirement_template_obligation#

The requirement claims delivery while its ## REQ-NNN section still says "The system MUST satisfy: ." with the note <code>new</code> left below it. Write the real obligation and delete the note. A Draft owes nothing yet.</p> <h3 id="check-tests-failed-done-tests-failed"><code>check_tests_failed</code> / <code>done_tests_failed</code><a class="anchor" href="#check-tests-failed-done-tests-failed" aria-label="Link to this section">#</a></h3> <p>The project's tests failed. These run only when a test command is configured (<code>--test-cmd "npm test"</code>, or <code>specgate config set test_cmd "npm test"</code> once). Without one, <code>check</code> and <code>done</code> say they checked the specification and not the code — read that warning as "nothing ran", not as a pass.</p> <h3 id="done-validate-failed"><code>done_validate_failed</code><a class="anchor" href="#done-validate-failed" aria-label="Link to this section">#</a></h3> <p><code>done</code> ran the gate and it failed; the output above it says why. Nothing was written. Fix it and run <code>done</code> again. <code>done --no-check</code> writes the status anyway — keep it for the rare case you know the gate is wrong, and say so in the PR.</p> <hr> <h2 id="the-agreement-to-make-as-a-team">The agreement to make as a team<a class="anchor" href="#the-agreement-to-make-as-a-team" aria-label="Link to this section">#</a></h2> <p>Three sentences are enough. Put them in the repository's contributing guide:</p> <ol> <li>A pull request that delivers behaviour carries its requirement, its scenario and a test that mentions it.</li> <li><code>specgate check</code> is green before review is requested.</li> <li>The reviewer reads the requirement, the scenario and the test — not the matrix.</li> </ol> <hr> <h2 id="next">Next<a class="anchor" href="#next" aria-label="Link to this section">#</a></h2> <ul> <li><a href="commands.html">The five commands, and the rest</a></li> <li><a href="writing-specs.html">Write a scenario that is worth testing</a></li> <li><a href="reviewing-changes.html">Change a requirement that already shipped</a></li> <li><a href="validating.html">What the gate checks, flag by flag</a></li> </ul> </article> <nav class="pager" aria-label="Neighbouring pages"><a class="pager__prev" href="forja/contributing.html"><span>Previous</span>Contributing to forja</a><a class="pager__next" href="writing-specs.html"><span>Next</span>Writing specs</a></nav> <footer class="page-foot"> <p class="page-foot__ask">Was this page useful?</p> <a href="https://github.com/rsaglobaltech/specgate/edit/main/docs/first-pr.md" target="_blank" rel="noreferrer">Edit this page</a> <span aria-hidden="true">·</span> <a href="https://github.com/rsaglobaltech/specgate/issues/new" target="_blank" rel="noreferrer">Something wrong? Open an issue</a> </footer> </main> <div class="rail"><nav class="toc" aria-label="On this page"><h2>On this page</h2><ul><li class="toc__l2"><a href="#once-per-repository">Once per repository</a></li><li class="toc__l2"><a href="#the-author-one-requirement-one-pull-request">The author: one requirement, one pull request</a></li><li class="toc__l3"><a href="#fixes-and-refactors">Fixes and refactors</a></li><li class="toc__l2"><a href="#the-reviewer-what-to-read-what-to-skip">The reviewer: what to read, what to skip</a></li><li class="toc__l2"><a href="#when-check-fails">When check fails</a></li><li class="toc__l3"><a href="#scenario-placeholder-step">scenario_placeholder_step</a></li><li class="toc__l3"><a href="#matrix-stale">matrix_stale</a></li><li class="toc__l3"><a href="#tdd-1-delivered-without-a-test">[TDD-1] — delivered without a test</a></li><li class="toc__l3"><a href="#declared-artifact-missing">declared_artifact_missing</a></li><li class="toc__l3"><a href="#requirement-template-obligation">requirement_template_obligation</a></li><li class="toc__l3"><a href="#check-tests-failed-done-tests-failed">check_tests_failed / done_tests_failed</a></li><li class="toc__l3"><a href="#done-validate-failed">done_validate_failed</a></li><li class="toc__l2"><a href="#the-agreement-to-make-as-a-team">The agreement to make as a team</a></li><li class="toc__l2"><a href="#next">Next</a></li></ul></nav></div> </div> <div class="palette" id="palette" hidden> <div class="palette__scrim" data-close="1"></div> <div class="palette__box" role="dialog" aria-modal="true" aria-label="Search documentation"> <div class="palette__field"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg> <input type="search" id="palette-input" placeholder="Search the documentation…" autocomplete="off" spellcheck="false" aria-label="Search documentation" aria-controls="results" aria-expanded="true"> <kbd class="palette__esc">Esc</kbd> </div> <div class="palette__results" id="results" role="listbox" aria-label="Results"></div> <p class="palette__hint"> <kbd>↑</kbd><kbd>↓</kbd> to navigate · <kbd>↵</kbd> to open · <kbd>Esc</kbd> to close </p> </div> </div> <script src="assets/docs.js" defer></script> </body> </html>