@hegemonart/get-design-done 1.38.0 → 1.38.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "Get Design Done — 5-stage agent-orchestrated design pipeline with 9 connections, handoff-first workflow, bidirectional Figma write-back, 22+ specialized agents, queryable knowledge layer (intel store, dependency analysis, learnings extraction), and a self-improvement loop (reflector, frontmatter + budget feedback, global-skills layer). v1.20.0 ships the SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream, and resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) for rate-limit + 429 + context-overflow recovery. Full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows) and release automation (auto-tag + GitHub Release + release-time smoke test).",
8
- "version": "1.38.0"
8
+ "version": "1.38.5"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "get-design-done",
13
13
  "source": "./",
14
14
  "description": "Agent-orchestrated 5-stage design pipeline: Brief → Explore → Plan → Design → Verify. 22+ specialized agents, 9 connections (Figma, Refero, Preview, Storybook, Chromatic, Figma Writer, Graphify, Pinterest, Claude Design), Claude Design handoff, bidirectional Figma write-back, and a queryable intel store (.design/intel/) for dependency and learnings queries. Standalone commands: style, darkmode, compare, figma-write, graphify, handoff, analyze-dependencies, skill-manifest, extract-learnings. Embeds NNG heuristics, WCAG thresholds, typographic systems, motion framework, and anti-pattern catalog. Ships with a full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows) and release automation. Optimization layer (v1.0.4.1, retroactive): gdd-router + gdd-cache-manager skills, PreToolUse budget-enforcer hook, tier-aware agent frontmatter, lazy checker gates, streaming synthesizer, /gdd:warm-cache + /gdd:optimize commands, and cost telemetry at .design/telemetry/costs.jsonl — targeting 50-70% per-task token-cost reduction with no quality-floor regression. v1.20.0 SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream at .design/telemetry/events.jsonl, resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) with rate-limit + 429 + context-overflow recovery, and TypeScript toolchain.",
