doccraft-story-84f900 — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited doccraft-story-84f900 (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
{{DOCS_DIR}}/stories/.openspec on an existing story.{{DOCS_DIR}}/queue.md and the Statuscolumn in {{DOCS_DIR}}/backlog.md. See Workflow reminders for queue-audit invocation rules.
Use valid YAML between --- delimiters at the top of the file. Every field marked yes MUST be present — do not omit any. If the user has not provided enough information to fill a required field, ask — NEVER guess.
| Field | Required | Values / notes | ||
|---|---|---|---|---|
id | yes | Stable, unique id across all stories. P0.3 when aligned to {{DOCS_DIR}}/backlog.md, or a slug like story-2026-001. MUST be unique — verify before writing. | ||
title | yes | Short human-readable title. | ||
status | yes | One of the values in story.status config (default: todo \ | in_progress \ | done). Manual updates only. |
impact | yes | One of the values in story.impact config (default: H \ | M \ | L). If the user does not specify, ask. |
urgency | yes | One of the values in story.urgency config (default: now \ | soon \ | later). If the user does not specify, ask. |
tags | yes | YAML list of prefixed strings (area:, slice:, theme:) from the tag vocabulary below. If nothing fits and the label will recur, extend the vocabulary in doccraft.yaml in the same change. | ||
openspec | yes | MUST be set to one of: not-needed \ | recommended \ | required. See openspec guidance below. |
updated | yes | ISO date YYYY-MM-DD. MUST be set on creation and updated on every meaningful edit. | ||
roadmap_ref | optional | e.g. P1.7 — pointer to the backlog row when applicable. | ||
depends_on | optional | YAML list of story `id` values that MUST be satisfied before this story is picked up (prerequisites). Omit or [] if none. Each entry MUST match another story's id or a backlog id you intentionally treat as external — prefer real story ids so the queue-audit graph stays honest. | ||
adr_refs | optional | List of ADR filenames this story implements or contradicts (e.g. 001-foo.md). | ||
openspec_change | optional | Path or name of the OpenSpec change folder when one exists. |
Do not invent new values forstatus,impact, orurgencywithout first adding them to the matchingstory.*enum indoccraft.json— those are the single source of truth. Foropenspec, update this skill in the same change. One-off nuance belongs in the body, not as a new enum value.
<!-- doccraft:inject point=story.frontmatter.fields --> <!-- /doccraft:inject -->
openspec guidancehigh regression risk; add a sentence in the body: OpenSpec recommended because: …
class of change.
Do not create an openspec/ tree unless the repository has adopted OpenSpec; the field is preparatory.
p{tier}-<topic>.md where tier is p0…p4. The ordinal (e.g. P0.3) lives in YAML id, not in the filename. Examples: p0-payment-retry-flow.md, p2-observability-rollout.md.
opt-2a-workflow-rename.md.tags for grouping.After frontmatter, use these markdown sections in this order:
src/...), related ADRs, PRs.Do not add other top-level sections. Put additional context in Notes.
<!-- doccraft:inject point=story.body.sections --> <!-- /doccraft:inject -->
---
id: P0.3
title: Payment retry flow with idempotency keys
status: todo
impact: H
urgency: now
tags:
- area:api
- area:data
openspec: recommended
updated: 2026-04-18
roadmap_ref: P0.3
depends_on: []
adr_refs:
- 003-payment-gateway-choice.md
---
## Problem / outcome
Failed third-party charges silently drop transactions; add retries with
idempotency so users can reorder without double-billing.
## Acceptance criteria
- [ ] Retries use persisted idempotency keys.
- [ ] Integration tests cover success, transient-failure, and permanent-failure paths.
- [ ] Runbook updated with the new retry behaviour.
## Notes
OpenSpec recommended because: touches schema + payment service + integration tests.Every tag MUST use a prefix so subsystem vs product slice vs cross-cutting theme is unambiguous. Use lowercase after the colon (e.g. area:api).
| Prefix | Meaning | Examples |
|---|---|---|
area: | Subsystem / code area. Align with your project's commit scopes where you already have them. | area:api, area:cli, area:auth, area:data, area:infra, area:schemas |
slice: | Product surface that spans multiple areas. | slice:ui, slice:admin, slice:onboarding |
theme: | Cross-cutting quality or kind of work. | theme:observability, theme:performance, theme:security, theme:docs, theme:testing |
A story may list several tags, e.g. area:api, area:data, theme:performance.
area:, slice:, or theme: value fits, and thelabel will recur, add it to the matching list in doccraft.yaml (keys story.areas / story.slices / story.themes). Commit the config edit together with the first story that uses the new value.
not as a new tag.
Do not edit the tables in this SKILL.md directly — doccraft update regenerates this file and would overwrite the edit. doccraft.yaml is the single source of truth for project-specific vocabulary.
api, ui — always use a prefix so the kind of label isexplicit.
area:ui while slice:ui is theconvention) — prefer slice: for product surfaces.
Before writing or updating a story file, MUST complete these checks:
{{DOCS_DIR}}/stories/*.md frontmatter andconfirm the id value does not already exist. If it does, stop and ask the user for a different id.
depends_on MUST match anexisting story's id value. If a reference is not found, stop and ask the user to clarify.
area:,slice:, theme:). Bare words are NEVER acceptable.
status, impact, urgency, and openspec valuesMUST match the allowed values (from doccraft.yaml or the defaults in the frontmatter table above).
table MUST be present. If the user has not provided enough information to fill impact, urgency, or openspec, ask — do not guess.
The task is complete when:
{{DOCS_DIR}}/stories/<slug>.md).depends_on was added or changed, doccraft-queue-audit has beeninvoked in the same turn.
status: done), {{DOCS_DIR}}/queue.md and{{DOCS_DIR}}/backlog.md have been updated.
Read doccraft.yaml at invocation. The story: section is this skill's customisation surface; override the defaults in the tables above with the values found there. If the file is missing or the story: section is absent, use the defaults as-is.
Relevant keys:
docsDir — root folder for all docs, relative to project root. Default:docs. Stories live at {docsDir}/stories/.
story.areas, story.slices, story.themes — tag vocabulary lists(replace the default area: / slice: / theme: values).
story.status — allowed values for the status: field. Default:[todo, in_progress, done]. Extend if your project uses additional states (e.g. blocked, abandoned).
story.urgency — allowed values for the urgency: field. Default:[now, soon, later]. Some projects use tier names (p0..p4) directly here, or mix both.
story.impact — allowed values for the impact: field. Default:[H, M, L]. Override for projects that prefer [high, medium, low] or another taxonomy.
story.id.tiers — filename tier prefixes like p0…p4. Empty list[] means the project does not use tier prefixes.
story.id.pattern — regex accepting valid story id: values infrontmatter. Use this to validate new stories and to normalise depends_on typos. Default: ^(P\d+(\.\d+)?|[a-z][a-z0-9-]+)$.
Adding to a list in doccraft.yaml teaches the skill a new valid value without touching this file (which doccraft update regenerates). That is the intended way to extend vocabulary for a project.
<!-- doccraft:packages --> <!-- /doccraft:packages -->
For monorepo projects, stories may live at the project root or under a declared package's {{DOCS_DIR}}/stories/ tree (a Known package roots block appears above when packages are declared). For single-root projects no block appears, every story lives at the project-root {{DOCS_DIR}}/stories/, and the namespace rules below do not apply.
When the project declares packages, decide which scope to write to:
a story for audio-engine"), write to that package's {{DOCS_DIR}}/stories/ and use the namespaced id form <slug>/STR-NNNN.
declared package path, default to that package's docs root.
{{DOCS_DIR}}/stories/ with an unprefixed id.
In depends_on, the form <slug>/STR-NNNN references a story under that package's {{DOCS_DIR}}/stories/; unprefixed ids always refer to the project-root scope. The same namespace rule applies to adr_refs (unprefixed = root, <slug>/NNN-slug.md = package-scoped).
Per ADR 017, a cross-reference should resolve in one hop — opening the target should never require globbing a directory to find the file. The namespaced id stays the canonical, rename-stable handle; pair it with a path so neither readers nor agents pay a search tax:
depends_on, adr_refs), keep the id form —link syntax in a YAML list is awkward, and the audit resolves these against the Known package roots anyway. Ids remain canonical here.
or agent will follow (a related-story line, a queue row, an epic table), render it as a markdown link whose text is the id and whose target is the resolvable file path: [pipeline/P1.30](../services/pipeline/{{DOCS_DIR}}/stories/p1-...md).
(doccraft-queue-audit) re-derives from the id and repairs when a file moves — so a stale path is a mechanical fix, not a dead link.
status to in_progress when you start implementation; done whenshipped or explicitly abandoned (note why in body if abandoned).
depends_on, invokedoccraft-queue-audit in the same turn so the working queue stays consistent with the dependency graph.
status: done), update {{DOCS_DIR}}/queue.mdand the Status column in {{DOCS_DIR}}/backlog.md in the same commit.
<!-- doccraft:inject point=story.instructions --> <!-- /doccraft:inject -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.