You are performing a fast, focused drift check on a specific target. This skill detects whether code aligns with its governing ADRs and specs.
3a. Tier 3 staleness check (v5.0.0+):
On entry, check the qmd index's last-modified timestamp for this repo's collections (use the exact-prefix match algorithm from references/qmd-helpers.md § "This-Repo Collection Identification" to identify them, then take the maximum lastUpdated across them). If that timestamp is older than the configured staleness threshold, run a silent qmd update first.
-
Determine relevant artifacts:
Use qmd hybrid retrieval to identify the top-K candidate ADRs and specs governing the target before reading any artifact in full. The pre-v5 "read all ADRs and specs to find which ones govern the target" path is removed in v5.0.0 — qmd retrieval is the canonical mechanism.
-
If the target is a file or directory: construct a hybrid query per references/qmd-helpers.md § "Hybrid Retrieval" derived from the target's content. The query SHOULD include:
lex: the file path basename, exported symbol names from a quick scan, and any Governing: comment block content (if present)
vec: a one-sentence summary of what the target file/dir does (e.g., for src/auth/login.go → "user authentication via JWT-based session login flow")
intent: "/sdd:check {target} — find ADRs and specs governing this code"
Filter to collections: ["{repo}-adrs", "{repo}-specs"] (or per-module variants in workspace mode). Set limit: 8 and minScore: 0.3. Read the top-K candidates in full before evaluating drift.
-
If the target is an ADR (ADR-XXXX): read the ADR directly. Then qmd-search {repo}-specs for related specs (those that implement or reference the ADR) and {repo}-code for code that should implement the decision. Same query structure as the file/dir case, with the ADR's title and decision as the vec query.
-
If the target is a SPEC (SPEC-XXXX): read the spec directly. Then qmd-search {repo}-adrs for governing ADRs and {repo}-code for implementing files. Same pattern.
On qmd unreachable / timeout per qmd-helpers.md § "Error Handling", surface the error and stop. Per ADR-0024 and SPEC-0019 REQ "qmd Assumption in Consumer Skills", fallback paths were eliminated in v5; the failure mode is "fix qmd, retry" not "scan the entire corpus."
-
Validate spec artifact pairing: For each spec directory found under {spec-dir}, check that both spec.md and design.md exist. If a spec.md exists without a corresponding design.md (or vice versa), report as [WARNING] under "Code vs. Spec" with finding: "Unpaired spec artifact: {path} exists but {missing-file} is missing. Per ADR-0003, spec.md and design.md are a paired unit." (Governing: ADR-0003, SPEC-0003)
-
Security lint scan: Scan source code files in the target for dangerous patterns that indicate security risks. Use text-based pattern matching (Grep tool with regex), NOT AST analysis. False positives are acceptable — flag patterns for human review.
For each pattern below, search applicable source files and report any matches as findings in the output table. All security lint findings use category Security Lint and severity [WARNING].
Pattern 1 — Unbounded body read: Reading an HTTP request body without enforcing a size limit allows a single request to allocate arbitrary memory.
- Go:
io.ReadAll(r.Body) or ioutil.ReadAll(r.Body) without http.MaxBytesReader wrapping the body in the same function or file.
- JS/Node:
req.on('data' accumulating chunks without a size check, or body-parser / express.json without a limit option.
- Python: Reading
request.body or request.data without DATA_UPLOAD_MAX_MEMORY_SIZE or equivalent framework-level limit.
- Remediation: "Wrap the body with a size-limiting reader (e.g.,
http.MaxBytesReader in Go, { limit: '1mb' } in Express, DATA_UPLOAD_MAX_MEMORY_SIZE in Django) before reading."
Pattern 2 — Template safety bypass: Disabling template auto-escaping injects raw HTML into rendered output, enabling XSS.
- Go:
template.HTML( casting user-supplied or unsanitized content.
- JS/React:
dangerouslySetInnerHTML usage.
- Python/Jinja:
|safe filter or {% autoescape false %} in Jinja/Django templates.
- Remediation: "Avoid bypassing template auto-escaping. If raw HTML is required, sanitize the content with a trusted library before marking it safe."
Pattern 3 — User-controlled redirect: HTTP redirects where the target URL comes from request parameters allow open redirect attacks.
- Go:
http.Redirect( where the URL argument references r.URL.Query(), r.FormValue, or r.PostFormValue.
- JS/Express:
res.redirect(req.query or res.redirect(req.body or res.redirect(req.params.
- Python/Django:
redirect(request.GET[ or redirect(request.POST[ or HttpResponseRedirect(request.GET[.
- Remediation: "Validate redirect targets against an allowlist of trusted URLs or paths. Never redirect to a raw user-supplied URL."
Pattern 4 — Missing auth middleware: Route or endpoint registration without authentication middleware in the handler chain leaves the endpoint publicly accessible.
- Go:
http.HandleFunc( or router.GET( / router.POST( / mux.Handle( where the handler chain does not reference an auth middleware function in the same registration block.
- JS/Express:
app.get( / app.post( / router.get( / router.post( without an auth or authenticate or requireAuth middleware in the argument list.
- Python/Django: View functions or class-based views without
@login_required, @permission_required, or equivalent auth decorator.
- Remediation: "Add authentication middleware to the handler chain. If this endpoint is intentionally public, add a comment:
// Public: [justification]."
Pattern 5 — DOM injection: Assigning to innerHTML bypasses DOM sanitization and is a common XSS vector.
- JS/HTML:
.innerHTML = or .innerHTML += assignments in JavaScript files or inline <script> blocks.
- Remediation: "Prefer
textContent for text content or use a DOM sanitization library (e.g., DOMPurify) before assigning to innerHTML."
Pattern 6 — CDN without SRI: Loading external scripts or stylesheets without Subresource Integrity attributes allows compromised CDNs to inject malicious code.
- HTML:
<script src="https:// or <script src="http:// without an integrity attribute on the same tag. Also <link href="https:// or <link href="http:// with rel="stylesheet" without an integrity attribute.
- Remediation: "Add
integrity and crossorigin attributes to all CDN-loaded <script> and <link> tags. Generate SRI hashes with shasum or an online SRI hash generator."
Each finding MUST include: the file path with line number in the Location column, the matched pattern in the Finding column, and the remediation suggestion. Report findings even if they may be false positives — the goal is to flag patterns for human review.
-
Template quality scan: Scan HTML templates, JavaScript files, and frontend assets in the target for template quality patterns. Use text-based pattern matching (Grep tool) to detect the following 5 patterns. All template quality findings use category Template Quality.
Pattern 1 — Duplicate inline <script> blocks (Severity: [WARNING]): Identical or near-identical <script> blocks appearing in the same file or across multiple template files indicate code duplication.
- Detection: Search for inline
<script> blocks (not <script src=). Compare content of inline script blocks within the same file and across template files. Flag when the same block (or substantially similar content) appears more than once.
- Remediation: "Duplicate inline script detected in [files]. Extract to a shared JavaScript file or template partial."
Pattern 2 — Duplicate form structure (Severity: [INFO]): The same form structure (same action, same field names) appearing in multiple template files signals a refactoring opportunity.
- Detection: Search for
<form tags across template files. Compare form action attributes and field name attributes. Flag when two or more templates contain forms with the same structure.
- Remediation: "Similar form structure found in [files]. Consider extracting to a shared form partial or component."
Pattern 3 — Duplicate navigation/sidebar (Severity: [WARNING]): Navigation or sidebar markup rendered in multiple templates without using a shared partial creates layout inconsistency risk.
- Detection: Search for
<nav elements or elements with role="navigation" across template files. Flag when navigation markup appears in more than one template file without evidence of a shared partial/include (e.g., Go {{ template "nav" }}, Jinja {% include "nav.html" %}, EJS <%- include('nav') %>).
- Remediation: "Navigation markup appears in multiple templates: [files]. Extract to a shared partial/include to prevent layout drift."
Pattern 4 — Dev-only CDN URLs (Severity: [WARNING]): CDN URLs intended only for development (such as cdn.tailwindcss.com) should not appear in production templates.
- Detection: Search for
<script or <link tags referencing known dev-only CDN URLs: cdn.tailwindcss.com, unpkg.com (when used for production), or any CDN URL containing /dev/ or /debug/ in the path.
- Remediation: "Dev-only CDN detected:
[url]. Replace with a production build (bundler, CLI tool, or self-hosted asset)."
Pattern 5 — Multiple JS interaction frameworks (Severity: [INFO]): Loading more than one JS interaction framework (e.g., HTMX + Alpine.js + Hyperscript, or React + jQuery) signals framework sprawl and a missing architectural decision.
- Detection: Search across all project files for references to JS interaction frameworks: HTMX (
htmx.org, hx-get, hx-post, hx-swap), Alpine.js (alpinejs, x-data, x-bind), Hyperscript (hyperscript.org, _="on), React (react., ReactDOM, jsx), jQuery (jquery, $(document), $(function), Vue (vue.js, v-bind, v-model), Stimulus (stimulus, data-controller). Flag when more than one distinct framework is detected.
- Remediation: "Multiple JS interaction frameworks detected: [list]. Consider an ADR to document the rationale for each framework or consolidate to one."
Each finding MUST include the affected file paths in the Location column and the remediation suggestion.
-
Analyze for drift across three categories:
Code vs. Spec: Does the implementation match the spec's requirements and scenarios?
- Check MUST/SHALL requirements -- violations are
[CRITICAL]
- Check SHOULD/RECOMMENDED requirements -- violations are
[WARNING]
- Check scenario coverage -- missing scenarios are
[WARNING]
Code vs. ADR: Does the implementation follow the accepted ADR decisions?
- Check that the chosen option/approach is implemented, not a rejected alternative -- violations are
[CRITICAL]
- Check that architectural constraints from the decision are followed -- violations are
[WARNING]
ADR vs. Spec: Are the ADR decisions consistent with spec requirements?
- Check for contradictions between ADR decisions and spec requirements -- contradictions are
[CRITICAL]
- Check for terminology or approach mismatches -- mismatches are
[WARNING]
-
Produce the findings table using the standard format:
## Drift Check: {target}
Checked {N} ADRs and {M} specs against {target}. Found {X} findings.
### Findings
| Severity | Category | Finding | Source | Location |
|----------|----------|---------|--------|----------|
| [CRITICAL] | Code vs. Spec | {one-sentence description} | SPEC-XXXX | src/path/file.ts:NN |
| [WARNING] | Code vs. ADR | {one-sentence description} | ADR-XXXX | src/path/file.ts:NN |
| [WARNING] | Security Lint | {pattern name}: {matched code}. {remediation} | ADR-0018 | src/path/file.go:NN |
| [WARNING] | Template Quality | {pattern name}: {description}. {remediation} | ADR-0019 | templates/page.html:NN |
### Summary
- Critical: {N}
- Warning: {N}
- Info: {N}
-
Add suggested actions at the end based on findings:
If a module has no findings, omit its section and show "No drift detected" in the summary row.