# zit 0.3.13

zit 0.3.13 adds the write side of attachments. zit could read attachment
artifacts — A cards fold, `zit artifact` describes them, sync carries them
— but could not author one. Every other authoring path quarry uses is a
zit verb; attachments now are too, so the artifact format is written in one
place.

No artifact, tag namespace, sync message, or on-disk format changed. One
new repository setting, `attachment-size-limit`, is carried in the config
frame under a new key; older zit reads a repository that sets it without
complaint and simply does not honour it.

## `zit attach add / rm / list` (zit#186)

```
zit attach add  TARGET FILE [--name NAME] [--comment TEXT] [--mimetype TYPE]
                [--user NAME] [-R repo]        # FILE may be - for stdin
zit attach rm   TARGET NAME [--user NAME] [-R repo]
zit attach list [TARGET] [-R repo]
```

- `add` stores FILE as a blob, then an attachment artifact carrying one
  `A NAME TARGET SOURCE` card plus `C` (when given), `D`, `N` (when given),
  `U`, `Z` — both written in the same commit, so an attachment can never
  name bytes the store does not hold. It prints the artifact's hash, then
  the blob's, on two lines. NAME defaults to FILE's final path component;
  a directory prefix is always discarded, as the format requires. TARGET
  is a ticket, technote, or forum post's hash (full or abbreviated) or a
  wiki page's name, checked for shape only — an unresolved target is
  recorded as a generic reference. An empty file is refused, as fossil
  refuses it.
- `rm` writes an A card with no source for (TARGET, NAME): the
  association ends under the format's latest-wins rule; nothing leaves
  the store.
- `list` prints the live attachments — the newest A card per name, a
  sourceless one meaning gone — as `NAME SIZE MIMETYPE BLOB DATE USER`,
  with the target as a first column when listing the whole repository.

**The cap.** `attachment-size-limit` is fossil's setting, honoured the way
fossil reads it — a byte count, checked before the blob is written, `0`
meaning unlimited — with one difference: unset, zit's default is **1 MiB**,
not unlimited. A blob in the DAG travels to every clone for ever, and a
default that lets a first-time user attach a 400 MB recording is the wrong
default. `add` refuses over the limit naming the size and the limit;
`zit settings attachment-size-limit N` raises it.

**Interop.** A zit-authored attachment pushed to a real fossil server
crosslinks as a live attachment on its target with zit's blob as its
source — fossil's `attachment` table says so, and the smoke suite now
checks it on every run (scenario S15).

## The quarry attachment stub (zit#187)

quarry never attaches file bytes to a hosted repository; it attaches a
small text blob naming the bytes by SHA-256, size, type and name, so the A
card stays a valid fossil artifact and the store stays small. zit now
recognises that shape:

- `zit attach list` shows it as `NAME SIZE TYPE external:sha256:…`, with
  the size and type it points at rather than the stub's own bytes.
- `zit artifact HASH` on the blob adds an `attachment-stub:` line.
- The size cap applies to the blob actually stored, so a stub always
  passes. Nothing write-side changed; a client that does not recognise a
  stub sees a small text file under the attachment's name.

## Compatibility

- Fossil RFC revision 00 remains the target; the attachment artifact is
  written in the form the format specifies and fossil's own reader
  crosslinks it.
- The new setting lives in the config frame under a fresh key, read as
  "unset" by any zit that predates it.
- `attach` is a machine verb: unlisted in `zit help`'s command list like
  `wiki`, `ticket`, `forum` and `technote`, documented by `zit help attach`
  and in the command reference.

## Qualification

`zig build test`, `e2e` (including the new attach test: add/list/replace/
rm, the size limit and its lifting, stdin, a wiki-name target, prefix
stripping, and the stub), `smoke` (Fossil interop against a real `fossil`,
now including S15), `muscle` (41 differential steps), `git-import-e2e`,
`git-export-e2e`, and `dst`, plus the three-runner CI battery.
