# PDDOPTIONS — Print options research summary

**Last updated:** 2026-11-11
**Scope:** duplex, paper size and color for the PaperCut Mobility Print queue
behind the local IPP relay (`ipp_relay.py`); CUPS/PPD option mapping; the
Konica Minolta C451i PPD/filter; implemented tools and what has actually been
tested.

> This document is a continuation note, not a protocol reference. It contains
> no tokens, JWTs or queue secrets. Capture-specific names/IPs are the same
> placeholders used in `README.md` and `PROTOCOL2.txt`.

---

## 1. Environment and starting point

| Item | Value |
|---|---|
| CUPS | 2.4.10 (Debian 13) |
| Queue | `PaperCut-FollowMe` (local CUPS queue) |
| Local relay | `ipp_relay.py`, `127.0.0.1:9123` by default |
| Relay config | YAML from `acquire_queue_info.py` (`printer_jwt`, `ipp_endpoint`, `printer_uri`, `queue_url`) |
| Upstream queue | Mobility Print at `172.25.1.14:9164` (capture; actual may differ) |
| Generic PPD | `Follow-Me.ppd` from the server driver zip |
| Vendor PPDs | `KMbeuC750iux.ppd`, `KMbeuC751iux.ppd` |
| Vendor filter | `KMbeuEmpPS.pl` |
| Queue device URI | `ipp://127.0.0.1:9123/...` (stock `ipp` backend), or `papercut-relay:/` when using the mapping backend |

The capture advertised `application/pdf` and `image/urf` for the Mobility
Print queue and a `media-col-supported` collection containing 45 media sizes,
including A3 as `29700 x 42000` (hundredths of a millimetre). It advertised
`print-color-mode-supported: color, monochrome`.

**Important:** the capture's `Get-Printer-Attributes` request asked for
`media-col-supported` and `print-color-mode-supported`, but **not**
`media-supported` or `sides-supported`. The absence of those names in the
captured response does **not** prove the server lacks them.

---

## 2. Root cause: why CUPS/UI PPD options did not reach Mobility Print

With CUPS 2.4.10, the stock `ipp` backend normally converts PPD options to IPP
attributes through `_cupsConvertOptions()` in `cups/ppd-cache.c`. It only does
that when it can build the PPD cache, which requires `media_col_sup` to be
found by:

```c
media_col_sup = ippFindAttribute(supported, "media-col-supported",
                                 IPP_TAG_KEYWORD);
```

The Mobility Print server sends `media-col-supported` as a **collection**.
That lookup does not match, `media_col_sup` is NULL, the PPD cache path is
skipped, and the backend takes the fallback path: it sends the PPD option names
verbatim (`ColorModel`, `PageSize`, `Duplex`, ...). Mobility Print ignores
those, so the printer uses its defaults.

This explains the observed behaviour exactly:

| Supplied as | What CUPS sends | Result |
|---|---|---|
| `-o print-color-mode=color` | `print-color-mode=color` (keyword) | works (confirmed); the queue default is monochrome, so this is required for color (2026-11-11) |
| `-o sides=two-sided-long-edge` | `sides=two-sided-long-edge` (keyword) | works (confirmed 2026-11-11); the queue default is one-sided, so this is required for duplex |
| `-o media=iso_a3` | `media=iso_a3` (keyword) | A3 **not** selected on the release display (2026-11-11); either CUPS drops the PWG name or the server ignores it |
| `-o media=iso_a3_297x420mm` | `media=iso_a3_297x420mm` (keyword) | A3 **not** selected (2026-11-11) |
| `-o media=A3` | `media=A3` (keyword) | A3 **selected** (2026-11-11); this instance honours the non-standard name |
| `-o 'media-col={media-size={x-dimension=29700 y-dimension=42000}}'` | a real `media-col` collection | A3 **selected** (2026-11-11); collection encoded correctly |
| `-o ColorModel=RGB` | `ColorModel=RGB` (`nameWithoutLanguage`) | ignored |
| `-o PageSize=A3` | `PageSize=A3` (`nameWithoutLanguage`) | ignored |
| `-o Duplex=DuplexNoTumble` | `Duplex=DuplexNoTumble` | ignored |

