# Machine-Generated File Banner (Canonical Contract)

Canonical banner template emitted by every deft writer that produces a
machine-managed markdown file. Defined to eliminate the four-convention
drift surfaced in #572 (spec:render emitted none; migrator heuristic
searched for strings no writer actually produced).

Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.

## Why

Before this contract, deft had four machine-managed file writers
(frozen `task migrate:vbrief` deprecation redirects (v0.59.0; historical), `task spec:render`,
`task prd:render`, `task roadmap:render`) and each used a different
(or no) banner convention. Downstream heuristics that distinguish
"is this file user-customized" from "is this machine-managed" were
decoupled from what the writers actually emitted -- a correctness
risk, not a polish one.

## The canonical 4-line banner

! Every machine-managed markdown file MUST begin with exactly these
four HTML-comment lines, in this order, as the very first four lines
of the file:

```
<!-- AUTO-GENERATED by {generator} -- DO NOT EDIT MANUALLY -->
<!-- Purpose: {purpose} -->
<!-- Source of truth: {source} -->
<!-- Regenerate with: {command} -->
```

- `{generator}` — the human-readable writer name (e.g. `task spec:render`).
- `{purpose}` — one of the enumerated per-writer purposes below; fixed
  string values so downstream detectors can match on a stable token.
- `{source}` — the source-of-truth path the writer consumed
  (typically `xbrief/specification.xbrief.json`), or `n/a` when the
  writer has no single source-of-truth file (e.g. the migrator
  deprecation redirect, which is driven by the migration flow).
- `{command}` — the canonical `task *` invocation that regenerates
  the file; operators copy-paste from this line.

! All four lines MUST be populated (no empty `{...}` placeholders).
! The banner MUST be the first four lines of the file -- nothing
  (not even blank lines) precedes it.

## Per-writer purpose registry

The `Purpose:` value is a small fixed enum so detectors can match on a
stable token. Writers MUST use exactly one of these values:

- `rendered specification` -- `task spec:render` -> `SPECIFICATION.md`
- `rendered PRD` -- `task prd:render` -> `PRD.md`
- `rendered roadmap` -- `task roadmap:render` -> `ROADMAP.md`
- `deprecation redirect` -- frozen `task migrate:vbrief` (v0.59.0; historical)
  -> replaced `SPECIFICATION.md` / `PROJECT.md`

? Future render tasks added under `tasks/` MUST extend this list before
shipping; a new writer without a registered `Purpose:` value is a
contract violation.

## Detection heuristic (for user-customization guards)

! Frozen `task migrate:vbrief` (v0.59.0) `_is_user_customized()` consults the
`_SPEC_AUTO_MARKERS` and `_PROJECT_AUTO_MARKERS` tuples. Both MUST
include `"AUTO-GENERATED by"` and the FULL HTML-comment prefix
`"<!-- Purpose:"` so any file carrying this banner is recognised as
machine-managed. The marker is deliberately the full `<!-- Purpose:`
prefix and NOT the bare `Purpose:` string, so a hand-authored
specification containing ordinary prose such as
`"Purpose: deliver a self-service flow."` is not misclassified as
machine-managed and silently overwritten.

! Pre-cutover guards (e.g.
`skills/deft-directive-setup/SKILL.md`) MUST accept BOTH the legacy
`<!-- deft:deprecated-redirect -->` sentinel AND the current
`Purpose: deprecation redirect` marker for at least one release
cycle so consumers that migrated under rc.1 / rc.2 are not
incorrectly re-flagged as pre-cutover on rc.3.

## Example (spec:render)

```
<!-- AUTO-GENERATED by task spec:render -- DO NOT EDIT MANUALLY -->
<!-- Purpose: rendered specification -->
<!-- Source of truth: xbrief/specification.xbrief.json -->
<!-- Regenerate with: task spec:render -->
# My Project
...
```

## Example (frozen migrator deprecation redirect, v0.59.0; historical)

```
<!-- AUTO-GENERATED by task migrate:vbrief -- DO NOT EDIT MANUALLY -->
<!-- Purpose: deprecation redirect -->
<!-- Source of truth: n/a -->
<!-- Regenerate with: task migrate:vbrief -->
<!-- deft:deprecated-redirect -->
# SPECIFICATION.md -- DEPRECATED
...
```

The legacy `<!-- deft:deprecated-redirect -->` sentinel remains on the
fifth line of the deprecation redirect for one release cycle so
existing detectors (consumer agents, pre-cutover guards, the
migrator's own re-run protection in `_vbrief_safety.py`) continue to
work while tooling upgrades to the canonical `Purpose:` token.

## Regression test

`tests/content/test_machine_generated_banner.py` parametrises over
all four writers, invokes each on a fixture, and asserts:

1. the output begins with the four canonical banner lines;
2. all `{generator}`, `{purpose}`, `{source}`, `{command}`
   placeholders are populated with the expected values;
3. the `Purpose:` token is one of the four registered purposes.

Guards the convention against future drift.

## Cross-references

- #572 — originating issue
- `scripts/migrate_vbrief.py` — `_deprecation_redirect()`,
  `_SPEC_AUTO_MARKERS`, `_PROJECT_AUTO_MARKERS`
- `scripts/spec_render.py::_BANNER`
- `scripts/prd_render.py::BANNER`
- `scripts/roadmap_render.py::BANNER`
- `skills/deft-directive-setup/SKILL.md` § Pre-Cutover Detection Guard
