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 markertests/conftest.py— shared fixtures (temp dir, test DB path)tests/test_health.py— covers INFRA-01 HTTP health checktests/test_db.py— covers INFRA-01 schema init (all tables created, WAL mode)tests/test_static.py— covers INFRA-02 no-CDN-URLs assertiontests/test_intunewin.py— covers spike byte layout validation- Framework install:
pip install pytest httpx— add torequirements-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.mdPhase 1 goal + plan outcomes, cross-checked against01-VERIFICATION.md(13/13 observable truths verified on 2026-04-10) andREQUIREMENTS.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: trueset in frontmatter- Nyquist audit complete — 2026-04-13 — Sébastien QUEROL
Approval: Nyquist-audited 2026-04-13 by Claude (gsd-executor, plan 08-01) — 14/14 pass; signed off 2026-04-13 by Sébastien QUEROL (index: v1.0-VALIDATION-INDEX.md)