quadlet-lens 0.2.0

Loss-aware parsing, validation, and rendering of version-aware Quadlet documents
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
# Roadmap

The roadmap is ordered by dependencies rather than dates.

Cross-repository delivery uses the stable task numbers in the [implementation plan](implementation-plan.md). This roadmap remains the detailed internal phase order for QuadletLens.

The [quality plan](quality-plan.md) groups the remaining work into maintainable priorities and
defines what “good enough” means for testing and conformance.

## Status key

- [x] Completed and validated
- **Recurring maintenance** — performed when an upstream release, supported target, or concrete
  regression supplies evidence; it is not a backlog checkbox.
- **Deferred boundary** — intentionally outside the current contract until a concrete consumer,
  use case, and evidence define it; it is not a backlog checkbox.

## Specification coverage ledger

The bounded phase-1 ledger is completed and was audited on 2026-08-14 against the current official
[Podman Quadlet manual](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html). Its
strict 222-row, versioned source of truth is
[`quadlet-manual-current.toml`](../fixtures/specification-drift/quadlet-manual-current.toml). It
records the latest documented key surface, not the subset available at the Podman 5.4 minimum.
Each promoted key still needs separate introduction/deprecation/removal evidence over the finite
supported Podman range.

QuadletLens syntax-preserves ordered unknown sections and keys. “Missing” below therefore means
that the key has no native typed enum/builder contract; it does not mean the source text is lost or
that the syntax parser rejects it.

| Section/unit                 | Current keys | Typed keys | Syntax-preserved only |
| ---------------------------- | -----------: | ---------: | --------------------: |
| `[Container]` / `.container` |           89 |         89 |                     0 |
| `[Pod]` / `.pod`             |           25 |         25 |                     0 |
| `[Network]` / `.network`     |           18 |         18 |                     0 |
| `[Volume]` / `.volume`       |           16 |         16 |                     0 |
| `[Build]` / `.build`         |           28 |         28 |                     0 |
| `[Image]` / `.image`         |           18 |         18 |                     0 |
| `[Kube]` / `.kube`           |           14 |         14 |                     0 |
| `[Artifact]` / `.artifact`   |           13 |         13 |                     0 |
| `[Quadlet]`                  |            1 |          1 |                     0 |
| reviewed `[Unit]` relations  |            9 |          9 |                     0 |

The typed model additionally recognizes historical/non-current-manual `Container.ImageVolume` and
Kube `LogOpt`, `RemapGid`, `RemapUid`, `RemapUidSize`, and `RemapUsers`. They remain preserved and
typed parser surface, but are deliberately outside the 222-row current-manual drift inventory until
the aggregate manual documents them again. `[Unit]`, `[Service]`, and `[Install]` are also excluded
because systemd, not Quadlet, owns their open-ended directive vocabulary.

The typed counts describe key recognition and programmatic construction. Capability and generator
evidence are separate layers documented in [Native coverage](coverage.md).

### Typed `[Container]` keys

All 89 current aggregate-manual Container keys are typed. `ContainersConfModule` and `GlobalArgs`
are repeatable physical entries; the remaining current-manual keys are singletons. The
historical/non-current-manual `ImageVolume` key remains typed and repeatable without a positive
native capability claim. Health-startup, health-log, and generated-service-name values remain
opaque.

The typed keys are `AddHost`, `ContainerName`, `Image`, `Rootfs`, `Entrypoint`, `RunInit`,
`StopSignal`, `StopTimeout`, `Pull`, `PidsLimit`, `HostName`, `ShmSize`, `ReloadCmd`, `ReloadSignal`, `DropCapability`,
`AddCapability`, `Tmpfs`, `Sysctl`, `Ulimit`, `AddDevice`, `Memory`, `LogDriver`, `LogOpt`, `IP`,
`IP6`, `NetworkAlias`, `DNS`, `DNSOption`, `DNSSearch`, `ExposeHostPort`, `Annotation`, `AppArmor`,
`NoNewPrivileges`, `SeccompProfile`, `SecurityLabelDisable`, `SecurityLabelFileType`,
`SecurityLabelLevel`, `SecurityLabelNested`, `SecurityLabelType`, `Mask`, `Unmask`, `Exec`,
`Environment`, `EnvironmentFile`, `Label`, `Secret`, `User`, `Group`,
`UserNS`, `GroupAdd`, `WorkingDir`, `ReadOnly`, `PublishPort`, `Volume`, `Network`, `Pod`,
`HealthCmd`, `Notify`, `HealthInterval`, `HealthRetries`, `HealthStartPeriod`, `HealthTimeout`,
`PodmanArgs`, `AutoUpdate`, `CgroupsMode`, `EnvironmentHost`, repeatable `GIDMap`/`UIDMap`,
`HttpProxy`, repeatable `Mount`, `ReadOnlyTmpfs`, `Retry`, `RetryDelay`, `StartWithPod`,
`SubGIDMap`, `SubUIDMap`, `Timezone`, `HealthOnFailure`, `ContainersConfModule`, `GlobalArgs`,
`HealthLogDestination`, `HealthMaxLogCount`, `HealthMaxLogSize`, `HealthStartupCmd`,
`HealthStartupInterval`, `HealthStartupRetries`, `HealthStartupSuccess`, `HealthStartupTimeout`,
`ImageVolume`, and `ServiceName`.

