From 8cb420107f06f389a4aabd99fddcb6d0186896ba Mon Sep 17 00:00:00 2001 From: Kawa Date: Fri, 10 Apr 2026 13:33:08 +0200 Subject: [PATCH] docs(04-01): complete script generator install plan summary - SUMMARY.md for phase 04 plan 01 (TDD install script generator) - STATE.md: progress updated to 89%, decisions recorded, session updated - ROADMAP.md: phase 4 plan progress updated (1/2 summaries) - REQUIREMENTS.md: SCRPT-01, SCRPT-04, SCRPT-05 marked complete --- .planning/REQUIREMENTS.md | 12 +- .planning/ROADMAP.md | 2 +- .planning/STATE.md | 14 ++- .../04-script-generation/04-01-SUMMARY.md | 105 ++++++++++++++++++ 4 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 .planning/phases/04-script-generation/04-01-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index f454b93..52ab084 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -30,11 +30,11 @@ Requirements for initial release. Each maps to roadmap phases. ### Script Generation -- [ ] **SCRPT-01**: System generates PowerShell install script (pnputil staging + Add-PrinterPort + Add-PrinterDriver + Add-Printer + Set-PrintConfiguration) +- [x] **SCRPT-01**: System generates PowerShell install script (pnputil staging + Add-PrinterPort + Add-PrinterDriver + Add-Printer + Set-PrintConfiguration) - [ ] **SCRPT-02**: System generates PowerShell uninstall script (Remove-Printer + Remove-PrinterDriver + Remove-PrinterPort) - [ ] **SCRPT-03**: System generates Intune detection script (registry check for printer name) -- [ ] **SCRPT-04**: Generated install script detects SYSTEM vs. user context and self-elevates via UAC when run by user -- [ ] **SCRPT-05**: Generated install script includes 64-bit WOW64 relaunch guard for Intune's 32-bit execution context +- [x] **SCRPT-04**: Generated install script detects SYSTEM vs. user context and self-elevates via UAC when run by user +- [x] **SCRPT-05**: Generated install script includes 64-bit WOW64 relaunch guard for Intune's 32-bit execution context ### Package Export @@ -100,11 +100,11 @@ Which phases cover which requirements. Updated during roadmap creation. | PRNT-08 | Phase 3 | Complete | | PRNT-09 | Phase 3 | Complete | | PRNT-10 | Phase 3 | Complete | -| SCRPT-01 | Phase 4 | Pending | +| SCRPT-01 | Phase 4 | Complete | | SCRPT-02 | Phase 4 | Pending | | SCRPT-03 | Phase 4 | Pending | -| SCRPT-04 | Phase 4 | Pending | -| SCRPT-05 | Phase 4 | Pending | +| SCRPT-04 | Phase 4 | Complete | +| SCRPT-05 | Phase 4 | Complete | | PKG-01 | Phase 5 | Pending | | PKG-02 | Phase 5 | Pending | | PKG-03 | Phase 5 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 2f70949..d5002cf 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -108,5 +108,5 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 | 1. Foundation | 3/3 | Complete | 2026-04-10 | | 2. Driver Management | 1/2 | In Progress| | | 3. Printer Configuration | 2/2 | Complete | 2026-04-10 | -| 4. Script Generation | 0/2 | Not started | - | +| 4. Script Generation | 1/2 | In Progress| | | 5. Package Export | 0/3 | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 087bd15..670b242 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: executing -stopped_at: Completed 03-02-PLAN.md -last_updated: "2026-04-10T11:14:33.220Z" +stopped_at: Completed 04-01-PLAN.md +last_updated: "2026-04-10T11:32:55.889Z" last_activity: "2026-04-10 — Plan 01-01 complete: Docker scaffold, FastAPI app shell, sidebar templates, 3-test green suite" progress: total_phases: 5 completed_phases: 3 - total_plans: 7 - completed_plans: 7 + total_plans: 9 + completed_plans: 8 percent: 7 --- @@ -55,6 +55,7 @@ Progress: [░░░░░░░░░░] 7% | Phase 02-driver-management P02-02 | 3 | 2 tasks | 7 files | | Phase 03-printer-configuration P01 | 7 | 2 tasks | 12 files | | Phase 03-printer-configuration P02 | 2 | 2 tasks | 4 files | +| Phase 04-script-generation P01 | 2 | 1 tasks | 3 files | ## Accumulated Context @@ -83,6 +84,7 @@ Recent decisions affecting current work: - [Phase 03-printer-configuration]: Alpine.js portEdited guard prevents port overwrite after manual edit (PRNT-03) - [Phase 03-02]: Detail page is a full-page template (not partial) — simpler than partial injection into printers.html - [Phase 03-02]: Route lives in pages.py (not printers.py) because it returns a full HTML page, not an HTMX fragment +- [Phase 04-script-generation]: render_install() takes plain string args (not ORM object) for DB-free unit testability; _duplex_map translates LongEdge->TwoSidedLongEdge before template rendering ### Pending Todos @@ -95,6 +97,6 @@ None yet. ## Session Continuity -Last session: 2026-04-10T11:05:44.949Z -Stopped at: Completed 03-02-PLAN.md +Last session: 2026-04-10T11:32:55.884Z +Stopped at: Completed 04-01-PLAN.md Resume file: None diff --git a/.planning/phases/04-script-generation/04-01-SUMMARY.md b/.planning/phases/04-script-generation/04-01-SUMMARY.md new file mode 100644 index 0000000..2f2fbce --- /dev/null +++ b/.planning/phases/04-script-generation/04-01-SUMMARY.md @@ -0,0 +1,105 @@ +--- +phase: 04-script-generation +plan: "01" +subsystem: script-generator +tags: [jinja2, powershell, tdd, wow64, uac, pnputil, idempotency] +one_liner: "Jinja2-based install.ps1 generator with WOW64 guard, UAC elevation, pnputil two-step, and duplex mapping" +dependency_graph: + requires: [] + provides: [render_install, install.ps1.j2] + affects: [imptune.generators.script_generator, imptune.templates.scripts] +tech_stack: + added: [] + patterns: + - Jinja2 FileSystemLoader with trim_blocks + lstrip_blocks for PowerShell templates + - Plain-string function parameters for DB-free unit testability + - _duplex_map translation dict (model values -> PowerShell cmdlet values) +key_files: + created: + - imptune/generators/script_generator.py + - imptune/templates/scripts/install.ps1.j2 + - tests/test_script_generator.py + modified: [] +decisions: + - "render_install() takes plain string args (not ORM Printer object) — keeps tests DB-free" + - "Boolean color_mode/collate converted to lowercase 'true'/'false' strings; template adds $ prefix" + - "_duplex_map translates before rendering: LongEdge->TwoSidedLongEdge, ShortEdge->TwoSidedShortEdge" + - "WOW64 guard comment avoids 'pnputil.exe' text to preserve ordering assertion in test" +metrics: + duration: "~2 min" + completed_date: "2026-04-10" + tasks_completed: 1 + files_created: 3 + files_modified: 0 + tests_added: 7 + tests_passing: 68 +--- + +# Phase 4 Plan 01: Script Generator (Install) Summary + +**One-liner:** Jinja2-based install.ps1 generator with WOW64 guard, UAC elevation, pnputil two-step, and duplex mapping + +## What Was Built + +A TDD-developed module `imptune/generators/script_generator.py` with a single public function `render_install()` that renders the `install.ps1.j2` Jinja2 template into a complete, production-ready PowerShell printer install script. + +### render_install() function + +- Takes plain string arguments (no ORM dependency) for easy unit testing +- Translates `duplex_mode` via `_duplex_map` before passing to template +- Converts Python booleans to lowercase strings (`"true"`/`"false"`) for PowerShell `$true`/`$false` rendering + +### install.ps1.j2 template structure (in order) + +1. Header comment with printer name and required Intune install command +2. WOW64 guard (`$env:PROCESSOR_ARCHITECTURE` + `SysNative` relaunch) — FIRST executable block +3. SYSTEM vs admin detection (`[WindowsIdentity]::GetCurrent()`, `IsSystem`, `IsInRole(Administrator)`) + UAC self-elevation via `Start-Process -Verb Runas` +4. pnputil two-step: `/add-driver` to stage INF, then `Add-PrinterDriver` to register +5. Idempotent port creation: `Get-PrinterPort` check before `Add-PrinterPort` +6. Idempotent printer creation: `Get-Printer` check before `Add-Printer` +7. `Set-PrintConfiguration` with translated duplex, color, paper size, collate + +## TDD Execution + +### RED Phase (commit b4f2c64) + +7 tests written in `tests/test_script_generator.py` covering SCRPT-01, SCRPT-04, SCRPT-05. All failed with `ModuleNotFoundError` (confirmed RED). + +### GREEN Phase (commit 8193e9d) + +- `imptune/generators/script_generator.py` created +- `imptune/templates/scripts/install.ps1.j2` created + +One auto-fix required during GREEN: template comment contained `"pnputil.exe"` before the WOW64 `PROCESSOR_ARCHITECTURE` check text, causing the ordering assertion in `test_render_install_wow64_guard` to fail. Fixed by removing `.exe` from the comment text. Not a logic error — purely a textual ordering issue in the rendered output. + +All 7 new tests pass. Full suite: 68/68 passing. + +## Commits + +| Hash | Type | Description | +|------|------|-------------| +| b4f2c64 | test | RED phase — 7 failing tests for script_generator | +| 8193e9d | feat | GREEN phase — script_generator.py + install.ps1.j2 | + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] Template comment contained 'pnputil.exe' before WOW64 guard text** +- **Found during:** GREEN phase test run +- **Issue:** Comment in the WOW64 guard block header said "pnputil.exe is 64-bit only", so the string "pnputil.exe" appeared in the rendered output before "PROCESSOR_ARCHITECTURE", breaking the ordering assertion in `test_render_install_wow64_guard` +- **Fix:** Changed "pnputil.exe is 64-bit only" to "pnputil is 64-bit only" in the template comment +- **Files modified:** `imptune/templates/scripts/install.ps1.j2` +- **Commit:** 8193e9d (included in same GREEN commit) + +## Self-Check: PASSED + +All created files verified on disk. All commits verified in git log. + +| Item | Status | +|------|--------| +| imptune/generators/script_generator.py | FOUND | +| imptune/templates/scripts/install.ps1.j2 | FOUND | +| tests/test_script_generator.py | FOUND | +| Commit b4f2c64 (RED) | FOUND | +| Commit 8193e9d (GREEN) | FOUND |