doccraft-queue-audit-60a610 — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited doccraft-queue-audit-60a610 (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.
reshuffling priorities and you want a sanity check on {{DOCS_DIR}}/queue.md.
"sanity-check the queue", or similar pick-next / dependency questions.
parallel?") — see Parallel waves below.
doccraft-story.Not for: authoring a new story (use doccraft-story), recording a decision (use doccraft-adr), proposing artifacts from a chat thread (use doccraft-session-wrap), or closing one specific story end-to-end (use doccraft-close — it does the status/backlog/queue/epic transition, then defers to this skill's reconcile invariants).
Read doccraft.yaml at invocation. Every key below has a default in the rest of this body so a missing config file is a soft fallback, not an error.
Relevant keys:
docsDir — root folder for all docs. Default: docs. Stories, queue,and backlog are at {docsDir}/stories/, {docsDir}/queue.md, {docsDir}/backlog.md.
queue.tables.suggestedOrder, queue.tables.platformSpikes — theheading text this skill uses to find the two tables in the queue file. Defaults: Suggested order, Platform spikes. Rename in config if the project uses different headings; the skill matches on heading text, not row position.
story.id.pattern — regex for valid story ids. Used when listingunknown-id errors and when normalising obvious typos.
queueAudit.laneFrom — tag-prefix priority list for the laneheuristic in the parallel-waves pass. Default: [area, slice]. Set to [slice, area] for projects that group work primarily by product surface. May also include epic — when present (and an epics extension defines the epic: story field), the queue groups by epic, which is the primary ordering for milestone/epic projects (ADR 016).
story.status — the project's allowed status values. Whichever of thesemean "no longer active work" are terminal (done always, plus any the project adds: done-no-promote, abandoned, absorbed). Wherever this skill says a story is done / shipped, it means any terminal status — read the vocabulary rather than matching the literal done, or a story closed as absorbed will wrongly look unfinished and never satisfy its dependents.
queueAudit.scale.maxStoryFiles, queueAudit.scale.maxQueueReorderPct— thresholds that trigger stop-and-confirm in Agent mode. Defaults: 5, 50. See Containment below.
<!-- doccraft:packages --> <!-- /doccraft:packages -->
For monorepo projects (a Known package roots block appears above when packages are declared), this skill operates over multiple docs roots. For single-root projects the entire skill operates on the project-root {{DOCS_DIR}}/.
When the project declares packages, the default scope is the active package, determined by (a) an explicit package: arg in the user request; (b) inference from the active file's path under a declared package root; or (c) the project root if neither applies. The skill reads <scope>/{{DOCS_DIR}}/stories/, <scope>/{{DOCS_DIR}}/queue.md, and <scope>/{{DOCS_DIR}}/backlog.md for that scope only.
Cross-scope `depends_on`. Story depends_on entries of the form <slug>/STR-NNNN reference a story in another package. When checking whether a prerequisite is satisfied, resolve the target against the matching package root, read its status, and treat done as satisfied. Cross-scope edges MUST NOT trigger reorders in the other package's queue — flag any that look stale and let the user choose.
Materialised aggregate (monorepo only). Per ADR 016, the root {{DOCS_DIR}}/queue.md in a monorepo is a generated cross-package aggregate, not a hand-maintained file. It composes every package root and the project root into one ordered queue, using queueAudit.laneFrom for the primary grouping (epic first → the milestone/epic roadmap; otherwise area/slice). Each row carries the scope-prefixed id and a resolvable link to the story file (ADR 017).
anywhere", "regenerate the roadmap", reshuffles cross-package priorities, or as the reconcile step of doccraft-close, rebuild this file from the per-scope stories and queues. The file MUST open with a generated-artifact marker (e.g. <!-- generated by doccraft-queue-audit — do not edit by hand; edit per-package queues instead -->) so no one curates it manually. This is the single change ADR 016 makes to ADR 014 §5: the aggregate is generated rather than forbidden.
{{DOCS_DIR}}/queue.md is authored/reconciled normally and is the source of truth; the root aggregate is derived from them and never the place to edit a package's ordering.
queue.md is anormal authored file, and this paragraph does not apply.
Reads:
{{DOCS_DIR}}/stories/*.md — YAML frontmatter (id, status, impact,urgency, depends_on, tags, openspec, roadmap_ref, optional openspec_change).
{{DOCS_DIR}}/queue.md — the Suggested order table, plus Platform spikeswhen parallel waves are in scope.
{{DOCS_DIR}}/backlog.md — the Story files table and the Status column.Writes (Agent mode only, on objective fixes):
{{DOCS_DIR}}/queue.md — reorder rows; drop rows for shipped stories.{{DOCS_DIR}}/backlog.md — update the Status column.{{DOCS_DIR}}/stories/*.md — narrow YAML edits (see Auto-apply rule 4).The user may paste a one- to three-line briefing (what changed, optional scope). If they omit it, infer from the repo: read every file under {{DOCS_DIR}}/stories/ (skip README.md) and {{DOCS_DIR}}/queue.md.
Two behaviours, controlled by the environment — not by user enthusiasm:
read + fix — apply objective mechanical fixes in the same turn, then report what changed. See Auto-apply below.
diff-style proposal plus the same issues list; NEVER suggest commits. The user copies anything they want applied into a follow-up turn.
If the environment is Ask mode, NEVER write files even when the user asks — emit a proposal they can apply themselves.
Apply in the same turn when the fix is objective — a rule-based reconciliation that any auditor would make the same way:
has status: done but still appears in the pick-next table: remove that row and renumber subsequent rows. Optionally backfill a new bottom row from the next obvious pick in the same band (main vs. platform spikes).
roadmap_ref whose story file isstatus: done, if the matching Status cell in {{DOCS_DIR}}/backlog.md still reads planned or equivalent, update it to the project's established "done" phrasing. NEVER mark done in the backlog when the story is still todo or in_progress.
Q in *Suggestedorder, if some prerequisite `d` is not `done` and does not appear above `Q`: reorder rows minimally until the rule holds, or move `Q` below every unfinished `d`. MUST prefer moving blocked work down* over reshuffling the whole table.
with urgency: later sits above a story with urgency: now in the same band and no depends_on justifies the order: update urgency on the lower-urgency story (users tend to understate, not overstate). If the inversion is not flat — if there is any ambiguity — list it under Remaining proposals instead of editing.
files or reorder more than half* the Suggested order* rows, MUST stop and report the full plan first, then wait for user confirmation. Large changes MUST be a human decision.
{{DOCS_DIR}}/queue.md, {{DOCS_DIR}}/backlog.md, or any story file you would touch, MUST report the planned changes first and let the user decide. NEVER overwrite in-progress work.
what changed so they can commit in their preferred grouping. When the user does ask to commit, MUST prefer one commit per file class (queue, backlog, stories) over one mega-commit — easier to review and revert. If the project uses conventional commits, docs(queue): / docs(backlog): / docs(stories): scopes are natural.
NEVER guess through these — list them clearly and let the user decide:
and the dangling id. Fix only obvious typos that restore a known id (e.g. P0-3 → P0.3) and say you did.
A → B → A). NEVER delete edgesto break it — the user MUST choose which edge is wrong.
id. Flag; NEVERrename either.
the constraints. Summarise the options (e.g. "put P0.2 before P0.5 because impact:H, or after because urgency:soon"); NEVER pick.
package: arg and theuser's briefing references stories across multiple package roots. Ask which scope to audit before proceeding.
See doccraft-story for the full frontmatter contract. For the audit, the fields that matter are:
id — node id in the graph; MUST be unique across stories.depends_on — directed edges. Each entry MUST match another story'sid or an explicit backlog row; unknown ids are errors.
status — terminal nodes (any value in story.status that meansclosed: done, and project additions like done-no-promote, absorbed, abandoned) satisfy prerequisites; non-terminal nodes (todo / in_progress) remain scheduling candidates. Match against the configured vocabulary, not the literal string done.
impact / urgency — tie-breakers once dependency constraints aresatisfied.
roadmap_ref — ties the story to its {{DOCS_DIR}}/backlog.md row for thebacklog-drift check.
<!-- doccraft:inject point=queue.artifact-types --> <!-- /doccraft:inject -->
S and each d independs_on, add edge d → S ("d is a prerequisite of S"; complete d before scheduling S).
depends_on references an id with no story and noclear backlog row: list as an error.
d → S graph has a directed cycle, list it.status ≠ done, thesources (no unfinished prerequisites) are natural "start next" candidates.
Precedence: when story urgency and depends_on disagree, unfinished prerequisites win unless the queue row explicitly documents accepted debt in its Notes column.
{{DOCS_DIR}}/queue.md. Story linksand id labels appear in the first column.
Q, every d in depends_on MUSTeither be done or appear above Q (or be explicitly accepted as parallel work — call that out).
done but still listed.MUST use these five sections in this order:
violations that remain after fixes.
numbers / backlog rows / frontmatter fields). If nothing changed, say None.
depends_on edges inferred from story bodies but not in YAML — list here when they are not unambiguous enough for auto-apply.
shipped stories, say so in one line.
**Summary:** Graph clean (6 stories, 4 edges, 0 cycles). Auto-apply ran.
**Issues:** None.
**Changes applied:**
- `docs/queue.md`: removed row 3 (P0.3, status: done); renumbered rows 4–6 → 3–5.
- `docs/queue.md`: moved P2.1 below P1.4 (unfinished prerequisite P1.4).
- `docs/backlog.md`: P0.3 Status → "shipped (v0.4.0)".
**Remaining proposals:**
- P2.5 and P2.6 have equal urgency:soon / impact:M and no dependency edge — consider which to prioritise.
**Exit:** Queue and backlog are now consistent with the dependency graph.When reordering or reviewing an auto-apply, these are the rules this skill enforces:
impact,urgency, depends_on. Read story bodies for chains not yet in YAML and add depends_on when a chain is stable.
urgency and impact move up, but depends_onoverrides: prerequisites MUST be done or appear above this story. If urgency and depends_on disagree, unfinished prerequisites win unless debt is documented.
a story, MUST update the story YAML in the same change — otherwise the table and frontmatter drift apart and the next audit will thrash.
column for that id in {{DOCS_DIR}}/backlog.md. New queued items need a story file and a row in the backlog's Story files table.
planned row in{{DOCS_DIR}}/backlog.md MUST have a matching file under {{DOCS_DIR}}/stories/ and an entry in the Story files table. Reconcile periodically.
Run this only when the user explicitly asks for parallel-ready batches ("what can I run in parallel", "parallel waves", "what's unblocked"). NEVER run as part of every audit — this is a separate pass.
Preconditions. Run the graph / queue checks first and surface any errors before proposing waves. NEVER propose waves on top of a broken graph.
Queue parsing.
id from the link text (e.g. [P4.7]), not thefilename.
priority in the main table.
id appears in the mainSuggested order table.
restricts candidates to that table.
Readiness.
d is satisfied when the story with id: d hasstatus: done. If d does not match any story file, treat as blocked and list under Problems — NEVER assume done.
status is todo or in_progress,every prerequisite is satisfied, and its id is in the active scope.
Batching rules.
may share a depends_on edge (mutual or one-way).
queueAudit.laneFromin priority order: for epic, use the story's epic: field; for area / slice, the first matching tags prefix; else lane: misc. MUST prefer batches where each lane appears at most once — reduces merge conflicts. If that drops too many ready items, note "merge risk: duplicate lane …" and offer a smaller batch or a second wave.
order, then (2) impact H > M > L, then (3) urgency now > soon
later.
ready items unless the user asks for a full scan.
OpenSpec gate. If the project uses OpenSpec, stories carry openspec: not-needed | recommended | required:
required — flag prominently. User MUST complete their OpenSpecpropose flow before heavy implementation. Link openspec_change when set.
recommended — one line: "OpenSpec recommended if scope is fuzzy."not-needed — no mention needed.Proposal output. For each candidate story, emit a compact row:
id, title, status, lane (area/slice), openspecdepends_on with target status{{DOCS_DIR}}/stories/<file>.mdEnd with a short Problems list when any id is missing, cyclic, or blocked.
<!-- doccraft:inject point=queue.instructions --> <!-- /doccraft:inject -->
Before applying any change in Agent mode, MUST complete these checks:
{{DOCS_DIR}}/stories/*.md frontmatter(skip README.md) and build the full dependency graph before making any edit. NEVER apply partial fixes from an incomplete graph.
report. NEVER break cycles by removing edges.
depends_on entry MUST resolve to anexisting story id or backlog row. Fix only obvious typos; flag the rest.
id MUST be unique. If duplicates exist,stop and report. NEVER rename either.
limits (>5 story files or >50% of queue rows), stop and present the full plan. MUST wait for user confirmation before proceeding.
would touch, report the plan and let the user decide. NEVER overwrite.
depends_on edge to break a cycle — NEVER; the user MUSTchoose which edge is wrong.
id to resolve a duplicate — NEVER; flag both andlet the user decide.
done in the backlog when its story file is stilltodo or in_progress — NEVER; backlog status MUST follow the story file, not lead it.
NEVER; list the options and let the user choose.
NEVER; fix or report graph issues first.
The task is complete when:
{{DOCS_DIR}}/stories/ has been read and itsfrontmatter parsed into the dependency graph.
either resolved (auto-apply) or reported (stop and report).
have been run and either resolved or reported.
applied, Remaining proposals, Exit).
the main audit output.
Use when something cannot be auto-fixed (cycles, ambiguous priority) or when the user wants to re-run with narrower scope:
Invoke doccraft-queue-audit.
[Context, e.g. "Break cycle P3.2 ↔ P3.4 by removing depends_on X
from story Y."]
[Optional: "Re-check queue only." | "Parallel waves only."]{{DOCS_DIR}}/queue.md — pick-next tables.{{DOCS_DIR}}/backlog.md — full P-tier tables and Status column.doccraft-story — field contract for story frontmatter.Project-specific vocabulary (tiers, area/slice tags, queue-table headings, scale thresholds) lives in doccraft.yaml — the Configuration section above lists the keys this skill reads. The tables in this body are defaults used when no config is present.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.