The vendor PPD's `SelectColor`/`KMDuplex` names have the same problem on the
IPP path: they are PPD names, not IPP attributes.

### Side note: why `make_relay_ppd.py` sets a new PPD nickname

`cupstestppd` rejects `(` in `*ModelName`; the generator therefore uses
`*ModelName: "KONICA MINOLTA C451iSeriesPS/P"` and puts the "relay" suffix in
`*NickName`, not `*ModelName`.

---

## 3. The two vendor PPDs and the KM filter

Both PPDs are multi-model PostScript/PJL drivers. They contain:

```
*OpenUI *Model/Model: PickOne
*DefaultModel: C750i          # C751i PPD: C751i
*Model C451i/C451i:  ""
...
*UIConstraints: ... *Model C451i
*cupsFilter: "application/vnd.cups-postscript 0 KMbeuEmpPS.pl"
```

So the 451i is a selectable `*Model` choice in **both** PPDs; the default is
not C451i. For a C451i, set `Model=C451i`.

### 3.1 Which PPD for a C451i?

`KMbeuC750iux.ppd` is the better base:

| | C750i PPD | C751i PPD |
|---|---|---|
| Revision | BEU **v1.2** | BEU v1.0 |
| Default model | C750i | C751i |
| Models added | C750i/C650i/C550i/C450i… | adds C751i/C651i/C551i |
| Page sizes | 52; A3 = 842×1191 pt | identical |
| `SelectColor` | Auto/Color/Grayscale | identical |
| `KMDuplex` | 1Sided/2Sided | identical |
| C451i-specific accessory exclusions | FS-536 and PK-520 excluded | PFP13T234 excluded; FS-542/PK-527 **not** excluded |
| Extra accessories | FS-536, PK-520, PFP13T2/23 | FS-542, PK-527, PFP13T234 |

For C451i color/A3/duplex the PPDs are functionally identical. The C750i PPD
is the later revision and has the more careful C451i accessory constraints.
Use the C751i PPD only for a C751i/C651i/C551i.

### 3.2 What `KMbeuEmpPS.pl` actually does with options

The filter (v2.5, 2016) parses only **KM job-control** options, primarily from
`$ARGV[4]` (CUPS `argv[5]`, the options string):

- OutputMethod (Secure/Proof/Box/ID&Print/SafeQ)
- `KMSecID`, `KMSecPass`, `KMBoxNumber`, `KMBoxFileName`, `KMSafeQUser`
- `KMSectionManagement`, `KMDepCode`, `KMAccPass`
- `KMAuthentication`, `KMAuthUser`, `KMAuthPass`, `KMAuthServer`
- `KMCopySecurity*`
- `KMStamp*`, `KMStampPageNumber*`
- `KMEncryption`, `KMEncPass`
- copies from `$ARGV[3]` → `@PJL SET QTY`

It does **not** parse or rewrite `PageSize`, `PageRegion`, `PaperDimension`,
`KMDuplex`, `Duplex`, `SelectColor`, `ColorModel`, `InputSlot` or `MediaType`.
It adds a PJL header/footer (`@PJL JOB`, `@PJL ENTER LANGUAGE = POSTSCRIPT`) and
passes the input PostScript through unchanged.

Paper size, duplex and color are therefore in the PPD's PostScript
`setpagedevice` snippets, e.g.:

```
*PageSize A3: "<</PageSize[842 1191]...>>setpagedevice"
*KMDuplex 2Sided: "<< /Duplex true >> setpagedevice"
*SelectColor Color: ... /ProcessColorModel /DeviceCMYK ...
```

The `$A4Device` variable in the filter is set by `POutputMethod` and is used
for secure-print username handling; it is **not** paper-size selection.

### 3.3 Consequence: the unmodified vendor PPD can work if the upstream accepts PS/PJL

If A3 printed correctly with the unmodified vendor PPD and the KM filter, the
printer received a PJL/PostScript job and the PPD's `setpagedevice` selected
A3. The filter did not select A3; the PPD's PS did.

Whether this means the **relay/upstream** accepted PS/PJL depends on where the
test was made:

