Skip to content

fix: TTF font + last_page→feed propagation (Phase 1i smoke-test live-bugs)#100

Merged
strausmann merged 3 commits into
mainfrom
fix/font-and-last-page-feed
Jun 4, 2026
Merged

fix: TTF font + last_page→feed propagation (Phase 1i smoke-test live-bugs)#100
strausmann merged 3 commits into
mainfrom
fix/font-and-last-page-feed

Conversation

@strausmann

Copy link
Copy Markdown
Owner

Bug 1: font_size wird ignoriert

Symptom (Live): Templates mit unterschiedlichen font_size rendern visuell identisch große Texte.

Root Cause: Container hat keine TrueType-Fonts installiert. ImageFont.truetype('DejaVuSans.ttf', N) schlägt fehl mit OSError('cannot open resource'). _load_font_cached fällt auf ImageFont.load_default() zurück — Pillow's Default ist eine fixe-Größe Bitmap-Font die das size-Argument ignoriert.

Fix: fonts-dejavu-core apt-Paket in der runtime-Stage des Dockerfiles installieren → /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf verfügbar, Pillow findet es via Pfad-Suche.

Test: test_label_renderer_uses_truetype_font verifiziert FreeTypeFont-Typ und tatsächliche Größenskalierung (Glyphe bei size=22 muss >1.5x größer sein als bei size=10).


Bug 2: last_page wird weggeworfen → 22.5mm Pre-Roll überall

Symptom (Live): Multi-Label-Batch mit half_cut=True erzeugt 22.5mm Tape-Vorlauf vor jedem Label statt ~5mm Half-Cut (wie Brother iOS App).

Root Cause: ptouch-py 1.1.0 LabelPrinter.print() hat einen feed: bool = True Parameter der den Tape-Feed nach dem Print steuert. _ptouch_print in ptouch_backend.py akzeptierte last_page nicht und übergab kein feed an die ptouch-Lib → Default feed=True → voller Pre-Roll für JEDES Item im Batch.

batch_dispatch.py berechnete use_last_page korrekt (False für alle außer letztem Item), aber der Wert verschwand in PTouchBackend.print_image mit # noqa: ARG002 (unused arg) Marker.

Fix:

  • _ptouch_print Signature: last_page: bool = True Parameter hinzugefügt
  • _ptouch_print Body: printer.print(..., feed=last_page) übergeben
  • PTouchBackend.print_image: # noqa: ARG002 entfernt, last_page=last_page durchgereicht
  • TypeError-Fallback (ältere ptouch-Lib): unverändert

last_page=False (Intermediate-Item) → feed=False → ~5mm Half-Cut Trennung
last_page=True (Last-Item/Default) → feed=True → voller Tape-Feed für Trennung


Tests

  • +1 test_label_renderer_uses_truetype_font — verifiziert FreeTypeFont + Skalierung
  • +3 test_print_image_passes_last_page_false_to_ptouch, test_ptouch_print_calls_printer_with_feed_false, test_ptouch_print_calls_printer_with_feed_true_by_default
  • 3 bestehende fake_print-Stubs um last_page-Parameter erweitert (hatten keinen Platz für das neue kwarg)

Gesamt: 949 passed (Baseline 945, +4 neue Tests), 5 skipped, ruff + mypy clean.

Refs Phase 1i live smoke-test bugs.

…ored)

Container fehlte fonts-dejavu-core → ImageFont.truetype('DejaVuSans.ttf', N)
schlug mit OSError fehl → _load_font_cached fiel auf load_default() zurück.
Pillow's load_default() ist eine fixe-Größe Bitmap-Font die den size-Parameter
ignoriert — alle Templates renderten identisch große Texte unabhängig von font_size.

Fix: fonts-dejavu-core apt-Paket in runtime-Stage installieren.
Pillow findet /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf via Pfad-Suche.

Test: test_label_renderer_uses_truetype_font verifiziert FreeTypeFont-Typ und
tatsächliche Größenskalierung (h22 > h10 * 1.5x).

Refs Phase 1i smoke-test live-bugs.
…etween batch items)

batch_dispatch berechnete use_last_page=False für Intermediate-Items korrekt,
aber der Wert verschwand in PTouchBackend.print_image mit # noqa: ARG002.
_ptouch_print hatte keinen last_page-Parameter und übergab kein feed= an
ptouch-py → Default feed=True → 22.5mm Pre-Roll vor jedem Batch-Item statt
~5mm Halbschnitt (wie Brother iOS App).

