---
phase: 09-ux-tech-debt-closure
plan: 03
subsystem: api, ui
tags: [fastapi, powershell, jinja2, routes, scripts]

# Dependency graph
requires: []
provides:
  - ".ps1-suffixed route aliases for install, uninstall, detect scripts"
  - "Scripts section in printer_detail.html with 3 direct download links"
  - "Integration tests for the 3 new .ps1 routes and template links"
affects: [phase-10-rtval, phase-11-rollout]

# Tech tracking
tech-stack:
  added: []
  patterns:
    - "Shared handler helpers (_install_response, _uninstall_response, _detect_response) to avoid logic duplication between extensionless and .ps1 route aliases"

key-files:
  created:
    - tests/test_script_download.py
  modified:
    - imptune/api/scripts.py
    - imptune/templates/printer_detail.html
    - tests/test_packages.py

key-decisions:
  - "Added .ps1 routes as aliases (not renames) to preserve backward compatibility of existing extensionless routes"
  - "Scripts section placed inside {% if has_driver %} guard, before Export section"
  - "Shared _*_response() helper pattern to avoid code duplication across route aliases"

patterns-established:
  - "Route alias pattern: shared _*_response() helper called by both the extensionless and .ps1 route handlers"

requirements-completed: [UX-03]

# Metrics
duration: 18min
completed: 2026-04-13
---

# Phase 9 Plan 03: Script Download Links Summary

**Three .ps1 route aliases (install/uninstall/detect) + Scripts section on printer detail page, closing UX-03 with direct individual script downloads**

## Performance

- **Duration:** 18 min
- **Started:** 2026-04-13T08:46:27Z
- **Completed:** 2026-04-13T09:04:00Z
- **Tasks:** 2 (TDD: RED then GREEN)
- **Files modified:** 4

## Accomplishments

- Added `.ps1`-suffixed route aliases for all three script endpoints via shared `_*_response()` helpers
- Added Scripts section to `printer_detail.html` inside the `{% if has_driver %}` guard with 3 direct download anchor links
- 6 new tests: 5 in `test_script_download.py` covering all .ps1 routes (200, 404, 422), 1 in `test_packages.py::TestCommandPreview` for template link presence
- Full non-e2e suite: 106/106 passing with no regressions

## Task Commits

Each task was committed atomically:

1. **Task 1: Wave 0 — failing tests for .ps1 routes + detail page script links** - `d359001` (test)
2. **Task 2: Add .ps1 route aliases + printer_detail.html script links** - `68a2935` (feat)

**Plan metadata:** (docs commit to follow)

_Note: TDD tasks have two commits (test RED → feat GREEN)_

## Files Created/Modified

- `tests/test_script_download.py` - 5 integration tests for the 3 new .ps1 routes (install/uninstall/detect, 404, 422)
- `tests/test_packages.py` - Added `test_detail_page_shows_script_links` to `TestCommandPreview`
- `imptune/api/scripts.py` - Refactored to shared helpers, added 3 `.ps1` route aliases
- `imptune/templates/printer_detail.html` - Added Scripts section with 3 download links before Export section

## Decisions Made

- `.ps1` routes implemented as aliases (not renames) to preserve backward compatibility — existing extensionless routes remain functional
- Scripts section inserted inside existing `{% if has_driver %}` guard per plan spec (no scripts without a driver)
- Shared `_install_response()`, `_uninstall_response()`, `_detect_response()` helpers avoid logic duplication between the two URL shapes

## Deviations from Plan

None — plan executed exactly as written.

## Issues Encountered

During a `git stash` probe to check a pre-existing test failure, a stash from a previous 09-01 session was inadvertently popped into `tests/test_driver_upload.py`. The file was restored to its committed state via `git checkout --` before committing. The pre-existing test failure (`test_upload_returns_oob_when_called_from_form`) is out-of-scope for 09-03 and belongs to the 09-01 plan scope.

## User Setup Required

None — no external service configuration required.

## Next Phase Readiness

- UX-03 closed: technician can download each script individually from the printer detail page
- Existing package export buttons untouched
- Ready for Phase 10 real-world runtime validation

---
*Phase: 09-ux-tech-debt-closure*
*Completed: 2026-04-13*