### Typed `[Pod]` keys

All 25 current Pod keys are typed. `ContainersConfModule`, `DNS`, `DNSOption`, `DNSSearch`,
`GIDMap`, `GlobalArgs`, `Label`, `NetworkAlias`, `PodmanArgs`, and `UIDMap` retain ordered opaque
physical entries; the other Pod keys are opaque singletons. Pod mapping conflicts use the same
effective-value, source-spanned `QLM0013`–`QLM0015` diagnostics as Container mappings.

The typed Pod keys are `AddHost`, `PodName`, `PublishPort`, `Network`, `Volume`, `UserNS`,
`ShmSize`, `ExitPolicy`, `StopTimeout`, `ServiceName`, `ContainersConfModule`, `DNS`, `DNSOption`,
`DNSSearch`, `GIDMap`, `GlobalArgs`, `HostName`, `IP`, `IP6`, `Label`, `NetworkAlias`,
`PodmanArgs`, `SubGIDMap`, `SubUIDMap`, and `UIDMap`.

### `[Network]` key boundary

All current Network keys are typed. `ContainersConfModule`, `DNS`, `GlobalArgs`, and `PodmanArgs`
retain ordered opaque physical values; `DisableDNS`, `InterfaceName`, `NetworkDeleteOnStop`, and
`ServiceName` are opaque singletons. The generator fixture records 5.5.0 cleanup and 5.6.0 interface
boundaries; lifecycle cleanup is not conflated with actual network deletion.

### Typed `[Volume]` keys

`VolumeName`, `Driver`, `Options`, `Label`, `Device`, `Type`, `Copy`, `ContainersConfModule`, `GlobalArgs`, `PodmanArgs`, `User`, `Group`, `UID`, `GID`, `ServiceName`, and `Image` are typed. No current Volume keys remain syntax-preserved only.

### Other typed unit-key boundaries

The syntax layer preserves these unit files, but their native unit type, section, keys, builders,
relationships, capability records, and generator fixtures are open.

- `[Build]`: all current keys are typed. `ImageTag` and repeatable
  opaque `Network`/`Label`/`File`/`BuildArg`/`Secret`/`GroupAdd`/`DNS`/`DNSOption`/`DNSSearch`/`Annotation`/`Environment`/`ContainersConfModule`/`GlobalArgs`/`Volume`/`PodmanArgs` are typed with full 5.4.0-through-6.0.2
  generator evidence; singleton `SetWorkingDirectory`/`Target`/`Arch`/`Variant`/`Pull`/`Retry`/`RetryDelay`/`TLSVerify`/`ForceRM`/`AuthFile`/`IgnoreFile`/`ServiceName` values are also typed;
  exact `.network` Build references resolve in document sets, while effective-last `File` selection
  remains target evidence, not Lens normalization. `Label` retains every physical line without
  parsing, unquoting, duplicate-name selection, map collapse or sorting, or validation; the matrix
  covers only `build.label=one` and `empty=`. `BuildArg` is explicitly unsupported through 5.6.2,
  native from 5.7.0 through 6.0.2, and otherwise unknown; it remains opaque with no assignment,
  environment, secret, bare, or null-value interpretation. `Secret` is native from 5.4.0 through
  6.0.2 and unknown outside that range; it remains opaque without comma, argument, environment,
  path, or secret-data interpretation, and its separate fixture uses placeholder paths only. `Arch`
  and `Variant` preserve raw singleton text without platform parsing, host defaults, or effective-last
  normalization; their separate fixture asserts one `--arch arm64` and one `--variant v8` without
  a relative-order claim. `Pull` preserves opaque raw singleton text without policy validation,
  default selection, normalization, effective-last access, Compose mapping, registry, image-pull, or runtime claims; its separate fixture asserts exactly one `--pull=always` form. `Retry` and `RetryDelay` are unsupported in 5.4.0–5.4.2, native in 5.5.0–6.0.2, and otherwise unknown; their opaque fixture asserts one separate `--retry 4` pair and one separate `--retry-delay 7s` pair before final `.` without a relative-order claim between pairs, and makes no parsing, defaults, effective-last, Compose `dockerfile_inline`, registry, retry/timing, build-success, runtime, or conversion claim. `TLSVerify` is opaque and native in 5.4.0–6.0.2, otherwise unknown; its two-unit fixture asserts one bare `--tls-verify` for true and one `--tls-verify=false` for false before final `.`, without TLS/certificate/registry/pull/build-success/security/provenance/runtime/conversion claims. `ForceRM` is opaque and native in 5.4.0–6.0.2, otherwise unknown; its two-unit fixture asserts one bare `--force-rm` for true and one `--force-rm=false` for false before final `.`, without parsing/default/effective-last, cleanup/failure/execution/default/configuration/cache-equivalence, runtime, or conversion claims. `GroupAdd` is repeatable and native in 5.4.0–6.0.2, otherwise unknown; its fixture asserts ordered separate `--group-add 1234` then `--group-add 5678` pairs before final `.`, without group lookup, keep-groups exclusivity, rootless/user-namespace, runtime, build-execution, Compose privilege-equivalence, or conversion claims. `DNS` is repeatable and native in 5.4.0–6.0.2, otherwise unknown; its fixture asserts ordered separate `--dns 9.9.9.9` then `--dns 2001:4860:4860::8888` pairs before final `.`, without resolver, none-compatibility, resolv.conf, host-DNS, build-execution, Compose endpoint-mapping, or conversion claims.