Fix:
- _ptouch_print: last_page: bool = True Parameter hinzugefügt
- _ptouch_print: printer.print(..., feed=last_page) übergeben
- PTouchBackend.print_image: # noqa: ARG002 entfernt, last_page=last_page durchgereicht
- TypeError-Fallback (ältere ptouch-Lib ohne half_cut/feed): unverändert

last_page=False (Intermediate) → feed=False → ~5mm Half-Cut Separation
last_page=True  (Last/Default)  → feed=True  → voller Tape-Feed

Tests: 3 neue Tests verifizieren Propagation auf beiden Ebenen (print_image +
_ptouch_print direkt). 3 bestehende fake_print-Stubs um last_page-Parameter erweitert.

Refs Phase 1i smoke-test live-bugs.
Copilot AI review requested due to automatic review settings June 4, 2026 15:06
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses two critical bugs identified during live smoke testing. The first fix ensures consistent text rendering by providing the necessary TrueType font files in the container environment. The second fix resolves an issue where tape was being wasted due to incorrect feed settings in multi-label batches, by properly passing the 'last_page' status to the underlying printer driver.

Highlights

  • Font Rendering Fix: Installed 'fonts-dejavu-core' in the Dockerfile to ensure TrueType fonts are available for Pillow, preventing a fallback to bitmap fonts that ignored font size settings.
  • Tape Feed Propagation: Correctly propagated the 'last_page' parameter through the PTouch backend to the printer library, ensuring that intermediate labels in a batch use minimal tape feed (~5mm) instead of a full pre-roll (~22.5mm).
  • Regression Testing: Added comprehensive unit tests to verify font scaling behavior and correct feed parameter propagation to the printer backend.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request installs the fonts-dejavu-core package in the Dockerfile to ensure that DejaVuSans.ttf is available, preventing Pillow from falling back to a fixed-size bitmap font. It also introduces a last_page parameter to the ptouch backend to control tape feed during batch printing, and adds corresponding unit tests. The feedback suggests skipping the new font-scaling test on local developer machines if the font is not installed system-wide, ensuring the local TDD workflow is not disrupted outside of Docker.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +194 to +205
from app.services.label_renderer import _load_font_cached
from PIL import ImageFont

# Cache leeren damit der Test sauber von Null startet
_load_font_cached.cache_clear()

font = _load_font_cached(22)
assert isinstance(font, ImageFont.FreeTypeFont), (
f"Erwartet FreeTypeFont (TTF), bekommen {type(font).__name__}. "
"Stelle sicher dass fonts-dejavu-core im Dockerfile installiert ist "
"(/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf muss existieren)."
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Der Test test_label_renderer_uses_truetype_font schlägt auf Entwickler-Rechnern (z. B. macOS/Windows) fehl, wenn die Schriftart DejaVuSans.ttf nicht systemweit installiert ist. Dies beeinträchtigt den lokalen TDD-Workflow außerhalb von Docker.

Um dies zu beheben, ohne die Validierung in der CI/Docker-Umgebung zu schwächen, können wir den Test überspringen (pytest.skip), falls die Schriftart fehlt, wir uns aber nicht in einer CI- oder Container-Umgebung befinden.

Suggested change
from app.services.label_renderer import _load_font_cached
from PIL import ImageFont
# Cache leeren damit der Test sauber von Null startet
_load_font_cached.cache_clear()
font = _load_font_cached(22)
assert isinstance(font, ImageFont.FreeTypeFont), (
f"Erwartet FreeTypeFont (TTF), bekommen {type(font).__name__}. "
"Stelle sicher dass fonts-dejavu-core im Dockerfile installiert ist "
"(/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf muss existieren)."
)
from app.services.label_renderer import _load_font_cached
from PIL import ImageFont
import os
# Cache leeren damit der Test sauber von Null startet
_load_font_cached.cache_clear()
font = _load_font_cached(22)
if not isinstance(font, ImageFont.FreeTypeFont):
is_ci_or_docker = os.path.exists("/.dockerenv") or os.environ.get("CI") == "true"
if not is_ci_or_docker:
pytest.skip("DejaVuSans.ttf ist lokal nicht verfügbar (außerhalb von Docker/CI übersprungen)")
assert isinstance(font, ImageFont.FreeTypeFont), (
f"Erwartet FreeTypeFont (TTF), bekommen {type(font).__name__}. "
"Stelle sicher dass fonts-dejavu-core im Dockerfile installiert ist "
"(/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf muss existieren)."
)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes two live “Phase 1i” regressions in the backend: (1) Pillow was silently falling back to a fixed-size bitmap font in containers (ignoring font_size), and (2) last_page was not propagated to the ptouch library, causing unintended full tape feed between batch items.

Changes:

  • Install fonts-dejavu-core in the backend runtime Docker image so ImageFont.truetype("DejaVuSans.ttf", size) succeeds and font_size actually scales.
  • Propagate last_page through PTouchBackend.print_image_ptouch_print and map it to ptouch.LabelPrinter.print(feed=last_page).
  • Add unit tests covering TrueType usage/scaling and last_pagefeed forwarding behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
backend/tests/unit/services/test_label_renderer.py Adds a unit test ensuring a real TTF font is used and font_size affects glyph size.
backend/tests/unit/printer_backends/test_ptouch_backend.py Updates existing stubs and adds tests verifying last_page is forwarded and translated to feed.
backend/Dockerfile Installs fonts-dejavu-core in runtime stage to make DejaVuSans.ttf available in containers.
backend/app/printer_backends/ptouch_backend.py Adds last_page parameter to _ptouch_print and forwards it from print_image to ptouch as feed.

Comment on lines +191 to +192
Dieser Test schlägt im Container FEHL bis Dockerfile gefixt ist.
Auf Dev-Rechnern mit installierten Fonts läuft er grün.
)
except TypeError:
# Older ptouch lib doesn't support half_cut — fall back to full cut
# Older ptouch lib doesn't support half_cut/feed — fall back to full cut
@codecov

