spec · diff

git:20260922.c7615a5 to git:20260924.59d6cfa

59 added, 15 removed. Audit A to A.

---
name: spec
description: >
Write and keep current the reference documents a team reads long after the work that produced them
merged: the API contract per resource, the schema per table, and the behaviour of a feature. Also
compares what those documents claim against what the code does, and reports where the two drifted.
- Use when a project has no written contract, when a merged change left one behind, or when nobody
- trusts the documents any more.
+ In a project that works contract-first, writes them from the design before the code exists, so
+ frontend, backend and QA can work against one agreed contract.
+ Use when a project has no written contract, when a merged change left one behind, when nobody
+ trusts the documents any more, or when the contract has to exist before anyone writes the code.
Triggers on: "spec", "api spec", "database spec", "feature spec", "đặc tả", "tài liệu API",
"tài liệu database", "spec bị lệch", "cập nhật tài liệu", "仕様書", "API仕様", "spec drift",
- "document this endpoint", "is the doc still true", "/atk:spec".
- argument-hint: "[subject] [--kind api|db|feature] [--sync] [--check] [--lang <code>] [--out <path>]"
+ "document this endpoint", "is the doc still true", "api docs before the code", "contract first",
+ "viết tài liệu API trước khi code", "API docs cho FE làm trước", "実装前にAPI仕様を書く",
+ "/atk:spec".
+ argument-hint: "[subject] [--kind api|db|feature] [--from <design-path>] [--sync] [--check] [--lang <code>] [--out <path>]"
---
# Reference Specs (`atk:spec`)
- Owns the document somebody opens to answer "what does this endpoint do today". It carries no options
- and no history: it describes the system as it currently is, which is why a stale line in it is wrong
- rather than merely old, and why it is updated in place forever instead of being superseded.
- `shared/spec-docs.md` holds what separates it from a design document, and the obligation that keeps
- it true.
+ Owns the document somebody opens to answer "what does this endpoint do today", or, in a project whose
+ profile says `Contract: first`, "what is this endpoint agreed to do". It carries no options and no
+ history: it describes the system as it currently is or is agreed to be, which is why a stale line in
+ it is wrong rather than merely old, and why it is updated in place forever instead of being
+ superseded. `shared/spec-docs.md` holds what separates it from a design document, what changes under
+ `Contract: first`, and the obligation that keeps it true.
## Scope
Handles: writing and updating reference documents for API contracts, database schema, and feature
- behaviour; taking their shape from the documents a project already keeps; folding a merged change
- into them; and reporting where they and the code disagree.
+ behaviour; taking their shape from the documents a project already keeps; under `Contract: first`,
+ writing them from a design before the code exists and moving them onto the code as it lands; folding
+ a merged change into them; and reporting where they and the code disagree.
Does NOT handle: choosing an approach or weighing options (`atk:design-doc`, which decides and then
stops); turning a request into requirements (`atk:intake`); reviewing one change (`atk:review`);
generating OpenAPI documents, DDL, or migrations. It writes prose a person reads and never executes
a schema change.
It also does not decide that the code is wrong. A drift finding says the two disagree and which side
moved. Which of them changes is a decision, and decisions belong to the approver below.
## Roles
Dev authors. Tech Lead approves the `api` and `db` kinds, because both are contracts other people
work against. BrSE/BA approves the `feature` kind, because it states what the product does for a
user and that is a business claim rather than a technical one. See `shared/team-roles.md`.
The approver differs by kind, so a run covering two kinds produces two documents with two approvers.
Never one document with a shared one.
## Invocation
```bash
/atk:spec <subject> # Write or update the document for one subject
/atk:spec <subject> --kind api # Say which kind when the subject alone is ambiguous
+ /atk:spec <subject> --from <design-path> # Contract-first: write the document from the design, before the code
/atk:spec --sync # Fold the change on the current branch into the documents it touched
/atk:spec --check # Report drift between the documents and the code, change nothing
/atk:spec --check --kind db # Limit the drift report to one kind
/atk:spec --lang vi # Write the document in Vietnamese
/atk:spec --out <path> # Override the resolved path
```
## Workflow
```
- [1. Resolve kind and file] -> [2. Take the shape] -> [3. Read the code] -> [4. Write] -> [5. Report]
+ [1. Resolve kind and file] -> [2. Take the shape] -> [3. Read the source] -> [4. Write] -> [5. Report]
```
Before step 1, read `.atk/overrides/spec.md` when it exists, per rule 7 of `shared/team-roles.md`.
### 1. Resolve the kind and the file
The kind comes from `--kind`, or from the subject when it is unambiguous: a route or a resource name
means `api`, a table name means `db`, a named capability means `feature`. Ask when two kinds fit and
the answer changes which directory is written.
Where the subject belongs to one member repository and that member keeps a docs tree of its own,
resolve the directory there: the document then travels in the same pull request as the code, which is
what the sync obligation asks for. A contract two members share belongs to the project docs root.
`shared/artifact-paths.md` owns the split.
Resolve the directory from the `Docs` section of `.atk/profile.md`, falling back to the three default
kinds in `shared/artifact-paths.md`. A kind the project declared there is as valid as the three that
ship with the kit.
The file is named after the subject, never after a ticket or a date. Read it first when it exists;
this skill updates in place, and the reason is in the Persistence section of
`shared/artifact-paths.md`.
+ `--from` has two preconditions, checked here before anything is written. The `Contract` line in the
+ Docs section of `.atk/profile.md` says `first`: a missing line or `TBD` means `code`, per
+ `shared/spec-docs.md`, and changing it is the Tech Lead's call, so name that person and stop rather
+ than write a document the project's own rules call stale. And the design is at `IN REVIEW` or
+ `APPROVED`: a `DRAFT` is not a source, because nobody has been asked to look at it. Where either
+ fails, say which and change nothing.
+
### 2. Take the shape from the neighbours
When the directory already holds documents of this kind, read one and follow it, per the shape rule
in `shared/spec-docs.md`. Use `references/api-spec-template.md`, `references/db-spec-template.md`, or
`references/feature-spec-template.md` only when there is nothing to copy from. Say in the run summary
which of the two happened, so a reviewer knows whether the shape was inherited or invented.
- ### 3. Read the code
+ ### 3. Read the source
Describe what the code does, citing `path:line`. Do not describe intended behaviour taken from a
ticket, a design document, or a Figma file: those say what was going to happen, and the gap between
them and the code is exactly what this document exists to expose. Where they disagree, that is a
finding for step 5, not something to smooth over while writing.
+ `--from` is the one exception, and it has two sources, each cited. What the design decided is taken
+ from the design named, citing its section in place of `path:line`. What the design leaves to the
+ reference document, which under `Contract: first` is the full shape (fields, types, limits, status
+ and error codes), is asked of the person running the skill, who is this document's author: list
+ every gap in one prompt, and write each answer as the author's proposal, citing the author by name,
+ for the approver to accept or change. A gap the author cannot answer becomes an open question for
+ the document's approver rather than a plausible value filled in. A ticket or a Figma file is still
+ not a source, even here; the design and its author are, because the approver reviews both.
+
For `--sync`, read the diff of the change on the current branch rather than the whole module, and
touch only what the diff touched. A sync that rewrites sections the change never reached is an
- unreviewable edit wearing a small ticket.
+ unreviewable edit wearing a small ticket. On a contract-first document, the sync moves each item the
+ diff implements from its design citation to `path:line` and takes off its not-implemented line, per
+ `shared/spec-docs.md`; on a document at `no`, it first marks every item the diff does not reach, since
+ the field stops speaking for all of them. Where the code does something other than what the item
+ says, the item keeps its mark and the sync reports the difference in its summary as a disagreement
+ for the document's approver. This is the one place a marked item is compared with its code, which is
+ why `--check` never reports one as drift, and the sync never rewrites a contract to match the code.
### 4. Write
Front matter per `shared/artifact-paths.md`, with `approver` set per kind from the Roles section
above. An update that changes what the document promises sets `status` back to `IN REVIEW`; a
correction of wording does not.
+ Under `Contract: first` the front matter also carries `implemented`, set per `shared/spec-docs.md`.
+ `--from` sets `no` on a document it creates. Run again on a document that exists, which is also how a
+ design that changed in review is carried over, it rewrites every item that cites a design from the
+ design named, adds the items the design adds, marked unless the document is at `no`, marks the items it changes that are cited to the code,
+ and leaves the rest as they were. The value is then `no` if no item cites the code, and `partial`
+ otherwise. `--sync` moves it on as the items land, and sets `yes` in the change that takes the last
+ mark off, so the value becomes true when that change merges. A document written from a design still `IN REVIEW` says so
+ under its title, and stays `IN REVIEW` itself until that design is `APPROVED`. Under `Contract: code`
+ the field is left out.
+
Two rules keep an update honest:
- Never delete a statement you did not verify. A section about behaviour outside this change stays
exactly as it is, even when it looks wrong, and goes into the drift report instead.
- Everything the document cannot answer becomes an open question carrying the name of whoever can
answer it, per rule 1 in `shared/team-roles.md`. A blank is worse than a question, because it reads
as settled.
### 5. Report
`--check` compares the documents against the code and changes no file, following
`references/drift-check.md`. That file holds the coverage checklist that keeps items from being
quietly skipped, the shape of a finding, and the read-only boundary. What counts as drift in the
first place is in `shared/spec-docs.md`, because `atk:review` has to answer it the same way.
Report in the session. Post to the ticket only when asked, and write a file only with `--out`: a
drift report is a record of one moment, and the reference document it is about is the thing meant to
last.
## Output
`docs/api/<resource>.md`, `docs/database/<table>.md`, or `docs/features/<slug>.md` per
`shared/artifact-paths.md`, one file per subject, updated in place.
Sections come from the neighbouring document when there is one, and otherwise from the template for
the kind. Diagrams are inline Mermaid per `shared/diagram-conventions.md`, and only where a sequence
or a state machine is genuinely hard to read as prose.
`--check` writes nothing unless `--out` is given.
Putting it where the team can see it is `atk:git`, which follows the artifact section of
`shared/finalize-steps.md`: the branch, the commit, and the judgement about whether this one belongs
in a pull request for its approver to read. Whether it is committed at all is the persistence group
it falls into, per `shared/artifact-paths.md`.
## Ticket
Follow `shared/ticket-adapters.md`. Link the document from the ticket that changed it, and record the
ticket in the `ticket:` field. A drift report becomes a comment or an issue only when the user asks,
one issue per finding, never one issue listing everything.
## Definition of done
- [ ] Every statement about behaviour is read from the code and cited, never copied from a ticket or
- a design document.
+ a design document; under `--from`, every statement it wrote cites the design or names its author.
+ - [ ] `--from` ran only where the profile says `Contract: first` and the design was `IN REVIEW` or
+ `APPROVED`, and `implemented` is `no` exactly when no item cites the code.
+ - [ ] Under `Contract: first`, `implemented` matches the items: at `no` every item cites the design or its
+ author and none carries a mark; at `partial` every item without the mark is cited to the code; at `yes` no
+ mark is left.
- [ ] The document's shape matches its neighbours when the directory was not empty, and the summary
says whether the shape was inherited or came from a template.
- [ ] The file is named after its subject, with no ticket and no date in the name.
- [ ] `approver` matches the kind: Tech Lead for `api` and `db`, BrSE/BA for `feature`.
- [ ] Nothing unverified was deleted; what looked wrong went into the drift report instead.
- [ ] Every open question carries the name of the person who must answer it.
- [ ] `--check` changed no file.
- [ ] `--sync` touched only what the change on the branch touched.
- [ ] A finding that the document never settled was reported as an open question, not as drift.