- `[Image]`: all current keys are typed. `PodmanArgs` remains repeatable; `Policy`, `Retry`,
  `RetryDelay`, `TLSVerify`, and `Variant` are opaque singletons. Its fixture records the 5.5.0
  Retry/RetryDelay and 5.6.0 Policy boundaries without claiming registry or pull behavior.
- `[Kube]`: all current keys are typed. `Yaml` is required and repeatable; it and `ConfigMap`
  are only lexical path values. QuadletLens never reads either file or parses Kubernetes YAML.
- `[Artifact]` (experimental upstream): `Artifact`, `AuthFile`, `CertDir`,
  `ContainersConfModule`, `Creds`, `DecryptionKey`, `GlobalArgs`, `PodmanArgs`, `Quiet`, `Retry`,
  `RetryDelay`, `ServiceName`, `TLSVerify`.
- `[Quadlet]`: `DefaultDependencies`.

### Generic systemd sections

`[Unit]`, `[Service]`, and `[Install]` remain deliberately open-ended because their complete key
space belongs to systemd, not Quadlet. All directives are syntax-preserved. QuadletLens currently
provides typed construction, reset-aware unit-list graph semantics, and capability evidence for
`[Unit]` `Requires`, `Wants`, `After`, `Requisite`, `BindsTo`, `PartOf`, `Upholds`, `Conflicts`,
and `Before`, plus `[Service]` `Restart`.

Podman 5.4 preserves native Quadlet basenames in those relationship lists literally; Podman 5.5
and newer rewrite them to generated service names. `Upholds` additionally requires systemd 249 or
newer; the optional caller-supplied systemd target context now checks that boundary without host
probing.
Other systemd directives should be promoted only for a concrete consumer scenario and must retain
their native ordering and repetition rules.

## Priority after 0.1.9

### Completed phase-2 Environment encoder slice

- [x] Add public render-owned `EnvironmentAssignment` and non-empty `EnvironmentAssignments`
      encoders for ASCII-named literal container assignments, with exact whole-assignment quoting,
      explicit `EntryValue` conversions, physical-directive ordering, parse-back/public-API tests,
      and smoke/full dry-run evidence for two distinct `--env` arguments from one grouped line.
- [x] Add the public zero-sized `EnvironmentReset` marker and ordered blank directive builder
      method, with source-preserving model tests and 5.4.0–6.0.2 source/dry-run evidence that two
      post-reset names become distinct `--env` arguments while two pre-reset names are absent.
- [x] Add a builder-owned `ContainerEnvironmentPlan` that preserves assignment/group/reset
      directive order, exposes explicit per-name later-wins/reset-clears literal lookup plus opaque
      membership/cardinality, retains empty values, emits original directives unchanged, and
      redacts debug output.
- [x] Add the bounded authored `Environment=` semantic view: physical order, literal assignments,
      bare names, reset, quote/escape handling, continuations, deferred `%` specifiers,
      recoverable `QLM0023`/`QLM0024` diagnostics, and redacted debug output. **Deferred
      boundary:** environment-file/secret loading, manager/process/runtime expansion, command
      parsing, and a general systemd token grammar require a concrete use case and evidence.

### Next 1: lifecycle and process parity

- [x] Type singleton container `Entrypoint` and verify JSON-array argument preservation from Podman
      5.4.0 through 6.0.2.
- [x] Type singleton container `RunInit`, preserve omission and explicit true/false/raw values, and
      verify that true emits one `--init` while false emits one `--init=false` from Podman 5.4.0 through
      6.0.2.
- [x] Type singleton container `StopSignal` and `StopTimeout`, preserve native zero, and verify
      named/numeric signals plus positive/zero timeout generator observations from Podman 5.4.0 through
      6.0.2.
- [x] Type singleton container `Pull`, preserve omission and raw values, and verify isolated
      `always`, `missing`, `never`, and `newer` generator output from Podman 5.4.0 through 6.0.2.
- [x] Type singleton container `PidsLimit`, preserve omission/zero/raw values, add safe typed
      `-1`/nonzero ASCII-decimal construction without parsing, and verify isolated positive/unlimited
      generator output from Podman 5.4.0 through 6.0.2 without claiming runtime cgroup behavior.
- [x] Record the exact generic `PodmanArgs=--interactive` escape-hatch form with boundary manuals,
      tagged source, and one isolated all-20-release generator assertion; retain the existing generic
      repeatable API and claim generated command text only, not runtime stdin, attach, or TTY behavior.
- [x] Record the exact generic `PodmanArgs=--tty` escape-hatch form with boundary manuals, tagged
      source, and one isolated all-20-release generator assertion; retain the existing generic
      repeatable API without a `Tty` key or wrapper, and claim generated command text only, not runtime
      TTY, stdout, stderr, or pipe behavior.
