Case Study
trail.venturanomadica.com
The Trail Framework website. Built end-to-end using Trail.
← Back to trail.venturanomadica.com
trail/runs/intent-003/run-2026-03-25-20-03-17/results.md
results.md
What's this? →# Run: run-2026-03-25-20-03-17
# Purpose: Build the Brushy case study page and publish its landing-page link
# Completed: 2026-03-25
## Tasks Completed
- CS-001: Created `case-studies/brushy/brushy.php` scaffold with shared header/footer, docs two-column layout, and allowlist-based file request model.
- CS-002: Implemented left sidebar (ADF tree, 7 files, per-file "What's this?" links) and artifact viewer (file name, full ADF path, back control, escaped Markdown in highlighted code block).
- CS-003: Populated the brief view with product description, stats grid, video, and six screenshots. Appended scoped styles to `style.css`.
- CS-004: Updated Brushy card on `case-studies.php` — removed "Coming Soon" badge, added link to `brushy.php`, updated stats to match required values.
- CS-005: Validated PHP syntax on both modified PHP files; verified all acceptance criteria.
## Files Changed/Added
| File | Action |
|------|--------|
| `case-studies/brushy/brushy.php` | Created |
| `case-studies.php` | Modified (Brushy card only) |
| `style.css` | Modified (Brushy scoped section appended at end) |
| `trail/runs/intent-003/run-2026-03-25-20-03-17/results.md` | Populated |
## Deviations from Plan
- **Video embed**: `tasks.md` specifies a YouTube demo embed. No YouTube video ID was present in any file listed in `dev-prompt.md`. Used a local `<video>` element pointing to `media/brushy-in-action.mp4` as the simplest available alternative. A YouTube `<iframe>` embed can replace it once an ID is provided.
- **Stat values on case-studies.php**: The pre-existing card showed `4 hours total` and `30 min AI build time`. Updated to `3 hours` and `15 min` to match the CS-003 required values. Treated `tasks.md` as authoritative over the prior card.
## Assumptions Made
1. **Brief copy**: `tasks.md` references "the exact supplied Brushy description" but no separate copy document was listed in `dev-prompt.md`. The existing `case-studies.php` card text ("A toothbrush timer app for iOS and Android. No smart toothbrush required.") was treated as the supplied one-liner; additional prose drawn solely from factual content in `adf/meta/intent.md`.
2. **Stat labels**: Only the five numeric values were specified (`1`, `3 hours`, `15 minutes`, `30 minutes`, `30 minutes`). Labels (intent / total time / AI build time / idea + intent / testing) chosen to match the style of other case study cards.
3. **highlight.js CDN**: Loaded from cdnjs (version 11.9.0, `atom-one-dark` theme) page-locally, only when the viewer is active. The `atom-one-dark` theme matches the site's existing dark code block treatment in `.prose pre`.
4. **`dirname(__DIR__, 2)` for includes**: Used to reach `header.php` / `footer.php` from `case-studies/brushy/brushy.php`, consistent with `docs/index.php` using `dirname(__DIR__)`.
## Notable Observations
- Both `ai-instructions.md` entries (meta-scoped and run-scoped) correctly link to `/docs/?page=changelog`; all five other artifact files link to `/docs/?page=glossary`.
- The path-traversal guard uses PHP `realpath()` compared against `BRUSHY_ADF_BASE`; unknown GET keys never touch the filesystem.
- highlight.js assets are deferred to the bottom of the page and only emitted when the viewer is active, so the brief view incurs no CDN request.
## Open Questions/Blockers
- **YouTube ID**: Replace the `<video>` element in `brushy.php` with a YouTube `<iframe>` embed once a video ID is available. The existing element is in the `<!-- Demo video -->` block inside the brief view conditional.
## Validation
| Check | Result |
|-------|--------|
| `php -l case-studies/brushy/brushy.php` | Pass — no syntax errors |
| `php -l case-studies.php` | Pass — no syntax errors |
| Default state is brief view | Pass |
| Seven files in sidebar | Pass |
| Each file key switches to viewer | Pass |
| Viewer shows file name + full ADF path | Pass |
| Back control returns to brief | Pass |
| `ai-instructions.md` → `/docs/?page=changelog` | Pass (both meta + run entries) |
| Other five files → `/docs/?page=glossary` | Pass |
| Out-of-bounds guard (realpath + ADF_BASE) | Pass |
| Brushy card links to `case-studies/brushy/brushy.php` | Pass |
| No other case study cards changed | Pass |
| Six screenshots present in brief | Pass |
| Stats values match required: 1, 3 hrs, 15 min, 30 min, 30 min | Pass |