- If it was through the relay queue, check the journal:
  `document-format=application/postscript` or `application/octet-stream`,
  and `upstream result: HTTP 200 OK, IPP successful-ok`. If present, the
  unmodified vendor PPD + KM filter is the simplest path for applications and
  vendor features.
- If it was direct to the printer (not through the relay), it does not prove
  the relay accepts PS/PJL. Test one job through the relay and check the same
  log lines.

The capture only advertises `application/pdf` and `image/urf`; PS/PJL
acceptance is outside the captured protocol and may be server/version
dependent.

---

## 4. Implemented solutions

### 4.1 Manual `lp` with IPP names (works today for color, duplex and A3)

```bash
lp -d PaperCut-FollowMe \
    -o print-color-mode=color \
    -o sides=two-sided-long-edge \
    -o media=A3 \
    document.pdf
```

The standards-based alternative is the advertised media-col dimensions:

```bash
lp -d PaperCut-FollowMe \
    -o print-color-mode=color \
    -o sides=two-sided-long-edge \
    -o 'media-col={media-size={x-dimension=29700 y-dimension=42000}}' \
    document.pdf
```

- Color (`print-color-mode=color`) confirmed working.
- Duplex (`sides=...`) confirmed working.
- `media=A3` and the media-col collection confirmed to select A3 on the
  release-device display (2026-11-11, eight-job test, jobs cancelled before
  printing).
- `media=iso_a3` and `media=iso_a3_297x420mm` did **not** select A3 in that
  test, although they are the standard PWG names. The A3 test page is itself
  A3, so the document's page size does not select A3 either.
- Use the media-col collection if you want the portable, standard form;
  `media=A3` works on this instance and is shorter, but `A3` is not a PWG
  keyword. See §5.6.
- The queue default is **monochrome** (2026-11-11 color test), so color
  requires `print-color-mode=color` (or `auto`, which produced color for the
  color test page). `ColorModel=RGB/CMYK/Gray` had no effect. See §5.6.
- The queue default is **one-sided** (2026-11-11 duplex test), so duplex
  requires `sides=two-sided-long-edge` for normal duplex or
  `sides=two-sided-short-edge` for the other binding. `Duplex=...` and
  `KMDuplex=2Sided` had no effect. See §5.6.

### 4.2 `papercut_relay_backend.py` — mapping backend for CUPS UI/apps

A CUPS backend wrapper that maps PPD options to IPP names and execs the stock
`ipp` backend pointed at the relay:

| PPD option | IPP attribute |
|---|---|
| `ColorModel=RGB/CMYK/CMY` | `print-color-mode=color` |
| `ColorModel=Gray/FastGray/DeviceGray` | `print-color-mode=monochrome` |
| `SelectColor=Color` | `print-color-mode=color` |
| `SelectColor=Grayscale` | `print-color-mode=monochrome` |
| `SelectColor=Auto` | left to the printer default |
| `PageSize=A3` | `media-col` with A3 canonical dimensions |
| `PageSize=<other PPD size>` | `media-col` from `*PaperDimension` (points → 1/100 mm) |
| `PageSize=<W>x<H>mm` | `media-col` with those dimensions |
| `Duplex=None/1Sided` | `sides=one-sided` |
| `Duplex=DuplexNoTumble/2Sided` | `sides=two-sided-long-edge` |
| `Duplex=DuplexTumble` | `sides=two-sided-short-edge` |
| `KMDuplex=2Sided` + `Binding=TopBinding` | `sides=two-sided-short-edge` |

Explicit `print-color-mode`, `media`, `media-col` and `sides` are preserved and
take precedence.

The `PageSize=A3` → `media-col` mapping is the path confirmed to select A3 in
the 2026-11-11 test (§5.6). The wrapper does not rewrite explicit `media`
values: `-o media=iso_a3` is passed through and was **not** honoured by the
queue, so use `-o media=A3` or the media-col form.

The color mapping is equally needed: the 2026-11-11 color test showed the queue
defaults to monochrome and the PPD names `ColorModel=RGB`/`CMYK` do not produce
color, while `print-color-mode=color` does. The wrapper is what turns the
`ColorModel`/`SelectColor` selections from the UI into that attribute.