- [x] Record the exact generic `PodmanArgs=--privileged` and `PodmanArgs=--privileged=false`
      escape-hatch forms with endpoint Quadlet manuals, tagged command placement, Podman CLI
      boolean/default evidence, and one isolated all-20-release two-unit generator assertion; retain
      the existing generic repeatable API without a `Privileged` key or wrapper, support only the
      finite 5.4.0-through-6.0.2 range, and claim command text only—not runtime privileges, devices,
      LSM, seccomp, rootless, or cross-format equivalence.
- [x] Type repeatable Build `PodmanArgs` as opaque physical-line text and record exact
      `--build-context extra=container-image://alpine:3.15` command placement through the all-20
      generator matrix, without Compose context lowering, resolution, CLI, build, runtime, or cross-format claims.
- [x] Record exact Build `PodmanArgs=--ssh=default` command placement through the all-20 generator
      matrix with endpoint manuals and tagged source; this non-secret fixture claims no keys, sockets,
      agent, PEM, path, environment, mount, build, runtime, or Compose lowering behavior.
- [x] Record exact Build `PodmanArgs=--shm-size=32m` command placement through the all-20 generator
      matrix with endpoint Quadlet/build manuals and tagged source; it adds no native Build `ShmSize`
      key and claims no Compose/unit equivalence, zero/default, IPC, host/cgroup/memory, build/runtime,
      or conversion behavior.
- [x] Record exact Build `PodmanArgs=--add-host=buildhost:192.0.2.10` command placement through
      the all-20 generator matrix with endpoint Quadlet/build manuals and tagged source; it does not
      lower Compose list/map hosts, establish IPv6/host-gateway/DNS/`/etc/hosts` semantics, resolve
      conflicts/defaults, or claim build, runtime, or conversion behavior.
- [x] Record exact Build `PodmanArgs=--cap-add=CAP_SYS_ADMIN` command placement through the all-20
      generator matrix with endpoint Quadlet/build manuals and tagged source; it does not establish
      Compose entitlement equivalence/conversion, actual capability grants, build execution, or
      LSM/seccomp/rootless/runtime effects.
- [x] Type singleton Build `Retry` and `RetryDelay` as opaque values; record the 5.4.x rejection
      boundary and 5.5.0–6.0.2 generator output without retry/timing, runtime, or conversion claims.
- [x] Type singleton Build `TLSVerify` as an opaque value and verify isolated true/false command
      construction from Podman 5.4.0 through 6.0.2 without TLS, registry, build-success, security,
      runtime, or conversion claims.
- [x] Type singleton Build `ForceRM` as an opaque value and verify isolated true/false command
      construction from Podman 5.4.0 through 6.0.2 without cleanup, failure, execution, default,
      configuration, cache-equivalence, runtime, or conversion claims.
- [x] Type repeatable Build `GroupAdd` as opaque physical-line values and verify ordered separate
      group arguments from Podman 5.4.0 through 6.0.2 without group lookup, keep-groups exclusivity,
      rootless/user-namespace, runtime, build-execution, Compose privilege-equivalence, or conversion claims.
- [x] Type repeatable Build `DNS` as opaque physical-line values and verify ordered separate DNS
      arguments from Podman 5.4.0 through 6.0.2 without resolver, none-compatibility, resolv.conf,
      host-DNS, build-execution, Compose endpoint-mapping, or conversion claims.
- [x] Type repeatable Build `DNSSearch` as opaque physical-line values and verify ordered separate
      post-reset `--dns-search corp.example` then `--dns-search .` arguments from Podman 5.4.0 through
      6.0.2, without model reset or dot semantics, domain removal, DNS/resolver work, build execution,
      Compose mapping, or conversion claims.
- [x] Type singleton Build `AuthFile` as opaque physical-line text and verify one separate path,
      generator-effective-last repeated output, and final-empty omission from Podman 5.4.0 through
      6.0.2, without model normalization, path reads or validation, credential parsing, sensitivity
      classification, authentication, build success, runtime, Compose mapping, or conversion claims.
- [x] Type singleton Build `IgnoreFile` as opaque physical-line text; record 5.4.0–5.6.2
      rejection/exclusion and 5.7.0–6.0.2 one-path, generator-effective-last, and final-empty
      command construction without model normalization, path or ignore-rule interpretation, build
      success, runtime, Compose mapping, or conversion claims.
- [x] Type repeatable Build `Annotation` as opaque physical-line text and record all-20-release
      target reset, tokenization/unquoting/C-unescaping, duplicate-key-collapse, sorting, and 5.6.0
      bare/malformed-token behavior without Lens normalization, OCI/image-metadata, build, runtime,
      Compose mapping, or conversion claims.
- [x] Type repeatable Build `Environment` as opaque physical-line text and record all-20-release
      target reset, tokenization/unquoting/C-unescaping, duplicate-name selection, sorting, and 5.6.0
      bare/malformed-token representation behavior without Lens normalization, host lookup, build,
      runtime, Compose mapping, or conversion claims.
