Files
ImpTune/.planning/phases/01-foundation/01-VALIDATION.md
T
kawa d37a196ee7 docs(08-01): add Phase 1 Nyquist Record to 01-VALIDATION.md
- Append ## Nyquist Record table above Validation Sign-Off
- 14 rows: one observable check per Phase 1 success criterion (derived from v1.0-ROADMAP.md goal + plan outcomes)
- Evidence cites committed tests (test_health, test_static, test_db, test_intunewin), source file:lines, commit SHAs, or 01-VERIFICATION.md rows
- Row 14 closes former 'Upload to real Intune tenant' spike: fail-fix-v1.1 -> resolved PASS citing Phase 10 RTVAL-01 sign-off (2026-04-13)
- Frontmatter: nyquist_compliant true, nyquist_audited 2026-04-13, nyquist_auditor set
- All historical sections preserved verbatim
2026-04-13 15:55:13 +02:00

10 KiB

phase, slug, status, nyquist_compliant, wave_0_complete, created, nyquist_audited, nyquist_auditor
phase slug status nyquist_compliant wave_0_complete created nyquist_audited nyquist_auditor
1 foundation draft true false 2026-04-10 2026-04-13 Claude (gsd-executor, plan 08-01)

Phase 1 — Validation Strategy

Per-phase validation contract for feedback sampling during execution.


Test Infrastructure

Property Value
Framework pytest 8.x
Config file none — Wave 0 installs
Quick run command pytest tests/ -x -q
Full suite command pytest tests/ -v
Estimated runtime ~5 seconds

Sampling Rate

  • After every task commit: Run pytest tests/ -x -q
  • After every plan wave: Run pytest tests/ -v
  • Before /gsd:verify-work: Full suite must be green
  • Max feedback latency: 10 seconds

Per-Task Verification Map

Task ID Plan Wave Requirement Test Type Automated Command File Exists Status
01-01-01 01 1 INFRA-01 smoke pytest tests/test_health.py -x W0 pending
01-01-02 01 1 INFRA-02 unit pytest tests/test_static.py::test_no_cdn_urls -x W0 pending
01-02-01 02 1 INFRA-01 unit pytest tests/test_db.py::test_create_tables -x W0 pending
01-03-01 03 1 INFRA-02 unit pytest tests/test_intunewin.py::test_byte_layout -x W0 pending
01-03-02 03 1 (spike) manual Upload to real Intune tenant N/A pending

Status: pending · green · red · ⚠️ flaky


Wave 0 Requirements

  • tests/__init__.py — package marker
  • tests/conftest.py — shared fixtures (temp dir, test DB path)
  • tests/test_health.py — covers INFRA-01 HTTP health check
  • tests/test_db.py — covers INFRA-01 schema init (all tables created, WAL mode)
  • tests/test_static.py — covers INFRA-02 no-CDN-URLs assertion
  • tests/test_intunewin.py — covers spike byte layout validation
  • Framework install: pip install pytest httpx — add to requirements-dev.txt

Existing infrastructure covers: None (greenfield project)


Manual-Only Verifications

Behavior Requirement Why Manual Test Instructions
No Node.js in container INFRA-02 Requires running container inspection docker exec imptune which node — should return nothing
.intunewin uploads to real Intune (spike) Requires Intune tenant access Upload generated .intunewin via Intune portal, verify "successfully uploaded" status

Nyquist Record

Audited 2026-04-13 by Claude (gsd-executor, plan 08-01). One row per Phase 1 success criterion derived from milestones/v1.0-ROADMAP.md Phase 1 goal + plan outcomes, cross-checked against 01-VERIFICATION.md (13/13 observable truths verified on 2026-04-10) and REQUIREMENTS.md (INFRA-01, INFRA-02). Evidence cites committed tests, source lines, or the dated VERIFICATION report. Status values: pass / fail-fix-v1.1 / deferred-v1.2 / wont-do.

Phase 1 goal (v1.0-ROADMAP.md): "A running Docker container with the app scaffold, data schema, and validated .intunewin generation capability."