The duplex mapping is needed for the same reason: in the 2026-11-11 test
`Duplex=DuplexNoTumble`/`DuplexTumble`/`None` and `KMDuplex=2Sided` all left
the job one-sided, while `sides=two-sided-long-edge`/`short-edge` were
honoured. The wrapper is what turns the `Duplex`/`KMDuplex` UI selections into
`sides`.

Install and switch the queue:

```bash
sudo install -m 0755 papercut_relay_backend.py \
    /usr/lib/cups/backend/papercut-relay
sudo systemctl restart cups
sudo lpadmin -p PaperCut-FollowMe -v papercut-relay:/
```

`papercut-relay.ppd` (PASS under `cupstestppd`) is a minimal PPD for this
queue: PageSize A4/A3, ColorModel RGB/Gray, Duplex None/DuplexNoTumble,
defaults A4 / monochrome / 1-sided, PDF/URF pass-through. Install it with
`lpadmin -P /usr/share/ppd/papercut-relay.ppd` if you do not want the server
PPD's larger option set. It cannot replace the wrapper: a PPD can only name
options, and CUPS is the layer that fails to translate those names to IPP for
this server (there is no PPD directive that adds IPP attributes).

- Default relay URI: `ipp://127.0.0.1:9123/`; override with
  `PAPERCUT_RELAY_URI`.
- It sets `DEVICE_URI` itself and execs `CUPS_SERVERBIN/backend/ipp`.
- No document conversion; the PPD's filter chain still runs first.
- It can read the PPD via the `PPD` environment variable for sizes.

### 4.3 `make_relay_ppd.py` — vendor PPD variant for the PDF/IPP path

If you want the vendor C451i option set but the upstream only accepts
PDF/URF, generate a relay-compatible vendor PPD:

```bash
python3 -I make_relay_ppd.py KMbeuC750iux.ppd -o KMbeuC451i-relay.ppd
sudo install -m 0644 KMbeuC451i-relay.ppd /usr/share/ppd/
sudo lpadmin -p PaperCut-FollowMe \
    -P /usr/share/ppd/KMbeuC451i-relay.ppd \
    -v papercut-relay:/ \
    -o Model=C451i
```

The generator:

- sets `*DefaultModel: C451i`;
- replaces `*cupsFilter: "application/vnd.cups-postscript 0 KMbeuEmpPS.pl"`
  with the generic PPD's PDF/URF pass-through lines;
- rewrites `*ModelName`, `*ShortNickName`, `*NickName`, `*Product`,
  `*PCFileName` to C451i/relay metadata.

The KM filter is then out of the chain: `cupsfilter --list-filters ...`
shows `gziptoany` for PDF. The mapping backend maps `SelectColor`,
`KMDuplex` and `PageSize`. Vendor-only options (trays, media type, finishing)
remain in the UI but are not mapped to IPP; Mobility Print does not advertise
them.

Validation caveat: the vendor PPD has a pre-existing duplicate
`KMAuthentication` choice and mixed line endings; `cupstestppd` reports those,
and the generated PPD inherits them. If `lpadmin`/CUPS refuses the PPD, use
the generic PPD + mapping backend.

### 4.4 Unmodified vendor PPD + KM filter (only if the relay accepts PS/PJL)

If the A3 test was through the relay and succeeded, the simplest setup for
applications and vendor features is:

- CUPS queue with the unmodified vendor PPD (C750i PPD is preferred for a
  C451i; C751i for newer models);
- `Model=C451i`;
- device URI `ipp://127.0.0.1:9123/...` (stock `ipp` backend), no mapping
  wrapper needed;
- relay forwards the PJL/PostScript body with the JWT.

This preserves the full vendor PPD UI and KM filter features, and paper
size/duplex/color are carried by PostScript `setpagedevice`. But it is outside
the captured PDF/URF protocol; verify the relay journal and re-test after
server changes.

### 4.5 Direct vendor queue (not the relay)