- [x] Type repeatable Build `ContainersConfModule` as opaque physical-line text and record
      all-20-release target reset plus ordered post-reset `--module` command construction without Lens
      path parsing, module reads, configuration inspection, deduplication, normalization, build,
      runtime, Compose mapping, or conversion claims.
- [x] Type repeatable Build `GlobalArgs` as opaque physical-line text and record all-20-release
      target reset, tokenization/unquoting/C-unescaping, malformed-line omission, and ordered placement
      between `podman` and `build` without Lens option validation, security, runtime, build, Compose,
      or conversion interpretation.
- [x] Type Build `ServiceName` as opaque singleton physical-line text, retain raw duplicate source
      diagnostics, and record all-20-release generated-unit default/override, template, and unmatched-quote
      naming observations without assigning document, dependency, runtime, or conversion identity semantics.
- [x] Type repeatable Build `Volume` as opaque physical-line text with only exact source-prefix
      `.volume` references, and record all-20-release reset/continuation, relative-source, and native
      volume substitution/dependency observations without mount, filesystem, runtime, or conversion claims.
- [x] Type repeatable Volume `ContainersConfModule` as opaque physical-line text and record
      all-20-release target reset, continuation presentation, and ordered post-reset `--module` command
      construction before `volume create` without Lens path parsing, module reads, configuration
      inspection, deduplication, normalization, volume creation, lifecycle, filesystem, runtime,
      Compose mapping, or conversion claims.
- [x] Type repeatable Volume `GlobalArgs` as opaque physical-line text and record all-20-release
      target reset, tokenization/unquoting/C-unescaping, malformed-line omission, and ordered
      post-reset token placement before `volume create` without Lens argument parsing, validation,
      security inference, volume creation, lifecycle, filesystem, runtime, Compose mapping, or
      conversion claims.
- [x] Type repeatable Volume `PodmanArgs` as opaque physical-line text and record all-20-release
      target reset, tokenization/unquoting/C-unescaping, malformed-line omission, and ordered terminal
      placement before the volume name without Lens CLI parsing, dedicated-key semantics, security
      inference, volume creation, lifecycle, filesystem, systemd, runtime, Compose mapping, or
      conversion claims.
- [x] Type opaque singleton `ReloadCmd` and `ReloadSignal`, reject their generated mutual-exclusion
      pair, and record the 5.4.x rejection plus 5.5.0–6.0.2 dry-run `ExecReload` boundary without
      command parsing, signal validation, resource-name derivation, or runtime execution.
- [x] Type opaque singleton pod `ExitPolicy` with its explicit 5.4.0–5.5.2 rejection and
      5.6.0–6.0.2 generator boundaries, without policy or restart interpretation.
- [x] Type opaque singleton pod `StopTimeout` with its explicit 5.4.0–5.6.2 rejection and
      5.7.0–6.0.2 generator boundaries, without timeout or restart interpretation.
- [x] Type opaque singleton pod `ServiceName`, preserve source values and duplicate diagnostics, and
      record generated-unit naming observations without assigning restart, identity, or runtime semantics.

### Next 2: networking and metadata parity

- [x] Type singleton container `HostName`, preserve omission/raw values without Compose
      validation, document private/default/pod-shared UTS behavior, and verify one isolated hostname
      argument from Podman 5.4.0 through 6.0.2 without claiming runtime behavior.
- [x] Type shared DNS, pod hostname, IP, network-alias, label, and module/global-argument concepts for
      container and pod units where their value grammars actually agree.
- [x] Complete the current `[Network]` key surface, including DNS and delete-on-stop lifecycle.
- [x] Keep repeatability and cross-field constraints explicit; do not reduce them to raw maps.

### Next 3: security, resources, health, and storage

- [x] Type singleton container and pod `ShmSize`, preserve omission/raw values, add exact native
      non-negative decimal construction with optional `b`/`k`/`m`/`g`, and verify positive, zero, and
      pod-owned generator arguments from Podman 5.4.0 through 6.0.2 without runtime claims.
- [x] Type repeatable container `DropCapability` as opaque ordered native values and verify exact
      lowercase generator arguments from Podman 5.4.0 through 6.0.2 without runtime privilege claims.
- [x] Type repeatable container `AddCapability`, including raw empty resets, and verify isolated
      additions plus drop-all/add-one ordering from Podman 5.4.0 through 6.0.2 without runtime claims.
- [x] Type repeatable container `Tmpfs`, preserve raw empty resets and opaque destination/options
      separately from `Volume`, and verify exact post-reset generator output from Podman 5.4.0 through
      6.0.2 without target-option, rootless, mount, or runtime claims.
- [x] Type repeatable container `Sysctl`, preserve raw empty resets and exact opaque one-line
      entries, and verify endpoint manuals, tagged `LookupAllStrv` construction/tokenization/reset,
      plus exact post-reset generator output from Podman 5.4.0 through 6.0.2 without namespace,
      rootless, kernel, or runtime-effect claims.
- [x] Type repeatable container `Ulimit`, preserve raw empty resets and exact opaque one-line
      entries, and verify endpoint manuals, Podman-run grammar/default caveats, tagged `LookupAll`
      command/reset construction, plus exactly two ordered post-reset generator arguments from Podman
      5.4.0 through 6.0.2 without runtime, host-inheritance, default, cgroup, rootless, or
      unknown-resource-name claims.