15
- "version": "1.38.0",
15
+ "version": "1.38.5",
16
16
  "author": {
17
17
  "name": "hegemonart"
18
18
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "get-design-done",
3
3
  "short_name": "gdd",
4
- "version": "1.38.0",
4
+ "version": "1.38.5",
5
5
  "description": "Agent-orchestrated 5-stage design pipeline: Brief → Explore → Plan → Design → Verify. 22+ specialized agents, 9 connections (Figma, Refero, Preview, Storybook, Chromatic, Figma Writer, Graphify, Pinterest, Claude Design), handoff-first workflow via Claude Design bundles, bidirectional Figma write-back (annotations, Code Connect), queryable intel store (`.design/intel/`) for O(1) design surface lookups, and self-improvement loop (reflector agent, frontmatter + budget feedback, global-skills layer at `~/.claude/gdd/global-skills/`). Standalone commands: style, darkmode, compare, figma-write, graphify, handoff, analyze-dependencies, skill-manifest, extract-learnings, reflect, apply-reflections. Embeds NNG heuristics, WCAG thresholds, typographic systems, motion framework, and anti-pattern catalog. Ships with a full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows, lint + schema + frontmatter + stale-ref + shellcheck + gitleaks + injection-scan + blocking size-budget) and release automation (auto-tag + GitHub Release + release-time smoke test). Optimization layer (v1.0.4.1, retroactive): gdd-router + gdd-cache-manager skills, PreToolUse budget-enforcer hook, tier-aware agent frontmatter, lazy checker gates, streaming synthesizer, /gdd:warm-cache + /gdd:optimize commands, and cost telemetry at .design/telemetry/costs.jsonl — targeting 50-70% per-task token-cost reduction with no quality-floor regression. v1.20.0 SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream at .design/telemetry/events.jsonl, resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) with rate-limit + 429 + context-overflow recovery, and TypeScript toolchain. v1.27.7 ships gdd-mcp (Phase 27.7): 12 read-only MCP tools for sub-3s priming. v1.28.0 (Phase 28): Foundational References Tier 2 — 5 new reference files (color-theory, composition, proportion-systems, i18n, contrast-advanced), 2 verifier i18n probes + 1 explore i18n-readiness probe, 12 additive cross-link insertions across 10 existing references, 2 orthogonal audit-scoring lens-tags (composition_alignment + i18n_readiness).",
6
6
  "author": {
7
7
  "name": "hegemonart",
package/CHANGELOG.md CHANGED
@@ -4,6 +4,28 @@ All notable changes to get-design-done are documented here. Versions follow [sem
4
4
 
5
5
  ---
6
6
 
7
+ ## [1.38.5] - 2026-06-01
8
+
9
+ ### Phase 38.5 — Deployment Coordination Loop
10
+
11
+ Bridges the gap between `/gdd:verify` passing and the design **actually being live**. `/gdd:ship` ends at "PR merged"; the post-merge journey (staging → canary % → 100% rollout) was invisible. 38.5 reads the feature-flag service (Phase 38's LaunchDarkly/Statsig/GrowthBook connections), tracks per-cycle rollout %, and weights the `design_arms` posterior by how widely a variant actually deployed. **No new runtime dependency, no new egress** (pure classifier + the Phase-38 read-only connections). **Read-only** — GDD reports + notifies; it never advances or rolls back.
12
+
13
+ ### Added
14
+
15
+ - **`scripts/lib/rollout/rollout-status.cjs`** — pure, dep-free classifier: `classifyRollout` (`unrolled`/`staging-only`/`canary-N%`/`prod-100%`), `deployedPct`, `isStuck` (default 14 days), `deployedWeight` (linear). Deterministic.
16
+ - **`agents/rollout-coordinator.md`** — reads the flag service → classifies → writes `STATE.md <rollout_status>` → emits `rollout_*`/`verify_outcome` events → folds the outcome into `design_arms` weighted by `deployedPct` (a 10%-rolled variant counts 0.1; a 100% one counts 1.0). Read-only, notify-on-stuck.
17
+ - **`skills/rollout-status/SKILL.md`** (`/gdd:rollout-status [<cycle>] [--all] [--stuck]`) — reports rollout state + surfaces stuck rollouts.
18
+ - **`reference/rollout-coordination.md`** — the `<rollout_status>` schema + state transitions + the deployed_pct weighting + the events. Registered.
19
+ - **`reference/schemas/events.schema.json`** — the free-form `type` seed list gains `verify_outcome` / `rollout_started` / `rollout_advanced` / `rollout_stuck` (Phase 22 extension).
20
+
21
+ ### Notes
22
+
23
+ - **No new runtime dependency, no new egress** — pure classifier; the flag-service reads reuse Phase 38's read-only connections.
24
+ - 6-manifest lockstep at **v1.38.5** + `OFF_CADENCE_VERSIONS.add('1.38.5')` + the 29 live-pinned `manifests-version.txt` baselines forward-propagated 1.38.0 → 1.38.5.
25
+ - Inventory relock: skill-list 76 → 77 (+`rollout-status`), agent-list 52 → 53 (+`rollout-coordinator`) + both frontmatter-snapshots, registry-diff 152 → 153, tarball golden 690 → 694 (+4), and the phase-20 `event-schema-snapshot.json` sha256 re-locked (the seed-list edit). Root `SKILL.md` command table + `command-count-sync` updated.
26
+
27
+ ---
28
+
7
29
  ## [1.38.0] - 2026-06-01
8
30
 
9
31
  ### Phase 38 — Outcome-Driven Adaptation (A/B Variants + Inbound User-Research Signals)
package/README.md CHANGED
@@ -174,6 +174,10 @@ Six more AI-native design tools join the connection layer (Phase 14's backlog, n
174
174
 
175
175
  GDD now learns **which design patterns win with users**, not just which pass lint. `/gdd:design --variants N` emits N competing, hypothesis-tagged variants; a new `design_arms` posterior ([`design-arms-store`](scripts/lib/ds-arms/design-arms-store.cjs) — Beta(2,8), distinct from the routing bandit) consults prior outcomes to bias generation (**advisory, never directive**). Two read-only external signal sources close the loop: **A/B experiments** ([LaunchDarkly / Statsig / GrowthBook](connections/launchdarkly.md) → [`experiment-result-ingester`](agents/experiment-result-ingester.md)) and **user research** ([UserTesting / Maze / Hotjar](connections/usertesting.md) → [`user-research-synthesizer`](agents/user-research-synthesizer.md)), the latter **pseudonymized before any agent context** (a tested PII guard). Findings populate the brief's `<prior-research>` block, which verify cross-checks. **No new runtime dependency.** Onboarding 27 → 33.
176
176
 
177
+ ### Deployment coordination (v1.38.5)
178
+
179
+ GDD now tracks a design past "PR merged" to **actually live**. [`/gdd:rollout-status`](skills/rollout-status/SKILL.md) reads the feature-flag service (the Phase 38 LaunchDarkly/Statsig/GrowthBook connections) via [`rollout-coordinator`](agents/rollout-coordinator.md) and classifies each cycle — `unrolled` / `staging-only` / `canary-N%` / `prod-100%` — surfacing **stuck** rollouts (a canary that hasn't advanced in N days). The pure [`rollout-status`](scripts/lib/rollout/rollout-status.cjs) classifier also computes a **deployed-percentage weight** that feeds the `design_arms` posterior via `verify_outcome` events — a variant that only reached 10% of users counts as weak evidence (0.1), a fully-rolled one counts 1.0. **Read-only** (GDD never advances or rolls back) and **no new runtime dependency**.
180
+
177
181
  ### Previous releases
178
182
 
179
183
  - **v1.26.0** — Headless Model Resolver (per-runtime tier→model map, `resolved_models` router field, per-runtime price tables, `reasoning-class` runtime-neutral alias).
package/SKILL.md CHANGED
@@ -101,6 +101,7 @@ Each stage produces artifacts in `.design/` inside the current project.
101
101
  | `benchmark <component\|--wave N\|--list\|--refresh component>` | `get-design-done:gdd-benchmark` | Harvest + synthesize per-component design specs from 18 design systems → `reference/components/<name>.md` |
102
102
  | `export <cycle> --format html\|pdf\|notion [--pseudonymize] [--pr]` | `get-design-done:gdd-export` | Phase 35.5 — package a finished cycle's design output into a stakeholder-shareable artifact (self-contained HTML / Paged.js-print PDF / Notion page); redacts always, `--pseudonymize` masks identity for external sharing, `--pr` posts the HTML preview via pr-commenter |
103
103
  | `bootstrap-ds [--primary <color>] [--secondary <color>] [--tone <tags>] [--framework <t>]` | `get-design-done:gdd-bootstrap-ds` | Phase 37.2 — bootstrap a design system for a GREENFIELD project (no DS): brand input → OKLCH token system (color tints + modular type + 4pt/8pt spacing + radius/motion) in 3 variants to pick, then button/input/card proof scaffolding via `ds-generator` |
104
+ | `rollout-status [<cycle>] [--all] [--stuck]` | `get-design-done:gdd-rollout-status` | Phase 38.5 — track a shipped cycle's production rollout (unrolled / staging-only / canary-N% / prod-100%) by reading the feature-flag service via `rollout-coordinator`; surfaces STUCK rollouts; feeds `design_arms` by deployed %. Read-only — never advances or rolls back |
104
105
 
105
106
  ## Handoff Routing
106
107
 
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: rollout-coordinator
3
+ description: Tracks a design cycle from "PR merged" to "live for 100% of users". Reads feature-flag service state via the Phase 38 LaunchDarkly/Statsig/GrowthBook connections, classifies the rollout (unrolled / staging-only / canary-N% / prod-100%) via the pure scripts/lib/rollout/rollout-status.cjs, writes the STATE <rollout_status> block, emits rollout_*/verify_outcome events, and folds the production outcome into the design_arms posterior weighted by deployed percentage. Read-only — notifies on stuck/rollback, never drives the rollout.
4
+ tools: Read, Bash, Grep, Glob, ToolSearch
5
+ color: green
6
+ default-tier: sonnet
7
+ tier-rationale: "Mechanical classification of flag-service state + a weighted posterior update via pure helpers; no design judgment — sonnet-tier."
8
+ size_budget: M
9
+ size_budget_rationale: "Honest tier sized to the ~100-line body. DELEGATES the classification math to scripts/lib/rollout/rollout-status.cjs, the posterior to scripts/lib/ds-arms/design-arms-store.cjs, the per-service probe to connections/{launchdarkly,statsig,growthbook}.md, and the contract to reference/rollout-coordination.md."
10
+ parallel-safe: false
11
+ typical-duration-seconds: 30
12
+ reads-only: false
13
+ writes:
14
+ - ".design/STATE.md (the <rollout_status> block)"
15
+ - ".design/telemetry/design-arms.json"
16
+ - ".design/intel/insights.jsonl"
17
+ ---
18
+
19
+ @reference/shared-preamble.md
20
+
21
+ # rollout-coordinator
22
+
23
+ ## Role
24
+
25
+ Close the deployment loop: GDD's pipeline ends at "PR merged", but the post-merge journey (staging → canary % → 100%) is invisible. Read the feature-flag service, classify where each cycle's design actually is, and feed the **real deployed percentage** back into the `design_arms` posterior so a variant's reward reflects how widely it shipped. **Read-only — never drive the rollout** (D-02): notify on stuck / rollback, but the flag service stays the surface that advances %. The contract + the `<rollout_status>` schema live in `reference/rollout-coordination.md`.
26
+
27
+ ## When invoked
28
+
29
+ After `/gdd:ship` merges a cycle's PR, and on demand via `/gdd:rollout-status`. Gate on an experiment-source/flag connection being `available` (per `connections/launchdarkly.md` / `statsig.md` / `growthbook.md`); none → `rollout: no flag service configured — skipped.` (degrade-to-noop).
30
+
31
+ ## Step 1 — Read the flag service (read-only)
32
+
33
+ Probe the configured service (ToolSearch MCP, else the platform API key env; injectable read path for hermetic tests). Read the cycle's flag: staging enablement, prod enablement, prod rollout %, and when it last changed. Normalize to `{ stagingEnabled, prodEnabled, prodPercent }` + `daysSinceChange`. Read-only scopes only.
34
+
35
+ ## Step 2 — Classify
36
+
37
+ ```bash
38
+ node -e "const r=require('./scripts/lib/rollout/rollout-status.cjs'); \
39
+ const s=r.classifyRollout(FLAG); \
40
+ console.log(JSON.stringify({ state:s, pct:r.deployedPct(FLAG), stuck:r.isStuck(s, DAYS, THRESHOLD) }))"
41
+ ```
42
+
43
+ `THRESHOLD` = `.design/config.json rollout.stuck_days` (default 14).
44
+
45
+ ## Step 3 — Write STATE + emit events
46
+
47
+ Write the `<rollout_status>` block (cycle, state, deployed_pct, flag_service, last_changed, stuck) per `reference/rollout-coordination.md`. Emit the matching event(s) into `.design/intel/insights.jsonl`: `rollout_started` (first prod exposure), `rollout_advanced` (% up / → 100%), `rollout_stuck` (crossed the threshold). PII-free payloads (cycle/component/pattern/percent only).
48
+
49
+ ## Step 4 — Feed `design_arms` (deployed_pct weighting)
50
+
51
+ When the cycle's variant is in prod and an outcome is known (won/lost per the experiment or a manual call), fold it into the posterior **weighted by deployment**:
52
+
53
+ ```bash
54
+ node -e "const {deployedWeight}=require('./scripts/lib/rollout/rollout-status.cjs'); \
55
+ const {variantKey,observe}=require('./scripts/lib/ds-arms/design-arms-store.cjs'); \
56
+ observe(COMPONENT, variantKey(COMPONENT, PATTERN), { won: WON, weight: deployedWeight(PCT), source: 'verify_outcome' });"
57
+ ```
58
+
59
+ A 10%-rolled variant contributes a 0.1-weight observation; 100% → full weight (D-03). Emit a `verify_outcome` event carrying `deployed_pct` + `weight`. This is a **slow-loop** reward, distinct from internal lint/test signals.
60
+
61
+ ## Stuck handling (notify only)
62
+
63
+ If `stuck`, surface it ("cycle X has been canary-10% for 18 days") and suggest advance-or-rollback. **Do not** auto-advance or roll back — append no `<blocker>`; the human + the flag service own the decision.
64
+
65
+ ## Record
66
+
67
+ Emit a `## Rollout status` summary: per-cycle state, deployed %, stuck flag, and any posterior update (component → pattern → weight). Close with:
68
+
69
+ ```
70
+ ## ROLLOUT COORDINATION COMPLETE
71
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hegemonart/get-design-done",
3
- "version": "1.38.0",
3
+ "version": "1.38.5",
4
4
  "description": "A design-quality pipeline for AI coding agents: brief, plan, implement, and verify UI work against your design system.",
5
5
  "author": "Hegemon",
6
6
  "homepage": "https://github.com/hegemonart/get-design-done",
@@ -986,6 +986,13 @@
986
986
  "type": "heuristic",
987
987
  "phase": 38,
988
988
  "description": "Phase 38 design-variants schema + the design_arms outcome loop: /gdd:design --variants N emits N hypothesis-tagged competing variants (<variant id component pattern hypothesis>); each (component_type, variant_pattern_hash) is a Beta(2,8) arm in scripts/lib/ds-arms/design-arms-store.cjs that learns which patterns win with USERS from A/B (experiment-result-ingester) + user-research (user-research-synthesizer) outcomes. Advisory not directive (the user always wins, D-03). Distinct from the routing bandit."
989
+ },
990
+ {
991
+ "name": "rollout-coordination",
992
+ "path": "reference/rollout-coordination.md",
993
+ "type": "heuristic",
994
+ "phase": 38.5,
995
+ "description": "Phase 38.5 rollout-coordination contract: the <rollout_status> STATE block (unrolled/staging-only/canary-N%/prod-100%), stuck detection (default 14 days), linear deployed_pct weighting feeding design_arms via verify_outcome (a 10%-rolled variant counts 0.1), and the rollout_started/advanced/stuck/verify_outcome events. Classifier scripts/lib/rollout/rollout-status.cjs; agent agents/rollout-coordinator.md; skill /gdd:rollout-status. Read-only — GDD never drives the rollout."
989
996
  }
990
997
  ]
991
998
  }
@@ -0,0 +1,63 @@
1
+ # Rollout Coordination — the `<rollout_status>` contract + the verify→prod loop
2
+
3
+ How GDD tracks a design from "PR merged" to "live for 100% of users", and feeds the **actual deployment percentage** back into the `design_arms` posterior so a variant's reward reflects how widely it was really shipped. The deterministic classifier is `scripts/lib/rollout/rollout-status.cjs`; the orchestration is `agents/rollout-coordinator.md` + `/gdd:rollout-status`. GDD **reads** the feature-flag service (via the Phase 38 LaunchDarkly/Statsig/GrowthBook connections) — it never drives the rollout.
4
+
5
+ ---
6
+
7
+ ## Rollout states
8
+
9
+ A cycle's rollout is classified from a normalized flag state (`{ stagingEnabled, prodEnabled, prodPercent }`):
10
+
11
+ | State | Meaning |
12
+ |---|---|
13
+ | `unrolled` | not in staging or prod |
14
+ | `staging-only` | enabled in staging (or prod-enabled at 0%) — no prod traffic |
15
+ | `canary-N%` | live to N% of prod (0 < N < 100) |
16
+ | `prod-100%` | fully rolled out |
17
+
18
+ `deployedPct(flagState)` returns the live prod percentage (0 when not in prod).
19
+
20
+ ## The `<rollout_status>` STATE block
21
+
22
+ The coordinator writes one block per cycle into `.design/STATE.md`:
23
+
24
+ ```xml
25
+ <rollout_status>
26
+ cycle: 2026-06-checkout-redesign
27
+ state: canary-10%
28
+ deployed_pct: 10
29
+ flag_service: launchdarkly
30
+ last_changed: 2026-05-20
31
+ stuck: false
32
+ </rollout_status>
33
+ ```
34
+
35
+ `state` ∈ the four states above; `deployed_pct` 0–100; `stuck` is `true` when a **partial** rollout (`staging-only`/`canary-N%`) has not advanced for ≥ the threshold.
36
+
37
+ ## Stuck detection
38
+
39
+ `isStuck(state, daysSinceChange, threshold)` — a partial rollout that has not progressed for ≥ `threshold` days (default **14**, configurable via `.design/config.json rollout.stuck_days`). `prod-100%` and `unrolled` are never stuck. `/gdd:rollout-status` surfaces stuck cycles ("canary-10% for 18 days — advance or roll back?"). GDD **notifies**; it does not auto-advance or roll back (read-only — D-02).
40
+
41
+ ## Feeding `design_arms` (deployed_pct weighting)
42
+
43
+ When a cycle's variant reaches prod, the coordinator folds the outcome into the `design_arms` posterior weighted by how widely it deployed (D-03, linear):
44
+
45
+ ```js
46
+ const { deployedWeight } = require('scripts/lib/rollout/rollout-status.cjs');
47
+ const { variantKey, observe } = require('scripts/lib/ds-arms/design-arms-store.cjs');
48
+ observe(component, variantKey(component, pattern),
49
+ { won, weight: deployedWeight(deployed_pct), source: 'verify_outcome' });
50
+ ```
51
+
52
+ `deployedWeight(pct) = pct/100` — a variant rolled to 10% contributes a 0.1-weight observation; a fully-rolled variant contributes 1.0. This keeps the bandit honest: a "win" that only reached 10% of users is weak evidence. `verify_outcome` is a **slow-loop** reward, distinct from internal lint/test signals.
53
+
54
+ ## Events (Phase 22 chain)
55
+
56
+ The coordinator emits free-form `type` events (registered in `reference/schemas/events.schema.json`):
57
+
58
+ - `rollout_started` — first prod exposure (`unrolled`/`staging-only` → `canary-N%`).
59
+ - `rollout_advanced` — canary % increased, or → `prod-100%`.
60
+ - `rollout_stuck` — a partial rollout crossed the stuck threshold.
61
+ - `verify_outcome` — the outcome fed to `design_arms` (carries `deployed_pct` + `weight`).
62
+
63
+ All event payloads are PII-free (cycle id, component, pattern slug, percentages — no user data).
@@ -10,7 +10,7 @@
10
10
  "type": {
11
11
  "type": "string",
12
12
  "minLength": 1,
13
- "description": "Free-form event type identifier. Pre-registered seeds: state.mutation, state.transition, stage.entered, stage.exited, hook.fired, error, capability_gap, kfm-candidate, router_pick."
13
+ "description": "Free-form event type identifier. Pre-registered seeds: state.mutation, state.transition, stage.entered, stage.exited, hook.fired, error, capability_gap, kfm-candidate, router_pick, verify_outcome, rollout_started, rollout_advanced, rollout_stuck."
14
14
  },
15
15
  "timestamp": {
16
16
  "type": "string",
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+ /**
3
+ * scripts/lib/rollout/rollout-status.cjs — Phase 38.5 rollout-state classifier.
4
+ *
5
+ * Pure + dep-free (D-01): zero `require`. Given a NORMALIZED feature-flag state (the
6
+ * rollout-coordinator normalizes LaunchDarkly / Statsig / GrowthBook payloads to this shape),
7
+ * classify the per-cycle rollout state, the deployed percentage, whether a rollout is stuck,
8
+ * and the deployed-weight a `verify_outcome` observation carries into the `design_arms` posterior.
9
+ * Deterministic — same input → same output (hermetic tests, D-07).
10
+ *
11
+ * Normalized flag state:
12
+ * { stagingEnabled: boolean, prodEnabled: boolean, prodPercent: number (0..100) }
13
+ *
14
+ * Rollout states: 'unrolled' | 'staging-only' | 'canary-N%' | 'prod-100%'
15
+ */
16
+
17
+ const STUCK_DEFAULT_DAYS = 14; // D-04
18
+
19
+ function clampPct(n) {
20
+ if (typeof n !== 'number' || !isFinite(n)) return 0;
21
+ return Math.max(0, Math.min(100, n));
22
+ }
23
+
24
+ /** classifyRollout(flagState) → the rollout-state string. */
25
+ function classifyRollout(flagState = {}) {
26
+ const stagingEnabled = !!flagState.stagingEnabled;
27
+ const prodEnabled = !!flagState.prodEnabled;
28
+ const pct = clampPct(flagState.prodPercent);
29
+ if (!prodEnabled || pct === 0) {
30
+ return stagingEnabled || prodEnabled ? 'staging-only' : 'unrolled';
31
+ }
32
+ if (pct >= 100) return 'prod-100%';
33
+ return `canary-${pct}%`;
34
+ }
35
+
36
+ /** deployedPct(flagState) → the live production rollout percentage (0 when not in prod). */
37
+ function deployedPct(flagState = {}) {
38
+ return flagState.prodEnabled ? clampPct(flagState.prodPercent) : 0;
39
+ }
40
+
41
+ /**
42
+ * isStuck(state, daysSinceChange, threshold=14) — a PARTIAL rollout (staging-only / canary-N%)
43
+ * that has not advanced for >= threshold days. A finished (prod-100%) or never-started (unrolled)
44
+ * rollout is never "stuck".
45
+ */
46
+ function isStuck(state, daysSinceChange, threshold = STUCK_DEFAULT_DAYS) {
47
+ if (state === 'prod-100%' || state === 'unrolled') return false;
48
+ const partial = state === 'staging-only' || /^canary-\d+%$/.test(state);
49
+ return partial && typeof daysSinceChange === 'number' && daysSinceChange >= threshold;
50
+ }
51
+
52
+ /**
53
+ * deployedWeight(pct) — the weight a verify_outcome observation carries into design_arms.
54
+ * Linear (D-03): a 10%-rolled variant counts 0.1; 100% counts 1.0. Range [0, 1].
55
+ */
56
+ function deployedWeight(pct) {
57
+ return clampPct(pct) / 100;
58
+ }
59
+
60
+ module.exports = { classifyRollout, deployedPct, isStuck, deployedWeight, clampPct, STUCK_DEFAULT_DAYS };
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: gdd-rollout-status
3
+ description: "Shows where a finished design cycle actually is in production rollout — unrolled / staging-only / canary-N% / prod-100% — by reading the feature-flag service (LaunchDarkly/Statsig/GrowthBook) via the rollout-coordinator. Surfaces STUCK rollouts (a canary that hasn't advanced for N days) and the design_arms outcome weighting. Read-only — GDD never advances or rolls back; it reports and notifies. Use after /gdd:ship to track the post-merge journey."
4
+ argument-hint: "[<cycle>] [--all] [--stuck]"
5
+ user-invocable: true
6
+ tools: Read, Bash, Grep, Glob, ToolSearch, Task
7
+ ---
8
+
9
+ # /gdd:rollout-status
10
+
11
+ Closes the visibility gap after `/gdd:ship`: a PR merges, but staging → canary → 100% rollout happens outside GDD. This skill reports where each cycle's design actually is in production, by delegating to `agents/rollout-coordinator.md` (which reads the feature-flag service via the Phase 38 connections). **Read-only** — it reports + notifies; it never advances or rolls back a rollout. Contract + the `<rollout_status>` schema: `../../reference/rollout-coordination.md`.
12
+
13
+ ## Invocation
14
+
15
+ | Command | Behavior |
16
+ |---|---|
17
+ | `/gdd:rollout-status` | The current cycle's rollout state (from `.design/STATE.md <rollout_status>`, refreshed via the coordinator). |
18
+ | `/gdd:rollout-status <cycle>` | A specific cycle's rollout state. |
19
+ | `/gdd:rollout-status --all` | Every cycle with a `<rollout_status>` block — a rollout dashboard. |
20
+ | `/gdd:rollout-status --stuck` | Only the **stuck** rollouts (partial rollouts that haven't advanced for ≥ the threshold). |
21
+
22
+ ## Steps
23
+
24
+ 1. **Probe the flag service.** Check a flag connection is `available` (`connections/launchdarkly.md` / `statsig.md` / `growthbook.md`). None → print `rollout-status: no flag service configured — connect one via /gdd:connections.` and exit.
25
+ 2. **Delegate to `rollout-coordinator`** (via `Task`): it reads the service, classifies via `scripts/lib/rollout/rollout-status.cjs`, refreshes the `<rollout_status>` block, and reports state + deployed % + stuck.
26
+ 3. **Render.** Show each cycle: `state` · `deployed_pct` · `last_changed` · `stuck?`. For `--stuck`, list only stuck cycles with the days-since-change and an advance-or-rollback suggestion.
27
+ 4. **Do not act.** Never run a flag-service mutation, advance a canary, or roll back — GDD reports; the human + the flag service decide.
28
+
29
+ ## Output
30
+
31
+ End with:
32
+
33
+ ```
34
+ ## ROLLOUT-STATUS COMPLETE
35
+ ```