# Success Criterion Observable Check Evidence Status Notes
1 docker compose up starts the app and serves HTTP 200 on GET /health pytest tests/test_health.py::test_health_returns_200 returns the health payload tests/test_health.py::test_health_returns_200; imptune/api/health.py (router returns {"status": "ok"}); 01-VERIFICATION.md row 1 (2026-04-10) pass INFRA-01. Docker image build itself is a human check (network to pico/htmx/alpine CDNs); covered by 01-VERIFICATION.md §"Human Verification Required" #1 and later exercised end-to-end during Phase 10 RTVAL-01 tenant upload (commit 7b37bdb referenced build 1c3f458).
2 Container has no Node.js dependency and starts from a single python:3.12-slim-bookworm image grep -n "^FROM" Dockerfile returns only FROM python:3.12-slim-bookworm; no node/npm install layer Dockerfile line 1; commit 34c7cb3 (feat(01-01)); 01-VERIFICATION.md row 2 pass INFRA-02 — "no Node.js" arm.
3 All static assets (Pico CSS, HTMX, Alpine.js) are served from /static/ with zero CDN references in templates pytest tests/test_static.py::test_no_cdn_urls_in_templates tests/test_static.py::test_no_cdn_urls_in_templates; imptune/templates/base.html (4 /static/ refs, zero https://); 01-VERIFICATION.md row 3 pass INFRA-02 — offline static arm.
4 App shell displays a sidebar with Dashboard, Drivers, Printers, Clients, Packages sections Grep imptune/templates/base.html for the 5 nav hrefs (/, /drivers, /printers, /clients, /packages) imptune/templates/base.html sidebar nav; 01-VERIFICATION.md row 4; Phase 7 GET /packages closure (commit landed under phase 07) proves the link is live pass Dashboard quick-action buttons intentionally aria-disabled in Phase 1 — documented, not a gap.
5 App follows OS dark/light theme preference automatically Grep imptune/templates/base.html line 2 for data-theme="auto" imptune/templates/base.html line 2; 01-VERIFICATION.md row 5 pass UI polish criterion from 01-01 plan frontmatter.
6 SQLite database initializes automatically on first run with all 4 tables (Client, Driver, Printer, Icon) pytest tests/test_db.py::test_create_tables tests/test_db.py::test_create_tables; imptune/db/database.py::init_db; imptune/main.py lifespan call (commit 88d9c5f); 01-VERIFICATION.md row 6 pass INFRA-01 — schema arm. Full 4-table upfront schema decision (v1.0 key decision).
7 Database uses WAL journal mode and has foreign keys enabled pytest tests/test_db.py::test_wal_mode and ::test_foreign_keys tests/test_db.py::test_wal_mode, ::test_foreign_keys; imptune/db/database.py pragmas {"journal_mode": "wal", "foreign_keys": 1}; 01-VERIFICATION.md row 7 pass
8 Database file is created inside the DATA_DIR volume path, not inside the container filesystem Grep imptune/db/database.py for cfg.DB_PATH; grep docker-compose.yml for imptune_data:/data; grep for DATA_DIR=/data env imptune/db/database.py (db.init(cfg.DB_PATH, ...)); docker-compose.yml named volume + env; 01-VERIFICATION.md row 8 pass Persistence-across-restart property.
9 Schema creation is idempotent — repeated startups do not fail or duplicate tables pytest tests/test_db.py::test_idempotent tests/test_db.py::test_idempotent; create_tables(..., safe=True) in init_db(); 01-VERIFICATION.md row 9 pass
10 A Python function produces a valid .intunewin file from a source directory and setup file name pytest tests/test_intunewin.py::test_output_is_valid_zip tests/test_intunewin.py::test_output_is_valid_zip; imptune/generators/intunewin_builder.py::build_intunewin; commit 25f82e6; 01-VERIFICATION.md row 10 pass Python-native .intunewin core decision (pycryptodome, no IntuneWinAppUtil.exe).
11 .intunewin output contains outer ZIP with IntuneWinPackage/Contents/IntunePackage.intunewin and IntuneWinPackage/Metadata/Detection.xml pytest tests/test_intunewin.py::test_outer_zip_structure tests/test_intunewin.py::test_outer_zip_structure; imptune/generators/intunewin_builder.py outer-ZIP assembly lines 103-111; 01-VERIFICATION.md row 11 pass
12 Encrypted blob uses correct byte layout: HMAC-SHA256 (32 bytes) + IV (16 bytes) + AES-256-CBC ciphertext pytest tests/test_intunewin.py::test_encrypted_blob_layout tests/test_intunewin.py::test_iv_is_16_bytes tests/test_intunewin.py::test_hmac_matches tests/test_intunewin.py (test_encrypted_blob_layout, test_iv_is_16_bytes, test_hmac_matches); imptune/generators/intunewin_builder.py (blob = mac_digest + iv + ciphertext); 01-VERIFICATION.md row 12 pass HMAC-over-IV+ciphertext scope later hardened in commit 74535ea during Phase 10 RTVAL-01 debug — but the byte-layout contract verified here is still the canonical one.
13 Detection.xml contains correct EncryptionKey, MacKey, InitializationVector, Mac, FileDigest values matching the actual encryption pytest tests/test_intunewin.py::test_detection_xml_fields tests/test_intunewin.py::test_decryption_roundtrip tests/test_intunewin.py::test_file_digest_matches tests/test_intunewin.py::test_unencrypted_content_size tests/test_intunewin.py (5 tests listed); 01-VERIFICATION.md row 13 pass Detection.xml field ordering also re-aligned with IntuneWinAppUtil.exe reference format in commit 7716246 (Phase 10 debug); byte-level equivalence preserved.
14 .intunewin output is accepted by a real Microsoft Intune tenant end-to-end (decrypt + app registration) Dated runtime check recorded in Phase 10 RUNTIME-VALIDATION.md (RTVAL-01) Phase 10 RUNTIME-VALIDATION.md RTVAL-01 PASS (2026-04-13, re-test on fixed build after ISSUE-01 resolved via commits 74535ea + 7716246); artifact .planning/phases/10-real-world-runtime-validation/evidence/Copieur_2eme.intunewin; STATE.md decision log [Phase 10-01 / 10-02 RTVAL-01 PASS] pass Was the single Phase 1 Nyquist gap ("Upload to real Intune tenant" spike in the Manual-Only Verifications table above). Resolved by Phase 10 (NYQ→RTVAL-01) on 2026-04-13; originally would have been fail-fix-v1.1 → Phase 10 / RTVAL-01, now closed as pass citing the Phase 10 sign-off.

Audit outcome: 14/14 rows pass. No fail-fix-v1.1, deferred-v1.2, or wont-do rows. Phase 1 is Nyquist-compliant: every success criterion has exactly one observable check with cited, committed evidence.


Validation Sign-Off

  • All tasks have <automated> verify or Wave 0 dependencies
  • Sampling continuity: no 3 consecutive tasks without automated verify
  • Wave 0 covers all MISSING references
  • No watch-mode flags
  • Feedback latency < 10s
  • nyquist_compliant: true set in frontmatter

Approval: pending