- Add Alpine.store('theme') for Light/Dark/System cycling with localStorage persistence
- Add Alpine.store('i18n') with FR/EN translations for all static UI strings
- Add topbar with theme toggle button (:aria-label, @click cycle) and lang button
- Wrap main content in .main-wrapper + .topbar for layout structure
- Add .main-wrapper, .topbar, .topbar-controls styles to app.css
- Add test_theme_toggle_present integration test
- Fix test_dashboard_shows_recent_printers assertion (string now in i18n JS too)
- Add PATCH /{printer_id} route with validation and in-place update
- Optional ip_address/port_name fall back to existing values when not sent
- updated_at set explicitly on save (datetime.now(UTC))
- Update _render_printer_list to include clients and driver_data in context
- Import Driver at module level for use in both handler and helper
- Create 11-01-SUMMARY.md with full execution record
- Update STATE.md: advance plan to 3, add decisions, update session
- Update ROADMAP.md: phase 11 progress to 1/4 summaries (In Progress)
- Add 8 new test functions: printers_new_returns_200, create_printer_redirects,
printers_library_no_form, patch_printer, patch_printer_not_found,
client_detail_returns_200, client_detail_not_found, client_links_in_printer_list
- Add FIXME comments on existing POST /printers tests noting upcoming 303 change
- All new tests FAIL against current code (proper RED TDD state)
- Existing 13 tests remain GREEN
Plan 4 plans across 3 waves covering UIE-01..05: form separation
(Plan 01), printer edit modal (Plan 02), theme+i18n toggles (Plan 03),
and client detail page (Plan 04). Wave 0 test scaffolds included in Plan 01.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Flip v1.0-VALIDATION-INDEX.md frontmatter draft -> signed-off (Sébastien QUEROL, 2026-04-13)
- Tick index sign-off line (45/45 pass, 0 fail-fix-v1.1)
- Replicate dated sign-off line into all 7 per-phase VALIDATION.md Validation Sign-Off blocks
- Tick nyquist_compliant checkbox in phases 01/02/03/04/05/07 (06 already ticked)
- Upgrade Approval lines phases 01-05 from 'pending' to signed-off with index back-link
- Tick REQUIREMENTS.md NYQ-02/NYQ-03 and flip Traceability Pending -> Complete
- Phase 4 attestation-only runtime gap recorded in index Residual Risk block (not reopened per plan 10-03 sign-off)
Technician confirmed real-world rollout: ImpTune ran in its local Docker
container, generated printer packages were delivered end-to-end via BOTH
Intune and NinjaRMM to real endpoints, and all tested installs succeeded
with no blocking items to triage.
Closes RWR-01..04. Attestation-only (mirrors Phase 10 accepted gap) -
no artifact evidence captured.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Status flipped from READY FOR SIGN-OFF to SIGNED OFF
- Signed off by Sébastien QUEROL on 2026-04-13
- All three sign-off checkboxes ticked
- Reviewer explicitly acknowledged attestation-only audit-trail gap for RTVAL-02/03/04
- Only RTVAL-01 is artifact-backed; RTVAL-02/03/04 accepted on technician attestation
- Status moved from IN PROGRESS to READY FOR SIGN-OFF
- RTVAL-01 evidence converted to markdown relative links (tenant-upload, app-assigned, .intunewin package)
- Sign-off section rewritten to surface attestation-only audit trail damage prominently
- Three sign-off checkboxes restructured to force explicit reviewer acknowledgement of RTVAL-02/03/04 attestation-only nature
- Compensating controls block added (known device, known tenant, single session, known-good generator)
- Duplicate Signed off by header removed from top; consolidated in Sign-off section
- Status: PASS (attested, no artifact) — third consecutive attestation-only check
- No uninstall log or portal screenshot captured
- Technician verbally confirmed uninstall under SYSTEM, clean removal from ARES-5CG5220YTM
- RTVAL-02/03/04 together constitute an attestation-only runtime half for Phase 10
- User warned twice and still chose attestation-only; audit trail weakened
- Top-level Status line updated to reflect all four RTVAL checks recorded
- Status: PASS (attested, no artifact) — second consecutive attestation-only check
- No evidence/rtval-03-detection.png or rtval-03-detect-manual.txt captured
- Technician verbally confirmed Intune 'Installed' on ARES-5CG5220YTM
- User warned about weakened audit trail and chose to proceed anyway
- Plan 10-02 advanced to Task 4 (RTVAL-04 uninstall under SYSTEM)
- Mark RTVAL-02 PASS based on technician verbal attestation
- Flag explicitly as attestation-only: no log excerpt, no screenshot
- Audit trail weakened for this check (documented in Notes)
- User approved proceeding without evidence on 2026-04-13
- Advance report header to 'paused at Task 3 (RTVAL-03)'
- Flip RTVAL-01 from FAIL to PASS after re-test against live tenant rubis.fr
- Reference evidence screenshots (tenant-upload, app-assigned)
- Fix Package SHA256 (strip trailing garbage) to 8818124aa97ed3da24bf73a1f08f43065e6efea46f44a3abffc9983b097d3ddc
- Update top-level Status to IN PROGRESS; plan 10-02 resumed at Task 2
- Resolve ISSUE-01 (fixed in 74535ea HMAC scope + 7716246 Detection.xml alignment)
- Lock package to ImpTune commit 00b709d
Session now records the second root cause (HMAC over ciphertext-only vs
IV+ciphertext) and the fix applied in commit 74535ea. Status moved back
to awaiting_human_verify for next Intune upload retry.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The reference implementation (svrooij/ContentPrep Zipper.cs DecryptFileAsync)
reads the first 32 bytes as the stored HMAC, then hashes the *remaining* bytes
— i.e. IV (16 bytes) || ciphertext — to verify integrity. ImpTune was computing
HMAC(mac_key, ciphertext) which omits the IV. Intune's server-side HMAC check
would therefore always fail, manifesting as the same silent symptom as the
Detection.xml bug: empty wizard fields, greyed OK button, no error banner.
The blob layout is unchanged: [HMAC(32)] + [IV(16)] + [ciphertext].
Only the hash input is corrected: iv + ciphertext instead of ciphertext.
The Mac field in Detection.xml is also updated accordingly (it stores the same
HMAC value that is prepended to the blob).
Tests updated: test_hmac_matches now verifies HMAC over blob[32:] (= IV+ciphertext),
which is exactly what the reference decryption algorithm verifies against.
All 114 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Four structural defects in the generated Detection.xml caused Intune's upload
wizard to silently fail metadata parsing (empty form, OK button greyed):
1. Missing ToolVersion="1.8.6.0" XML attribute on ApplicationInfo — the wizard
uses this to validate the package was produced by a compatible tool.
2. Spurious xmlns="http://schemas.microsoft.com/IntuneWin" namespace — changes
element identity for Intune's XML parser (reference emits no namespace).
3. <?xml version="1.0" ?> declaration header — reference uses OmitXmlDeclaration=true.
4. Extra <MacAlgorithm> child element inside EncryptionInfo — not present in
the reference FileEncryptionInfo model (svrooij/ContentPrep verified).
Fix: switched from toprettyxml() to tostring(xml_declaration=False)+indent(),
added ToolVersion attribute, removed xmlns and MacAlgorithm.
Tests updated to assert the corrected reference format; all 114 pass.
Root cause verified against svrooij/ContentPrep Packager.cs + ApplicationInfo.cs
(open-source C# reference implementation of IntuneWinAppUtil.exe).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Status set to BLOCKED with .intunewin structure defect as blocker
- BLOCKER-01 raised: Detection.xml missing/malformed in generated package
- Decision recorded: stop plan 10-02, gap-closure via /gsd:debug or /gsd:plan-phase 10 --gaps
- Session continuity updated to reflect RTVAL-01 FAIL stop point
- RTVAL-01 status set to FAIL: Win32 app wizard fields stayed empty, OK greyed out
- Verbatim technician symptom quoted verbatim in report
- Interpretation: Detection.xml / package metadata malformed or missing in .intunewin archive
- RTVAL-02, RTVAL-03, RTVAL-04 marked BLOCKED (all depend on RTVAL-01 PASS)
- ISSUE-01 raised in Issues Found with root cause hypothesis and resolution path
- Plan 10-02 stopped; gap-closure cycle required before retesting
- Add 10-01-preflight-package-and-scaffold-SUMMARY.md
- Update STATE.md: position moved to Phase 10 plan 01 complete
- Update ROADMAP.md: Phase 10 shows 1/3 summaries (In Progress)
- Mark RTVAL-05 complete in REQUIREMENTS.md
- Create RUNTIME-VALIDATION.md with Tenant & Environment metadata table
- Add RTVAL-01 through RTVAL-04 sections with PENDING status
- Add Issues Found and Sign-off checklist sections
- Create evidence/.gitkeep so git tracks the evidence directory
Real INFs (e.g. Ricoh oemsetup.inf) include [SourceDisksFiles] entries
with bare filename lines (no '='), which strict configparser rejects
with ParsingError, surfacing as a 500 on /drivers/upload.
Pre-process the INF text to rewrite bare lines into synthetic
__bare_N = <line> entries before parsing, and filter those synthetic
keys out of DriverDesc extraction so they cannot leak into driver_names.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create tests/e2e/test_port_autofill.py - headless chromium test for PRNT-03
- Verifies IP->port_name auto-derivation via Alpine @input handler at /printers
- Update 09-VALIDATION.md: mark UX-02 tasks green, cite test file as evidence
- Import Form from fastapi for mixed multipart + form field support
- Add caller: str = Form('') parameter to upload_driver handler
- Capture new_driver from Driver.get_or_create() return tuple
- Branch on caller == 'printer_form' to emit OOB-enabled response
- Create partials/driver_upload_with_oob.html with primary driver_list
include + hx-swap-oob select targeting id=printer-form-driver-select
- New driver is auto-selected via new_driver_id context variable
All 13 driver upload tests pass including 4 new OOB contract tests.
Full non-e2e suite: 111 passed.
- Create tests/test_script_download.py with 5 tests for .ps1 routes (install/uninstall/detect, 404, 422)
- Add test_detail_page_shows_script_links to TestCommandPreview in tests/test_packages.py
- All 6 new tests go RED (routes and template links do not exist yet)
Three plans covering UX-01 (driver upload 500 fix + inline HTMX OOB
refresh on printer form), UX-02 (Playwright headless test for PRNT-03
IP->port auto-fill), and UX-03 (.ps1 script download routes + detail
page links). VALIDATION.md finalized with real task IDs and
nyquist_compliant=true. ROADMAP Phase 9 plan list filled in.
- SUMMARY.md documents /packages route, dashboard live queries, 99 tests green
- STATE.md advanced to 7/7 phases complete (100%)
- ROADMAP.md marks Phase 7 and plan 07-01 complete
- Dashboard queries 5 most recent Printer records and 5 most recent driver-assigned ones
- New /packages route lists printers with drivers, with intunewin/ninja download links
- packages.html template extends base.html with Pico grid table
- Dashboard printer/package items now link to detail pages
- Quick action buttons wired to real routes (removed aria-disabled)
- Add shutil import and Icon import to packages.py
- After driver extraction, look up Icon record for printer
- If found and file exists on disk, copy to tmpdir/icon.png
- Missing icon (no DB record or missing file) silently skipped — export still succeeds
- PKG-04 requirement satisfied
Phase 6 wires icon into .intunewin export (closes PKG-04).
Phase 7 fixes dashboard empty state and /packages 404 nav link.
PKG-04 reset to Pending in REQUIREMENTS.md traceability table.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create 05-02-SUMMARY.md with full execution details
- Update STATE.md progress to 100%, add 4 key decisions, record metrics
- Update ROADMAP.md phase 5 status to Complete
- Mark requirements PKG-04 and PKG-05 complete
- Update printer_detail() to pass install_cmd, uninstall_cmd, has_driver, has_icon to template
- Rewrite printer_detail.html with Intune Commands, Export, and Icon sections
- Show command strings with Alpine.js copy-to-clipboard buttons (install-cmd, uninstall-cmd)
- Show NinjaRMM ZIP and .intunewin download links when driver assigned
- Add HTMX icon upload form with #icon-status swap target
- Remove disabled placeholder Regenerate Package button
- Add TestCommandPreview class (4 tests) to test_packages.py
- All 94 tests pass
- Create imptune/api/icons.py with POST /printers/{printer_id}/icon
- Validate PNG format, 256x256 dimensions, 750KB max size
- Store icons SHA256-addressed under cfg.DATA_DIR/icons/
- Replace existing Icon record on re-upload
- Register icons.router in main.py with ICONS_DIR makedirs
- Patch cfg.ICONS_DIR in conftest.py for tests
- All 6 icon upload tests pass
- GET /printers/{id}/packages/ninja: in-memory ZIP with install.ps1 + driver files in named subfolder
- GET /printers/{id}/packages/intunewin: temp dir build of .intunewin via build_intunewin()
- _get_printer_and_driver() helper validates printer, driver, inf, desc
- Driver ZIP file existence check before processing (RESEARCH pitfall 3)
- TemporaryDirectory context manager for auto-cleanup (RESEARCH pitfall 1)
- Router registered in main.py after scripts router
- All 9 package tests pass, 84 total tests green