codecov Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.52%. Comparing base (8df1be3) to head (9507432).
⚠️ Report is 4 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #100      +/-   ##
==========================================
- Coverage   89.57%   89.52%   -0.05%     
==========================================
  Files          95       95              
  Lines        4316     4316              
  Branches      368      368              
==========================================
- Hits         3866     3864       -2     
- Misses        357      360       +3     
+ Partials       93       92       -1     
Components Coverage Δ
Printer Backends (transport) 87.18% <ø> (ø)
Printer Models (drivers) 83.42% <ø> (ø)
Services 91.09% <ø> (-0.08%) ⬇️
REST API 85.02% <ø> (ø)
Pydantic Schemas 100.00% <ø> (ø)
Integration Plugins 100.00% <ø> (ø)
Files with missing lines Coverage Δ
backend/app/printer_backends/ptouch_backend.py 96.82% <ø> (ø)

... and 3 files with indirect coverage changes

Flag Coverage Δ
backend 89.52% <ø> (-0.05%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8df1be3...9507432. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- test_label_renderer.py: pytest.skip wenn DejaVuSans nicht system-installiert
  UND nicht in CI/Container (Gemini medium-priority — lokaler TDD-Workflow
  auf macOS/Windows nicht stoeren). Path(...).exists() statt os.path.exists.
- test_label_renderer.py: Docstring aktualisiert — Dockerfile-Fix ist im PR
  bereits drin, also nicht mehr 'failt im Container' sondern Erklaerung warum
  CI/Container der Test-Pflicht-Pfad ist (Copilot)
- ptouch_backend.py: TypeError-Fallback-Kommentar erweitert um feed/last_page
  Verhalten bei Legacy-ptouch <1.1 (Copilot)

Refs PR #100 review-followup
@strausmann
strausmann merged commit 3998575 into main Jun 4, 2026
17 checks passed
@strausmann
strausmann deleted the fix/font-and-last-page-feed branch June 4, 2026 15:23
strausmann added a commit that referenced this pull request Jun 4, 2026
…forwarding (Phase 1k.2 Task 6)

Bug discovered during Phase 1k.2 plan-writing: _PTPQueuePrinter.print_image
forwarded only auto_cut + high_resolution. half_cut und last_page wurden aus
options dict geholt aber NIE an backend.print_image() weitergeleitet. PR #100
fix landete nie bei ptouch lib.

Fix: explicit options.pop für half_cut + last_page. Plus neue print_images()
Adapter-Methode für Queue-BatchJob-Pfad.

Refs #102, regression-fixes PR #100 (silent drop in adapter layer)
strausmann added a commit that referenced this pull request Jun 5, 2026
Closes #102.

Multi-Label-Batches an PT-Series Drucker produzieren 5mm Half-Cut zwischen Labels via ptouch.print_multi statt 22.5mm Pre-Roll pro Item. Brother iOS App Verhalten.

## Architektur

- BackendRouter + per-slug PrintService (Phase 1i) bleibt
- Neue PrinterBackend.print_images Protocol-Methode
- PTouchBackend.print_images via ptouch.LabelPrinter.print_multi (atomic)
- BrotherQLBackend/MockBackend via default_print_images_loop (best-effort)
- PrintQueue.BatchJob als neuer Queue-Item-Typ
- Worker dispatched via isinstance, _process_batch ist atomic + state-consistent
- batch_dispatch refactor: ONE BatchJob statt N PrintJobs

## Bonus Bug-Fix

_PTPQueuePrinter Adapter droppte half_cut + last_page bei PR #100 — die Lib bekam den Fix nie. Task 6 fixt das mit Regression-Test.

## Reviews adressiert

- Gemini R1: 3 architektur-Lücken (in-memory Job-Registrierung, JobStateMachine + SSE, parallele Renders)
- Copilot R1: 9 design/quality findings (Protocol-Approach, Scope, Privacy, atomic docstring, PrinterError-Konsistenz, public API)
- Gemini R2: 3 runtime-bugs (lookup_ql, active_jobs alignment, DbJob signature)

## Stats

- 981 passed, 5 skipped (+32 net new tests)
- 0 regressions
- 80.04% diff coverage (codecov target met)
- Privacy/lint/mypy clean

Refs Phase 1k Umbrella #101, Phase 1k.1 Layout-Engine #103, Phase 1k.3 Editor #104</commit_message>
</invoke>
github-actions Bot pushed a commit that referenced this pull request Jun 5, 2026
## 0.9.0 (2026-06-05)

* feat: Phase 1i — Label-Quality + Multi-Printer + Samla + Preview (#98) ([a33dda9](a33dda9)), closes [#98](#98)
* feat: Phase 1k.2 Multi-Label-Batch via ptouch.print_multi (#106) ([a9726a9](a9726a9)), closes [#106](#106) [#101](#101) [#103](#103)
* feat(api): GET /api/templates/{key}/preview-svg + Dashboard-Modal (Phase 1i D) ([c2cbf3c](c2cbf3c))
* feat(api): GET /api/templates/{key}/preview.png (Diagnose-Tool, Phase 1i A) ([27dd325](27dd325)), closes [#5](#5)
* feat(batch): dispatch_batch refactor to atomic BatchJob + submit_batch_job (Phase 1k.2 Task 9) ([a2b6a98](a2b6a98)), closes [#102](#102) [#106](#106)
* feat(batch): printer_slug + half_cut_override + BackendRouter-Lookup (Phase 1i C) ([0561504](0561504)), closes [#6](#6)
* feat(brother_ql): print_images via default_print_images_loop (Phase 1k.2 Task 4) ([f56e44c](f56e44c)), closes [#102](#102)
* feat(config): Clean-Break Settings + upsert_runtime_printers (Phase 1i H CA-1 7a) ([64c38b3](64c38b3))
* feat(lifespan): Multi-Printer-Wiring + service_for pro Drucker (Phase 1i H CA-1 7b) ([3661a4e](3661a4e))
* feat(mock): MockBackend.print_images via default_print_images_loop (Phase 1k.2 Task 5) ([4ebdbee](4ebdbee)), closes [#102](#102)
* feat(printer_backends): BrotherQLBackend + QLSeriesModel (Phase 1i G) ([ad52009](ad52009))
* feat(printer_backends): default_print_images_loop helper (Phase 1k.2 Task 1) ([54e1123](54e1123)), closes [#102](#102)
* feat(printer_backends): half_cut Parameter + half_cut_supported Capability (Phase 1i C) ([d41c246](d41c246))
* feat(printer_backends): PrinterBackend.print_images Protocol method (Phase 1k.2 Task 2) ([e93f945](e93f945)), closes [#102](#102)
* feat(pt): _PTPQueuePrinter.print_images + bug-fix half_cut/last_page forwarding (Phase 1k.2 Task 6) ([15ef310](15ef310)), closes [#100](#100) [#100](#100)
* feat(ptouch): print_images via ptouch.print_multi (Phase 1k.2 Task 3) ([c0d15f0](c0d15f0)), closes [#102](#102)
* feat(ql): _QLQueuePrinter.print_images adapter (Phase 1k.2 Task 7) ([cb1e317](cb1e317)), closes [#102](#102) [#106](#106)
* feat(queue): BatchJob + enqueue_batch + worker isinstance dispatch (Phase 1k.2 Task 8) ([c08da56](c08da56)), closes [#102](#102) [#106](#106)
* feat(schemas): PrinterYAMLConfig + PrintersFile (Phase 1i H) ([7779a94](7779a94))
* feat(scripts): smoke_first_print_batch.py — manual 4-item batch hardware-smoke (Phase 1k.2 Task 12) ([d2ce28e](d2ce28e)), closes [#102](#102)
* feat(services): BackendRouter mit slug->Backend-Mapping (Phase 1i H CA-2) ([a735a34](a735a34))
* feat(services): PrinterConfigLoader + printers.yaml.example (Phase 1i H) ([f065575](f065575))
* feat(templates): DPI-Fix + Samla-Templates (Phase 1i B) ([af7bce8](af7bce8))
* test(batch): end-to-end multi-label batch integration test (Phase 1k.2 Task 11) ([bcc1d04](bcc1d04)), closes [#102](#102)
* test(queue): coverage for _process_batch error paths + pragma on _ptouch_print_multi (Phase 1k.2 Tas ([0b6250d](0b6250d)), closes [#106](#106) [#102](#102)
* style: ruff format + lint cleanup (Phase 1i) ([6cffe4c](6cffe4c))
* style: ruff format Task 11 integration test (Phase 1k.2 cleanup) ([ad47f7e](ad47f7e)), closes [#102](#102)
* fix: TTF font + last_page→feed (Phase 1i smoke-test bugs) (#100) ([3998575](3998575)), closes [#100](#100)
* fix(api): preview-png statt preview.png (OpenAPI kebab-Konvention) ([b420722](b420722))
* fix(ci): mypy types + privacy scan (Phase 1i) ([541502e](541502e))
* fix(ci): SnmpQueryError __all__ export + privacy test IP ([99c1946](99c1946)), closes [#98](#98) [#98](#98)
* fix(ci): UUID-Continuity-Runbook entfernen (privacy) ([b027cff](b027cff))
* fix(lifespan): col() for mypy-safe SQLModel where-clause in slug collision check ([6f9d840](6f9d840)), closes [#98](#98)
* fix(lifespan): session.flush() + slug-collision-detection in upsert_runtime_printers ([e7d81e6](e7d81e6)), closes [#98](#98)
* fix(print_service): forward auto_cut/high_resolution from request options (Phase 1k.2 Task 9 follow- ([51539b5](51539b5)), closes [#102](#102)
* fix(printer_backends): BrotherQLBackend.preflight_check (Phase 1i Task 8b) ([dba9b6c](dba9b6c))
* fix(printer_backends): print_images stubs to fix Protocol isinstance regressions (Phase 1k.2 Task 2  ([5cbf955](5cbf955)), closes [#102](#102)
* fix(ptouch): propagate last_page→feed to ptouch lib (short half-cut between batch items) ([05f780d](05f780d))
* fix(queue): align image payloads with active_jobs + strengthen Task 8 tests (Phase 1k.2 Task 8 follo ([c658e87](c658e87)), closes [#102](#102) [#106](#106)
* fix(renderer): install fonts-dejavu-core in Dockerfile (font_size honored) ([9b0cd84](9b0cd84))
* fix(reviews): adresse Gemini + Copilot PR #100 findings ([9507432](9507432)), closes [#100](#100) [#100](#100)
* fix(schemas): half_cut_override docstring matches actual force-to-false behavior ([a7b84b9](a7b84b9)), closes [#98](#98)
* docs: pydantic-settings honesty + DPI-decouple + openapi range + preview-png drift ([3d8857e](3d8857e)), closes [PR#98-Copilot](https://github.com/PR/issues/98-Copilot) [PR#98-Copilot](https://github.com/PR/issues/98-Copilot) [PR#98-Copilot](https://github.com/PR/issues/98-Copilot) [PR#98-Copilot](https://github.com/PR/issues/98-Copilot) [#98](#98)
* docs(plan): adresse Gemini Round-2 Review G-R2-1/2/3 (PR #106) ([968b693](968b693)), closes [#106](#106) [#102](#102) [#106](#106)
* docs(plan): adresse Gemini-Review G1+G2+G3 (PR #106) ([ad3aec5](ad3aec5)), closes [#106](#106) [#102](#102) [#106](#106)
* docs(plan): Phase 1k.2 Multi-Label-Batch implementation plan (#102) ([8917d0e](8917d0e)), closes [#102](#102) [#100](#100) [#102](#102)
* docs(research): PT-P750W Layout-Diagnose Befund (Phase 1i A) ([06e8fa9](06e8fa9))
* docs(runbook): UUID-Continuity-Check Phase 1i (MA-2-Fix) ([0ef3861](0ef3861))
* docs(spec): Phase 1k.2 Multi-Label-Batch via ptouch.print_multi (#102) ([96e53c9](96e53c9)), closes [#102](#102) [#101](#101) [#102](#102) [#103](#103) [#102](#102)
* docs(spec+plan): adresse Copilot-Review C1-C9 + Privacy-Fixes (PR #106) ([4f56a2a](4f56a2a)), closes [#106](#106) [#102](#102) [#106](#106)
* Merge pull request #99 from strausmann/fix/phase1i-ql-preflight-check ([8df1be3](8df1be3)), closes [#99](#99)

[skip ci]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants