# Dogfooding specdx on this site

This site consumes specdx as a real project, under a written contract: friction becomes a GitHub issue, never a workaround. In four days that contract produced ten issues — a schema bug, vacuous green verdicts, silent context truncation — every one closed the day it was filed. This log walks the whole loop, including the two bugs that verifying the fixes surfaced and the tenth fix that arrived better than the one I asked for.

Published: 2026-08-03
Canonical: https://umar.codes/dogfooding-specdx

## Revisions

- 2026-07-28 — Created.
- 2026-07-29 — Wrote the full body; the dogfooding arc converged with specdx 0.4.0-alpha.7.
- 2026-08-02 — Pre-publish: corrected the issue count from eight to nine against the GitHub record, and added the tenth issue — framework-agnostic declared artifacts in 0.4.0-alpha.8, now running in this site's gate.
- 2026-08-03 — Published.

---

Dogfooding only works if friction leaves a trace. This site runs on a written
contract with [specdx](/sdx): when the tool breaks a workflow here, I file the
issue instead of routing around it. Over four days in July that contract
produced ten issues, ten fixes, and a sharper tool — this log is the full
loop.

## The contract: friction is a bug report

This repo's CLAUDE.md contains one sentence that does most of the work:
"friction is a bug to report, not a reason to route around the tool." Solo
dogfooding fails by default without it. When you own both the project and the
tool, the cheapest move is always a local workaround — and every workaround
destroys the evidence that the bug existed. Writing the contract down, where
the agent working on the site also reads it, makes the expensive move the
default one.

## One schema bug, end to end

The first loop was textbook. This site's `spec.config.yaml` declared a spec of
type `project-context` — a documented type — and `specdx validate` rejected it,
along with `quick-spec` and `epic`: the config schema accepted only six of the
nine types the sections schema defined. The workaround (declare it as
`technical-design`, with a comment) went in labelled as debt in DECISIONS.md,
and the issue went upstream the same evening with the exact error output. The
fix shipped in 0.4.0-alpha.3, the workaround came out the next day, and the
gate ran clean. Elapsed time from friction to retired workaround: about 24
hours.

## Six issues in one afternoon

Two days later I went looking instead of waiting. This site runs
[spec-first](/spec-driven-development) on non-trivial work, so there were real
specs to point the tool at: two new ones joined the suite — a technical design
for a crawler-logging experiment, and the content calendar as an `epic`, the
very type the first issue had un-broken — and then every CLI command ran
against them. Six issues came out of one afternoon:
`--version` reporting 0.0.0; the dependency graph ignoring the schema's own
`references` frontmatter; `check` crashing under `pnpm dlx` with advice that
can't work there; `check` reporting "100% implementation coverage" on a spec
with zero implementation; `pack` dropping the exact spec a task named when the
token budget got tight; and `ready` passing a story-coverage check against a
PRD that didn't exist.

## The dangerous bugs report green

Three of those six shared a shape worth naming: they were vacuous passes. The
drift checker supports three frameworks, and on a site built with none of them
it found nothing checkable — and called that 100% coverage. A CI job wired to
that output would certify unimplemented specs forever. The crash bugs are
cheap: they announce themselves at the moment of failure. The green-checkmark
bugs are expensive, because the whole point of the output is to be trusted
unread. The fix that matters isn't the coverage math — it's that `check` now
says "coverage not assessed" and exits with a distinct code (3) so automation
can't mistake silence for health.

## Verifying the fixes found two more

0.4.0-alpha.6 arrived the same day claiming all six fixed. Instead of trusting
release notes, I re-ran every repro. All six held — and the verification pass
itself surfaced two new bugs. `pack`, now correctly keeping the task-named
spec, trimmed it from 849 tokens to 342 to fit the budget and said nothing: five
sections gone, no omission marker, so an agent consuming the packed context
would read a spec that ends after Architecture as a spec with no Risks section.
And the graph's new mismatch warning suggested a `requires` edge that was the
exact reverse of an existing one — advice that, followed, produced a circular
dependency `validate` happily accepted. Both went upstream; 0.4.0-alpha.7
closed them the same day, and this time re-verification came back clean.

## The tenth issue got a better fix than the one I asked for

The sprint left one thing deliberately unfixed. `check` now told the truth
about this site — exit code 3, "coverage not assessed" — but an honest zero
is still a zero: the drift checker supported three frameworks, this site uses
none of them, and so nothing here was actually being checked. The morning
after the sprint converged I filed the tenth issue asking for Astro support.

It closed in under two hours, and not with what I'd asked for. Rather than an
Astro extractor, the fix went framework-agnostic: any spec can declare the
`artifacts` it claims to produce — file paths, plus named exports per file —
and `check` verifies them with no framework knowledge at all. The design was
recorded as the specdx suite's first ADR, with per-framework route extraction
explicitly deferred. Asking for support for my stack produced an answer that
works for every stack. That's the reason to file the issue rather than fork
the tool: a workaround would have solved it for one Astro repo, and solved it
worse.

This site declares 25 such checks across its three specs today, and `specdx
check` runs in the verification gate — so drift detection blocks a commit
here, where four days earlier there was nothing to run.

## The tally, and one irony

Ten issues in four days, every one closed the day it was filed. What stays
behind in this repo: specdx pinned as a devDependency, `check-specs` in the
five-command verification gate and CI — now running drift detection, not just
linting — and two real specs feeding real future work. And one irony, found
the same afternoon: while writing up vacuous
green checkmarks in specdx, a casual "all ok?" revealed this repo's own CI had
failed on every push since the rebuild — a pnpm version conflict that killed
setup in ten seconds, invisible because deploys never depended on it. Vacuous
signals aren't a specdx problem. They're the default state of any system whose
outputs are trusted unread, and you have to engineer against them everywhere.