- [x] Type repeatable container `AddDevice`, preserve raw empty resets, duplicates, exact physical
      values, whitespace, quotes/specifiers, and leading `-`, and verify endpoint manuals, Podman-run
      caveats, tagged `LookupAllStrv`/conditional/reset construction, plus exactly two ordered final
      post-reset generator arguments from Podman 5.4.0 through 6.0.2 without CDI, runtime-access,
      rootless, SELinux, cgroup, existence, or symlink claims.
- [x] Type singleton container `Memory`, preserve raw values and duplicate diagnostics, add positive
      arbitrary-precision decimal construction, prove 5.4.x rejection/exclusion, and verify exactly one
      explicit-byte argument across all 17 Podman 5.5.0-through-6.0.2 patches without runtime claims.
- [x] Type singleton container `LogDriver` and repeatable/resettable `LogOpt` as opaque physical
      values, and verify one driver plus ordered post-reset options across Podman 5.4.0 through 6.0.2
      without validation, default, runtime, or cross-format claims.
- [x] Type singleton container `IP` and `IP6` plus repeatable/resettable `NetworkAlias` as opaque
      values, and verify address flags plus ordered final aliases with one selected network across
      Podman 5.4.0 through 6.0.2 without address, IPAM, DNS, runtime, or cross-format claims.
- [x] Type singleton network `Driver` and repeatable/resettable `Options` as opaque physical
      values, and verify reset, duplicate-key collapse, sorted final options, and the 5.4.0 versus
      6.0.2 bare-token difference without provider validation, runtime, or cross-format claims.
- [x] Type singleton network `Internal` and `IPv6` as opaque physical values, preserving literal
      true/false and invalid text without boolean parsing; verify omission/true/false generator forms
      across 5.4.0 through 6.0.2 without driver, network-creation, or runtime claims.
- [x] Type singleton `IPAMDriver` and repeatable/resettable `Subnet`, `Gateway`, and `IPRange` as
      opaque physical values; verify blank-driver omission and ordered final indexed groups across
      5.4.0 through 6.0.2 without applying target resets/zipping or making runtime/cross-format claims.
- [x] Type singleton volume `Driver` and raw singleton `Options`; preserve physical source values,
      reject generated duplicates, and record the 5.8.2 quote and 6.0.0 Device-prerequisite generator
      boundaries without driver/plugin, mount, rootless, runtime, Compose, or BoxFerry policy claims.
- [x] Type opaque singleton volume `Device` and `Type`; preserve physical source values, reject
      generated duplicates, and record final blank suppression, Type-without-Device rejection, the
      existing 5.8.2 unmatched-quote boundary, and Type=bind dependency-presentation bands without
      source-path, filesystem, mount, runtime, Compose, or BoxFerry equivalence claims.
- [x] Type repeatable/resettable volume `Label`; preserve every physical source value and record
      reset, duplicate collapse, key sorting, quoted-whitespace presentation, and the bare-token
      boundary without importing generator semantics into the model or builder.
- `[Image]`: all current keys are typed. `Image` is required; credentials and decryption material
  are redacted from repository-owned debug output; opaque values retain their exact physical text.
- [x] Type and generator-verify container DNS, exposed-port, and annotation keys across the
      reviewed Podman range.
- [x] Type and generator-verify AppArmor, no-new-privileges, seccomp, and SELinux-label keys.
- [x] Type and generator-verify repeatable Mask and Unmask values with reset evidence.
- [x] Complete typed Container construction for configuration/global arguments, health logging,
      health-failure/startup controls, service naming, and UID/GID maps; preserve raw values and
      record finite capability/generator evidence without runtime interpretation.
- [x] Type `ImageVolume` and `ReadOnlyTmpfs` as separate opaque Container keys. `ImageVolume`
      remains capability-unknown until immutable target evidence exists; extend `Tmpfs` only when a
      concrete target-aware option or runtime contract is defined.
- [x] Type health logging, failure actions, and the separate startup-health family without
      inferring HealthCmd coupling or health execution semantics.
- [x] Type `Mount` independently from `Volume`; retain their different grammars and defaults.

### Next 4: resource and image lifecycle units

- [x] Complete `[Volume]` typing and capability evidence.
- [x] Type all current `.image` keys; extend `.build` or `.image` only when their documented surface
      expands.
- [x] Type all `.kube` keys with required opaque `Yaml` source diagnostics and exact `.network`
      document-set references, without filesystem access, Kubernetes parsing, or kube execution claims.
- [x] Type experimental `.artifact` with required-final-source diagnostics, privacy-redacted
      credentials/key debug output, exact document-set references, and finite 5.7.0–6.0.2
      generator evidence. It remains explicitly experimental and unsupported through 5.6.2.

### Recurring version and conformance maintenance

- [x] Add a maintained versioned manual-key inventory, offline policy tests, an extraction fixture,
      and scheduled/manual-only upstream drift reporting for the current closed Quadlet key surface.
- **Recurring maintenance:** record introduction, deprecation, removal, systemd requirements, and
  known patch bugs whenever a new promoted key or upstream release changes the evidence boundary.