For full vendor features without relying on PS/PJL acceptance by Mobility
Print, create a direct CUPS queue to the printer with the vendor PPD/filter
(IPP/socket/LPD as appropriate). This bypasses the relay, the Printer JWT and
Follow-Me accounting; it is a different architecture.

### 4.6 Scaling when the document size differs (A4 content on A3)

CUPS runs `pdftopdf` before the relay. With cups-filters 1.28.17 / CUPS 2.4.10
and the default `print-scaling=auto`, an A4 PDF sent with `media=A3` gets A3
pages but the A4 content is **centered at 100%**, not enlarged. `auto` (and
`auto-fit`) only scale *down* when the document is larger than the page; they
never enlarge a smaller document.

Measured with the A4 test page through `pdftopdf` and a PPD containing an A3
entry (the vendor C750i PPD; its A3 dimensions are the same as the generic
PPD's):

| options | output page | content |
|---|---|---|
| `media=A3` (default auto) | A3, 842 × 1191 pt | A4-size, 100%, centered |
| `media=A3 print-scaling=none` | A3 | A4-size, 100%, centered |
| `media=A3 print-scaling=auto-fit` | A3 | A4-size, 100%, centered |
| `media=A3 print-scaling=fit` (or `fit-to-page`) | A3 | scaled ~1.37× to the printable area |
| `media=A3 print-scaling=fill` | A3 | scaled to fill, cropped if the aspect differs |

```bash
# A4 content on A3: unscaled and centered
lp -d PaperCut-FollowMe -o media=A3 document.pdf

# enlarge the A4 content to fill A3
lp -d PaperCut-FollowMe -o media=A3 -o print-scaling=fit document.pdf
```

Scaling is done by the CUPS filter, so the PDF sent upstream already has A3
pages with the content placed. A direct submission (`print_pdf_jwt.py`)
bypasses the filters: the PDF keeps its A4 page size and only the requested
media changes, so the release device decides what happens.

---

## 5. What was tested, and how

### 5.1 Capture analysis

- Parsed the captured `Get-Printer-Attributes` response:
  - `media-col-supported`: 45 unique sizes; A3 = `29700 x 42000`.
  - `print-color-mode-supported`: `color`, `monochrome`.
  - `document-format-supported`: `application/pdf`, `image/urf`.
  - No `sides-supported`/`media-supported` because they were not requested.
- Extracted `Follow-Me.ppd` from the captured driver zip; checked its
  `ColorModel`, `PageSize`, `Duplex`, and pass-through filter lines.

### 5.2 Stock `ipp` backend replay

Replayed the captured capabilities to the real CUPS 2.4.10 `ipp` backend and
inspected the IPP requests it generated:

- `ColorModel=RGB PageSize=A3 Duplex=DuplexNoTumble` → literal
  `ColorModel`/`PageSize`/`Duplex` attributes; no `print-color-mode`/media-col.
- `print-color-mode=color media=iso_a3 sides=two-sided-long-edge` → the
  expected IPP attributes in the job group (the value is forwarded verbatim;
  §5.6 shows the server did not honour `iso_a3`).
- `media-col={media-size={x-dimension=29700 y-dimension=42000}}` → a correctly
  encoded collection.
- The backend's `_cupsConvertOptions` path is skipped because
  `media_col_sup` is not found (collection vs keyword tag), confirmed from the
  CUPS source and the debug output.

### 5.3 `cupsfilter`

- Generic `Follow-Me.ppd`:
  - PDF input → `gziptoany`, PDF passes through.
  - `text/plain` → `texttopdf` → PDF.
- Generated `KMbeuC451i-relay.ppd`:
  - PDF input → `gziptoany`; the KM filter is not in the chain.

### 5.4 Mapping backend tests (stub upstream)

`papercut_relay_backend.py` was run against a stub replaying the captured
`Get-Printer-Attributes` and job responses:

- Generic PPD options → `print-color-mode=color`,
  `media-col` A3 (29700×42000), `sides=two-sided-long-edge`.
- Explicit IPP options preserved; PPD names dropped.
- Missing PPD → canonical A3 / fallback media names.
- `PageSize=297x420mm` → media-col A3.
- KM `SelectColor=Grayscale KMDuplex=1Sided PageSize=A3` → monochrome,
  one-sided, A3 media-col.
- `SelectColor=Auto` left unchanged; `KMDuplex=2Sided` + `Binding=TopBinding`
  → short-edge.
- No-args mode prints a device discovery line.

### 5.5 Relay logging

`ipp_relay.py` now logs the relevant attributes at INFO:

```
IPP request: Print-Job request-id=1 media=A3 print-color-mode=color sides=two-sided-long-edge
```

For a collection it logs e.g. `media-col=297x420mm`. It also logs
`document-format` if CUPS sends it. This is the primary live diagnostic for
which path a job took and what the server received.

### 5.6 Live results

- `print-color-mode=color`: works.
- `sides=two-sided-long-edge` etc.: fixes sidedness.
- A3 printed with the **unmodified vendor PPD + KM filter**. Whether this was
  through the relay or direct to the printer is not yet confirmed; if through
  the relay, the upstream accepts PS/PJL.
- **2026-11-11 A3 option matrix** (`a3_option_tests.py`, queue
  `Papercut-Default`, default `Follow-Me.ppd`, no mapping backend; paper size
  read from the release-device display, jobs cancelled, nothing printed):

  | # | option | A3 on display |
  |---|---|---|
  | 1 | none (queue default) | no |
  | 2 | `media=iso_a3` | no |
  | 3 | `media=iso_a3_297x420mm` | no |
  | 4 | `media=A3` | **yes** |
  | 5 | `media-col={media-size={x-dimension=29700 y-dimension=42000}}` | **yes** |
  | 6 | same collection plus `media-size-name=iso_a3` | **yes** |
  | 7 | `PageSize=A3` | no |
  | 8 | `PageSize=A3` + `media=iso_a3` | no |

  Only the named value `A3` and the media-col collection selected A3; the PWG
  name forms did not, and `PageSize` is inert (tests 7–8). The source PDF is
  A3, yet test 1 came out non-A3, so the document page size is not used as the
  media. The display answers do not show whether CUPS locally discarded the PWG
  names or the server ignored them; the relay journal for those jobs (if the
  queue goes through the relay) would decide that. The raw answers are in
  `results-a3-portrait.txt`.
- **2026-11-11 color matrix** (`color_option_tests.py`, same queue and PPD,
  `media=A4` pinned on every job; paper size is not the variable; jobs
  cancelled). Answers were given as y = Color / n = Mono:

  | # | option | display |
  |---|---|---|
  | 1 | none (queue default) | mono |
  | 2 | `print-color-mode=color` | **color** |
  | 3 | `print-color-mode=auto` | **color** |
  | 4 | `print-color-mode=monochrome` | mono |
  | 5 | `ColorModel=RGB` | mono |
  | 6 | `ColorModel=CMYK` | mono |
  | 7 | `ColorModel=Gray` | mono |
  | 8 | `print-color-mode=color` + `ColorModel=Gray` | **color** |

  The queue defaults to **monochrome**. Only the standard IPP attribute selected
  color; the PPD names were inert (tests 5–7), and the IPP attribute won the
  conflict with the PPD name (test 8). `auto` produced color for this CMYK test
  page, so it follows the job content rather than forcing color. The raw
  answers are in `results-a4-color.txt` (the display fields say `unknown`
  because the script's prompt expected c/m; the notes hold the y/n answers).
- **2026-11-11 duplex matrix** (`duplex_option_tests.py`, same queue and PPD,
  `media=A4` pinned, two-page A4 source; jobs cancelled). Answers: l = long
  edge, s = short edge, 1 = one-sided:

  | # | option | display |
  |---|---|---|
  | 1 | none (queue default) | one-sided |
  | 2 | `sides=two-sided-long-edge` | **long edge** |
  | 3 | `sides=two-sided-short-edge` | **short edge** |
  | 4 | `Duplex=DuplexNoTumble` | one-sided |
  | 5 | `Duplex=DuplexTumble` | one-sided |
  | 6 | `Duplex=None` | one-sided |
  | 7 | `KMDuplex=2Sided` | one-sided |
  | 8 | `sides=two-sided-long-edge` + `Duplex=DuplexTumble` | **long edge** |

  The queue defaults to **one-sided**. Both standard `sides` values were
  honoured, the PPD/vendor names were inert (tests 4–7), and the IPP attribute
  won the conflict (test 8). Raw answers are in `results-duplex-a4.txt`.
- **2026-11-11 combined matrix** (`combined_option_tests.py`, two repeats of
  each combination): all 16 jobs matched on the display —
  A4/A3 × 1-sided/2-sided-long-edge × color/monochrome. The three attributes
  do not interfere when set together, and the explicit IPP names remain the
  right form in combination. The jobs were cancelled, so the test confirms
  queue acceptance, not the physical sheet (tray, scaling, rendering).
  Raw answers are in `results-stress-combined.txt`.

### 5.7 Not tested

- No live CUPS queue was installed for the mapping backend or the generated
  relay PPD.
- No wire-level confirmation of the A3 matrix: the 2026-11-11 answers come from
  the release-device display, and the relay journal / CUPS debug log for those
  jobs was not captured, so it is not known whether CUPS or the server
  discarded the PWG media names.
- No live test of duplex through the mapping backend.
- No live test of the unmodified vendor PPD through the relay with the
  document-format/status captured.
- The relay's PS/PJL forwarding path was not probed with the vendor filter in
  a controlled test.

---

## 6. Open questions / next steps

1. **Clarify the A3 success path.** Check
   `journalctl -u papercut-ipp-relay` for the job:
   - `IPP request: ... document-format=application/postscript` or
     `application/octet-stream`?
   - `upstream result: HTTP 200 OK, IPP successful-ok`?
   If yes, the unmodified vendor PPD + KM filter is viable through the relay.

2. **Decide the primary path:**
   - **Unmodified vendor PPD + KM filter** if the relay accepts PS/PJL:
     best UI/vendor features, no mapping backend, but outside the captured
     PDF/URF protocol.
   - **Generic PPD + mapping backend** for a standards-based PDF/IPP path.
   - **Generated relay PPD + mapping backend** for vendor options on the
     PDF/IPP path.

3. **Physical combined test.** The display-level combined matrix is done
   (§5.6): all 16 combinations matched. What remains is the physical result:
   release a job with `-o media=A3 -o print-color-mode=color
   -o sides=two-sided-long-edge` and check the sheet. Use a multi-page A3 PDF
   so duplex is meaningful, and allow for the A4-content-on-A3 scaling
   behaviour in §4.6 (unscaled and centred unless `print-scaling=fit`).

4. **Check queue defaults** (`lpoptions -p PaperCut-FollowMe -l`) for
   conflicting media/color/duplex settings. Test 1 of the A3 matrix showed the
   current default media is not A3.

5. **Check the PPD actually installed** on the queue:
   `/etc/cups/ppd/PaperCut-FollowMe.ppd`; make sure it is the server/generic
   PPD or the generated C451i relay PPD, not a raw queue.

6. **Monitor CUPS changes.** The mapping skip is a CUPS 2.4.10 behavior; a
   future CUPS that accepts the server's collection form for
   `media-col-supported` could make the wrapper unnecessary.

7. **Vendor PPD validation.** Resolve or accept the pre-existing duplicate
   `KMAuthentication` choice / mixed line endings if `lpadmin` complains.

8. **Do not use the C751i PPD for a C451i** unless the device is actually a
   C751i/C651i/C551i. For a C451i, prefer `KMbeuC750iux.ppd` as the base.

9. **Settle the PWG-name question at the wire.** If the test queue uses the
   relay, check `journalctl -u papercut-ipp-relay` around the 2026-11-11 jobs:
   if the log shows `media=iso_a3` while the display showed non-A3, the server
   ignored it; if the log shows no `media` or a substituted size, CUPS
   discarded it. This decides whether the mapping backend should also
   translate PWG media names into the media-col collection.

10. **Verify the option mapping through the backend.** The matrices used
    explicit IPP names. The CUPS UI/application path (`ColorModel`/`SelectColor`
    → `print-color-mode`, `PageSize` → `media-col`, `Duplex`/`KMDuplex` →
    `sides`) has not been live-tested: queue a color/A3/duplex job from a print
    dialog with the mapping backend installed and check the relay journal and
    the display.

---

## 7. Quick reference

### Correct IPP names

```
print-color-mode=color|monochrome
sides=one-sided|two-sided-long-edge|two-sided-short-edge
media=A3                      # honoured by this instance (tested 2026-11-11)
media-col={media-size={x-dimension=29700 y-dimension=42000}}
```

`print-color-mode=color` is required for color: the queue defaults to
monochrome (2026-11-11). `print-color-mode=auto` also produced color for the
color test page, but it follows the document content.

`sides=two-sided-long-edge` is required for normal duplex: the queue defaults
to one-sided (2026-11-11), and `Duplex`/`KMDuplex` names have no effect.

`media=iso_a3` and `media=iso_a3_297x420mm` are the standard PWG names but were
**not** honoured by this Mobility Print queue in the 2026-11-11 test.

### Do not rely on these PPD names on the IPP path

```
ColorModel=RGB
PageSize=A3
Duplex=DuplexNoTumble
SelectColor=Grayscale
KMDuplex=2Sided
```

They are either ignored or require the mapping backend/vendor filter path.

### Commands

```bash
# Manual IPP options
lp -d PaperCut-FollowMe -o print-color-mode=color \
    -o sides=two-sided-long-edge -o media=A3 document.pdf

# Mapping backend
sudo install -m 0755 papercut_relay_backend.py /usr/lib/cups/backend/papercut-relay
sudo systemctl restart cups
sudo lpadmin -p PaperCut-FollowMe -v papercut-relay:/

# Generated relay PPD (PDF/IPP path)
python3 -I make_relay_ppd.py KMbeuC750iux.ppd -o KMbeuC451i-relay.ppd
sudo install -m 0644 KMbeuC451i-relay.ppd /usr/share/ppd/
sudo lpadmin -p PaperCut-FollowMe -P /usr/share/ppd/KMbeuC451i-relay.ppd \
    -v papercut-relay:/ -o Model=C451i

# Diagnostics
journalctl -u papercut-ipp-relay -f
tail -f /var/log/cups/error_log
lpoptions -p PaperCut-FollowMe -l
cupsfilter --list-filters -p /etc/cups/ppd/PaperCut-FollowMe.ppd \
    -i application/pdf -m application/pdf test.pdf
```

---

## 8. Relevant files and docs

| File | Role |
|---|---|
| `ipp_relay.py` | Loopback IPP relay; forwards to Mobility Print with the JWT; logs options/document-format. |
| `papercut_relay_backend.py` | Maps PPD options to IPP names; execs the stock `ipp` backend; queue URI `papercut-relay:/`. |
| `papercut-relay.ppd` | Minimal PPD (A4/A3, colour/mono, 1-/2-sided) for the wrapper path; passes `cupstestppd`. |
| `lxc_papercut_backend.py` | Host CUPS backend: forwards to a CUPS queue inside an LXC container via `lxc-attach`; same PPD→IPP option mapping. |
| `make_relay_ppd.py` | Generates a C451i relay PPD from the vendor C750i/C751i PPD (KM filter removed). |
| `acquire_queue_info.py` | Writes the relay YAML (JWT, endpoint, queue URL). |
| `KMbeuC750iux.ppd` | Vendor multi-model PPD; preferred base for C451i. |
| `KMbeuC751iux.ppd` | Vendor multi-model PPD for newer C751i/C651i/C551i; also lists C451i. |
| `KMbeuEmpPS.pl` | Vendor PJL/PostScript filter; KM job control, not paper/duplex/color. |
| `README.md` | Files, quick start, relay and option notes. |
| `PROTOCOL3.md` §8.4.1–8.4.3 | CUPS filter/backend analysis, option mapping, mapping backend and vendor PPD variant. |
| `PROTOCOL2.txt` §9 | Captured static IPP attributes. |

Check `svn status` before resuming; the vendor PPDs/filter are present in the
directory but are untracked and are not part of the toolkit.
