Skip to content

v4.12 — Zip-Style Critical Path

Critical Path's daily puzzle stopped being "rotate tiles to connect a network" and became "draw one line through numbered checkpoints in order" — faster to grasp, more immediately satisfying, with everything else about the daily loop untouched.

Summary

Critical Path's daily minigame had been Pipes since the mechanic first shipped under OBJ-216: rotate tiles until a network connects. Josh reported it felt slower and less satisfying than LinkedIn's Zip puzzle format, and confirmed on 2026-07-23 that Pipes should be fully replaced — not run alongside a second game — with the Hint button explicitly deferred to a future milestone.

v4.12 delivered that replacement in three additive-then-atomic phases. Phase 1 built a headless Zip puzzle engine (seeded Hamiltonian-path generation with ordered checkpoints and wall barriers, mirroring the existing Pipes engine's 500ms-budget-plus-fallback-pool pattern almost exactly) as new files alongside the live Pipes code, changing nothing about what players actually saw. Phase 2 built the interactive ZipBoard.vue component — drag, tap, or keyboard to draw the path — again purely additive. Phase 3 was the single cutover PR: PlayView.vue rewired from Pipes to Zip, pipes/ and PipesBoard.vue deleted, and every player-facing surface (tutorial overlay, instruction copy, analytics param names) updated to describe the new mechanic. Reverting that one PR restores Pipes wholesale — the milestone was deliberately structured so the riskiest change (the live cutover) had the cleanest possible rollback.

The backend needed zero changes throughout: CriticalPathPlay already recorded only puzzle_date and elapsed_seconds, and FetchToday already served a mechanic-agnostic daily seed. Stim XP, streaks, cosmetic themes, percentile scoring, the share card, and the one-play-per-day lock are all exactly as they were before this milestone — only the puzzle itself changed.

As of this writing, the work is complete on the milestone's own integration branch (gsd/v4.12-zip-style-critical-path) but has not yet merged to master — see Outcomes below for what that means for who has actually seen this.

Goal

Replace the Critical Path daily puzzle mechanic (currently Pipes — rotate tiles to connect a network) with a Zip-style Hamiltonian-path puzzle: the player draws one continuous line that connects numbered checkpoints 1 → N in order, fills every cell, and never crosses a wall barrier between cells. The board is solved when a single path visits every cell in checkpoint order. Faster to grasp, more immediately satisfying, and a better daily-loop retention driver — without adding a dark-pattern hook (still one play per day, still no infinite loop).

.planning/milestones/v4.12-zip-style-critical-path-ROADMAP.md

Scope — What Shipped

  • New headless engineionic_frontend/src/play/zip/ (types.ts, adjacency.ts, generator.ts, winCheck.ts, build-fallback-pool.ts + fallback-puzzles.json): deterministic, guaranteed-solvable seeded Hamiltonian-path generation with ordered checkpoints and wall placement, a 500ms generation budget backed by a curated fallback pool, and a zip:fallback-triggered Sentry alert mirroring the existing Pipes pattern.
  • New interactive componentionic_frontend/src/play/ZipBoard.vue + zip/pathLogic.ts: drag-to-draw, tap-adjacent, and keyboard input unified on one shared legality rule; wall-barrier and numbered-checkpoint rendering; the full state catalog (start/active/invalid/won/hover/disabled/pressed/reduced-motion) reusing stimThemes.ts's existing Stim gradient hooks — no new color palette.
  • PlayView.vue rewired off Pipes onto the Zip engine and board: progress model changed from "pipes connected" to "cells filled / total," win is a complete valid path, Undo now removes the last path segment (was: undo last tile rotation), Reset unchanged.
  • pipes/ and PipesBoard.vue deleted wholesale, along with their tests — no dead code left behind.
  • Player-facing copy and visuals updated to Zip rulesHowToPlayOverlay.vue rewritten for checkpoint order, wall barriers, and "fill every cell"; CompletionModal.vue, CriticalPathShareCard.vue, and CriticalPathTile.vue needed no changes (they never carried pipe-specific copy or artwork).
  • Analytics renamed, not restructuredrotation_countpath_moves (and the reset-time counterpart), while event names (critical_path_puzzle_completed/abandoned/critical_path_undo_tapped) stayed stable for dashboard continuity.
  • No backend, migration, model, Interaction, or GraphQL change — the entire delivery is ionic_frontend/src/play/**.
  • Docs — engine docs at kickoff (critical-path/README.md, docs/operations/alerting.md's fallback-alert section), then CHANGELOG entries (both the engineering log and the in-app player-facing note) and two stale-doc corrections at the cutover.

Phases

PhaseNameStatusPRsHighlights
1Zip puzzle engine (headless TS)Shipped#1730Deterministic, guaranteed-solvable generator; 41/41 tests, 98%+ coverage; zero Roy findings
2ZipBoard component + interactionShipped#1732Desi's UI-SPEC passed gsd-ui-checker clean; Roy's Round 1 review caught 3 unimplemented spec'd states, fixed same day
3PlayView cutover + surfaces + copyShipped#1735The atomic cutover — pipes/ deleted, PlayView.vue rewired, CHANGELOG + release note shipped

Key Decisions

  • Full replacement, not a second game (Josh, 2026-07-23) — Zip supersedes Pipes outright; there was never a plan to run both mechanics side by side.
  • Walls in scope from the start — the defining Zip twist that distinguishes it from a plain space-filling path puzzle; deferring walls would have made the puzzle materially easier and off-brief.
  • Hint deferred (Josh, 2026-07-23) — Zip parity would eventually want a Hint button, but it stayed explicitly out of scope for this milestone, tracked only as a future idea.
  • Per-phase PRs on the integration branch, with the cutover as the sole atomic step — Phases 1 and 2 landed as pure additions with zero live-behavior change (PlayView.vue kept importing pipes/ until Phase 3), so the only PR that could regress a real user's daily puzzle was the single, easily-revertible cutover PR.
  • No new feature flag for the cutover/play was already gated by the pre-existing, fully-rolled-out critical-path-full-product flag from Critical Path's original v1.19 launch. The team chose not to add a second flag specifically for Zip, meaning the mechanic goes live for every existing Critical Path player the moment the integration branch reaches production — there is no gradual-rollout lever to pull separately.
  • Generator solver bounded by node-visit count, not wall-clock polling alone (Codi, Phase 1) — a randomized-DFS Hamiltonian-path search needs a different timeout guard than the spanning-tree approach Pipes used, so the fallback trigger stays deterministically fast regardless of machine speed while the real 500ms/Sentry path remains the true last resort.

Requirements Coverage

7 / 7 requirements satisfied (per .planning/milestones/v4.12-zip-style-critical-path-MILESTONE-AUDIT.md — this milestone has no separate REQUIREMENTS.md; the ROADMAP's phase checklist is the requirements source of record).

CategoryCountStatus
ZIP-ENGINE / ZIP-DOCS-1 (Phase 1)2Satisfied
ZIP-UISPEC / ZIP-BOARD (Phase 2)2Satisfied
ZIP-PLAYVIEW / ZIP-SURFACES / ZIP-DOCS-2 (Phase 3)3Satisfied

Full requirements list: v4.12-zip-style-critical-path-ROADMAP.md on GitHub.

Outcomes

In the codebase, Critical Path's daily puzzle is Zip: draw one line through numbered checkpoints in order, fill every cell, respect wall barriers — with every mechanic-independent surface (XP, streaks, themes, percentile scoring, sharing, reminders, the one-play-per-day lock) exactly as it was before this milestone.

No real user has played it yet. The milestone's integration branch (gsd/v4.12-zip-style-critical-path) has not merged to master, so nothing here has reached staging's or production's live app. Because /play rides the already-fully-rolled-out critical-path-full-product flag rather than a new flag of its own, the moment that merge lands and deploys, the cutover is live for every existing Critical Path player — there's no separate rollout percentage to raise. Merging the integration branch to master is the one concrete step standing between this milestone's code being complete and the feature actually shipping to users.

Tech Debt

  • (Phase 3) Master merge not yet performed — see Outcomes above. No integration-merge issue has been opened for this yet (compare v4.11's OBJ-1622).
  • (Phase 3) True interactive UAT of the live /play puzzle never happened this milestone. Root cause: .github/workflows/preview.yml never sets VITE_POSTHOG_KEY, so PostHog can't resolve any feature flag on Preview builds, and every /play screenshot attempt during this milestone rendered the Dashboard instead. Tracked as OBJ-1682 (Tess). Roy's code-level UI-SPEC fidelity review was the compensating control.
  • (Phase 3) docs/features/critical-path.md still documents the old Pipes gameplay in detail and needs a fuller rewrite than this milestone's docs scope covered.
  • (Phase 3) The Pipes Sentry alert rule (pipes:fallback-triggered) is now permanently inert since its emitting code was deleted — documented as retired in docs/operations/alerting.md, but the Sentry UI itself hasn't been cleaned up.
  • 582a918f — Phase 1 merge: headless Zip puzzle engine
  • dd2dbc06 — Phase 2 merge: ZipBoard component + interaction
  • 4c6c2cb0 — Phase 3 merge: PlayView cutover, pipes/ retirement, docs

Last updated: 2026-07-23

Loading…