- **Deferred boundary:** run rootless/rootful runtime fixtures only when a concrete supported claim
  cannot be established by generator evidence; installed environments are not assumed equivalent.

## Phase 0: foundation — completed

- [x] Accept architecture and origin ADR.
- [x] Prototype and accept the systemd-style syntax representation.
- [x] Scaffold the crate, CI, lints, MSRV policy, and fixture metadata.
- [x] Establish the initial capability schema.
- [x] Define source spans and structured diagnostics.

## Phase 1: syntax and rendering — completed current scope

- [x] Parse ordered physical sections and entries with source locations.
- [x] Preserve repeated keys, comments, continuation context, line endings, and unknown lines.
- [x] Preserve current quote and newline source syntax, continuation context, and bounded
      environment/unit-list token handling. **Deferred boundary:** generic command and argument
      semantics remain demand-driven rather than a global parser commitment.
- [x] Distinguish literal paths, relative paths, and native systemd specifiers such as `%h`.
- [x] Implement deterministic canonical rendering.
- [x] Provide validated programmatic construction for the supported native document types.
- [x] Establish malformed-input, round-trip, and property tests.

## Phase 2: typed Quadlet documents — completed current scope

- [x] Implement the first shared and `.container`, `.pod`, `.network`, and `.volume` unit-specific sections.
- [x] Add conservative path and native unit-reference value forms for the first conversion.
- [x] Model `.container` relationships with `.pod`, `.network`, and `.volume` resources.
- [x] Model regular health-command and timing keys separately from startup/readiness behavior.
- [x] Model all nine reviewed generic systemd relationship/ordering directives with reset-aware
      native-reference graphs, plus container `Notify=healthy` readiness.
- [x] Build document sets and dependency graphs.
- [x] Preserve generic systemd sections, repeated entries, and unknown Quadlet keys.

## Phase 3: Podman 5.4 minimum through rolling current — completed current range

- [x] Establish the initial capability catalogue for Podman 5.4.
- [x] Run the first-conversion fixture against every official image from Podman 5.4.0 through 5.8.2.
- [x] Build and run exact generators for Podman 5.8.3 through current 6.0.2.
- [x] Type the complete current documented native key inventory.
- **Demand-driven admission rule:** add value-form validation, fallbacks, or new limitations only
  when a concrete consumer and immutable evidence define an exact contract; otherwise retain the
  raw source-preserving boundary.
- [x] Cover path handling, pod membership, resource references, regular health commands/timings, restart behavior, and fallback arguments.
- **Deferred boundary:** rootless/rootful runtime validation is added only for an explicit runtime
  claim that generator output cannot prove.

## Phase 4: version expansion — recurring maintenance

- **Recurring maintenance:** extend the finite Podman evidence range in release order, tracking
  introductions, changes, deprecations, removals, and known patch bugs.
- **Recurring maintenance:** add a systemd target check only when a reviewed Quadlet capability has
  a direct systemd-version boundary; `Upholds` 249 is complete.
- **Deferred boundary:** distribution capability overrides require a concrete supported backport
  use case and must not be inferred from the installed system.

## Phase 5: ecosystem hardening — recurring maintenance

- [x] Establish the first licensed, immutable real-world corpus across official and community evidence classes.
- **Recurring maintenance:** expand the immutable licensed corpus only when a new promoted surface
  or regression needs a representative fixture.
- [x] Establish the supported 0.1.x public API and versioned catalogue schema.
- [x] Prepare and validate compatibility documentation and the QuadletLens 0.1.0 release candidate.
- **Deferred boundary:** optional installed-generator tooling requires a concrete maintainer use
  case and must stay separate from deterministic pull-request validation.

## Maintainer-controlled 0.1.0 release operation — completed

- [x] Publish QuadletLens 0.1.0 from the reviewed clean default-branch commit using the documented
      one-time crates.io bootstrap.
- [x] Revoke the bootstrap token, configure trusted publishing, and run the protected release
      workflow from the same commit to create the tag, attestation, and GitHub release.

## Additive 0.1.1 generation boundary — completed

- [x] Add typed native document construction without exposing parser internals.
- [x] Reject wrong-section keys, duplicate singleton keys, line endings, and NUL bytes.
- [x] Preserve repeatable native and generic systemd entries deterministically.
- [x] Parse and validate every generated document before returning it.
- [x] Add consumer, document-set, rejection-path, MSRV, and documentation coverage.
- [x] Publish QuadletLens 0.1.1 through the protected trusted-publishing workflow.

Follow the exact [release process](releasing.md). BoxFerry can consume the released 0.1.1 API
without a sibling path or Git dependency.

## Additive 0.1.2 host-mapping boundary — completed

- [x] Type repeatable `AddHost` entries in `.container` and `.pod` documents.
- [x] Preserve ordinary addresses and the runtime-specific `host-gateway` value without
      normalization.
- [x] Add finite capability entries for container and pod host mappings.
- [x] Verify generated `--add-host` arguments across every Podman patch release from 5.4.0 through
      current 6.0.2.
- [x] Add release notes and validate the Rust 1.85.0 consumer boundary.
- [x] Publish QuadletLens 0.1.2 through the protected trusted-publishing workflow.

## Additive 0.1.3 regular-health boundary — completed

- [x] Type regular health interval, retries, start period, and timeout keys.
- [x] Add capability records from the Podman 5.4.0 floor through current 6.0.2.
- [x] Verify all four keys against every recorded Podman patch generator in that range.
- [x] Keep Compose `start_interval` distinct from Podman's startup-healthcheck mechanism.
- [x] Add release notes and validate the Rust 1.85.0 consumer boundary.
- [x] Publish QuadletLens 0.1.3 through the protected trusted-publishing workflow.

## Additive 0.1.4 dependency-readiness boundary — completed

- [x] Type the container `Notify` key and evidence the `healthy` readiness form.
- [x] Add typed programmatic construction for `[Unit]` `Requires`, `Wants`, and `After`.
- [x] Add separate capability records for strong, weak, and ordering dependencies.
- [x] Verify readiness and dependency fragments against every recorded Podman patch generator from
      5.4.0 through current 6.0.2.
- [x] Add release notes and validate the Rust 1.85.0 consumer boundary.
- [x] Publish QuadletLens 0.1.4 through the protected trusted-publishing workflow.

## Additive 0.1.5 execution-identity boundary — completed

- [x] Type container `User`, `Group`, `UserNS`, repeatable `GroupAdd`, `WorkingDir`, and `ReadOnly`.
- [x] Add capability records from the Podman 5.4.0 floor through current 6.0.2.
- [x] Verify the generated Podman arguments against every recorded patch generator in that range.
- [x] Add parser, builder, singleton/repetition, public-consumer, and documentation coverage.
- [x] Add release notes and validate the Rust 1.85.0 consumer boundary.
- [x] Publish QuadletLens 0.1.5 through the protected trusted-publishing workflow.

## Additive 0.1.6 pod user-namespace and secret boundary — completed

- [x] Type singleton pod `UserNS` parsing and programmatic construction.
- [x] Add a separate `quadlet.pod.userns` capability record from Podman 5.4.0 through 6.0.2.
- [x] Verify a pod-specific `--userns auto:size=8192` fragment at the support floor, image
      boundary, and current ceiling.
- [x] Add parser, builder, duplicate-singleton, catalogue, and public-consumer coverage.
- [x] Type repeatable container `Secret` parsing and programmatic construction.
- [x] Add `quadlet.container.secret` capability evidence for mounted-file and environment-variable
      option forms from Podman 5.4.0 through 6.0.2.
- [x] Verify both secret forms in the complete real-generator matrix.
- [x] Run the complete 20-patch generator matrix.
- [x] Add release notes and validate the Rust 1.85.0 consumer boundary.
- [x] Publish QuadletLens 0.1.6 through the protected trusted-publishing workflow.

## Additive 0.1.7 container-label boundary — completed

- [x] Type repeatable container `Label` parsing and programmatic construction.
- [x] Add `quadlet.container.label` capability evidence from Podman 5.4.0 through 6.0.2.
- [x] Verify repeated native label arguments in the complete 20-patch generator matrix.
- [x] Append the public key-enum variant without changing published discriminants.
- [x] Add parser, builder, catalogue, public-consumer, and documentation coverage.
- [x] Add release notes and validate the Rust 1.85.0 consumer boundary.
- [x] Publish QuadletLens 0.1.7 through the protected trusted-publishing workflow.

## Additive 0.1.8 real-world corpus and rootfs boundary — completed

- [x] Establish the first license-reviewed, immutable real-world Quadlet corpus.
- [x] Parse and construct `Rootfs` as the mutually exclusive alternative to `Image`.
- [x] Add explicit missing, empty, and conflicting workload-source diagnostics.
- [x] Add `quadlet.container.rootfs` capability evidence from Podman 5.4.0 through 6.0.2.
- [x] Verify `--rootfs` output in the complete 20-patch generator matrix.
- [x] Preserve every published public key-enum discriminant.
- [x] Validate the patch API, Rust 1.85.0 consumer, package, documentation, dependency-policy,
      complete generator-matrix, and real-world-corpus gates.
- [x] Publish QuadletLens 0.1.8 through the protected trusted-publishing workflow.

## Additive 0.1.9 explicit-container-name boundary — completed

- [x] Type singleton `ContainerName` parsing and programmatic construction.
- [x] Add `quadlet.container.container-name` capability evidence from Podman 5.4.0 through 6.0.2.
- [x] Verify exact `--name` output at the support floor, image boundary, and current ceiling.
- [x] Append the public key-enum variant without changing published discriminants.
- [x] Add parser, builder, catalogue, public-consumer, and documentation coverage.
- [x] Run the complete 20-patch generator matrix, real-world corpus, patch API, Rust 1.85.0,
      package, documentation, and dependency-policy release gates.
- [x] Publish QuadletLens 0.1.9 through the protected trusted-publishing workflow.

## Issue-derived evidence

The dated [Podlet regression map](research/podlet-regressions-2026-08-01.md) records concrete
syntax, document-set, capability, and generator cases behind these tasks. Issue closure is not
compatibility evidence; exact Podman/systemd documentation and observations remain required.