{"id":50370133,"url":"https://github.com/binaryphile/sofdevsim-2026","last_synced_at":"2026-05-30T06:31:06.855Z","repository":{"id":346230617,"uuid":"1127034980","full_name":"binaryphile/sofdevsim-2026","owner":"binaryphile","description":"Software development simulation - DORA vs TameFlow experiment","archived":false,"fork":false,"pushed_at":"2026-05-26T02:57:01.000Z","size":1468,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T04:33:05.171Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/binaryphile.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-03T03:32:36.000Z","updated_at":"2026-05-26T02:57:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/binaryphile/sofdevsim-2026","commit_stats":null,"previous_names":["binaryphile/sofdevsim-2026"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/binaryphile/sofdevsim-2026","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsofdevsim-2026","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsofdevsim-2026/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsofdevsim-2026/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsofdevsim-2026/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/binaryphile","download_url":"https://codeload.github.com/binaryphile/sofdevsim-2026/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binaryphile%2Fsofdevsim-2026/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33682998,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-30T06:31:06.122Z","updated_at":"2026-05-30T06:31:06.849Z","avatar_url":"https://github.com/binaryphile.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Software Development Simulation\n\nSimulate software delivery to test DORA vs TameFlow sizing strategies.\n\n## Why This Matters\n\nTeams argue endlessly about sizing:\n- *\"Just break it down into smaller pieces\"*\n- *\"We need to understand it better first\"*\n\n**DORA research** says batch size matters: tickets taking longer than one week correlate with worse delivery outcomes.\n\n**TameFlow** argues that cognitive load (understanding level) is the real discriminant: uncertain work causes variance regardless of size.\n\nThis simulation lets you test both hypotheses with data.\n\n## The Experiment\n\n| Policy | Rule | Theory |\n|--------|------|--------|\n| **DORA-Strict** | Decompose tickets \u003e 5 days | Time-based ceiling reduces batch size |\n| **TameFlow-Cognitive** | Decompose tickets with Low understanding | Reducing uncertainty improves predictability |\n| **Hybrid** | Both conditions | Belt and suspenders |\n| **None** | No decomposition | Baseline |\n\nRun the same scenario under each policy. Compare DORA metrics. See which approach wins.\n\n## Features\n\n- **8-phase workflow** (Research → Sizing → Planning → Implement → Verify → CI/CD → Review → Done)\n- **4 sizing policies** with automatic decomposition\n- **Variance model** (understanding level → outcome predictability)\n- **DORA metrics dashboard** with ntcharts sparklines\n- **Fever chart** (buffer consumption: Green/Yellow/Red)\n- **A/B policy comparison** with identical seeds for reproducibility\n\n## How It Works\n\nThe simulation's core insight: **understanding level determines predictability**.\n\n| Understanding | Variance | What Happens |\n|---------------|----------|--------------|\n| **High** | ±5% | Ticket completes close to estimate |\n| **Medium** | ±20% | Some surprises, moderate slippage |\n| **Low** | ±50% | Frequent surprises, major slippage possible |\n\nThis is why TameFlow-Cognitive often beats DORA-Strict: decomposing by *uncertainty* (Low understanding) reduces variance more than decomposing by *size* (\u003e5 days).\n\n**Example:** A 3-day ticket with Low understanding has more variance (1.5-4.5 days) than a 6-day ticket with High understanding (5.7-6.3 days). DORA-Strict would decompose the 6-day ticket but leave the risky 3-day ticket alone.\n\n## Screenshot\n\n```\n┌──────────────────────────────────────────────────────────────────────────────┐\n│  Planning   Execution   Metrics   Comparison      Policy: DORA-Strict │ Day 5│\n├──────────────────────────────────────────────────────────────────────────────┤\n│ Backlog (8 tickets)                              │ Team                      │\n│ ────────────────────────────────────────────────│                           │\n│ ID       Title                        Est  Understanding  Phase             │ Alice (v:1.0) [busy] → TKT-001 │\n│ ▶TKT-002 Implement auth flow         4.5d Medium         Backlog           │ Bob (v:0.8)   [idle]           │\n│  TKT-003 Add logging middleware      2.0d High           Backlog           │ Carol (v:1.2) [busy] → TKT-004 │\n│  TKT-005 Refactor database layer     8.2d Low            Backlog           │                                │\n│  TKT-006 Write API documentation     1.5d High           Backlog           │                                │\n│  TKT-007 Fix memory leak             3.0d Medium         Backlog           │                                │\n└──────────────────────────────────────────────────────────────────────────────┘\n\n┌─ Execution View ─────────────────────────────────────────────────────────────┐\n│ Sprint 1                                                                     │\n│ Day 5/10  [████████░░░░░░░░░░░░] 50%                                        │\n│                                                                              │\n│ Active Work                                                                  │\n│ Alice    → TKT-001   [████████████░░░░░░░░] 60% (Implement)                 │\n│ Bob      [idle]                                                              │\n│ Carol    → TKT-004   [██████░░░░░░░░░░░░░░] 30% (Verify)                    │\n│                                                                              │\n│ ┌─ Fever Chart ──────────────┐  ┌─ Events ─────────────────────────────────┐│\n│ │ Buffer: [████░░░░░░] 38%   │  │ Day 5: TKT-001 entered Implement phase  ││\n│ │ 0.8 / 2.0 days remaining   │  │ Day 4: Bug found in TKT-004 (+0.5d)     ││\n│ │ Status: GREEN              │  │ Day 3: TKT-003 completed                ││\n│ └────────────────────────────┘  │ Day 2: Sprint 1 started                 ││\n│                                 └──────────────────────────────────────────┘│\n└──────────────────────────────────────────────────────────────────────────────┘\n\n┌─ Metrics View ───────────────────────────────────────────────────────────────┐\n│ DORA Metrics                                                                 │\n│                                                                              │\n│   Lead Time       Deploy Freq      MTTR            Change Fail Rate         │\n│   2.3 days        0.43/day         1.2 days        8.3%                     │\n│   ▂▃▄▃▂▃▄▅▆▅▄▃   ▁▂▂▃▃▄▄▅▅▆▆▇   ▇▆▅▄▃▃▂▂▁▁▁   ▅▄▄▃▃▂▂▂▁▁▁               │\n│   ↓ lower better  ↑ higher better  ↓ lower better  ↓ lower better           │\n└──────────────────────────────────────────────────────────────────────────────┘\n\n┌─ Comparison View ────────────────────────────────────────────────────────────┐\n│ Policy Comparison Results                                                    │\n│ Seed: 1704067200  |  Sprints: 3  |  Same backlog \u0026 team                     │\n│                                                                              │\n│ Metric               DORA-Strict    TameFlow-Cognitive    Winner            │\n│ ─────────────────────────────────────────────────────────────────           │\n│ Lead Time                   3.2d                  2.8d    TameFlow ✓        │\n│ Deploy Frequency         0.38/d                0.42/d    TameFlow ✓        │\n│ MTTR                       1.5d                  1.1d    TameFlow ✓        │\n│ Change Fail Rate          12.5%                  8.2%    TameFlow ✓        │\n│                                                                              │\n│ WINNER: TameFlow-Cognitive (4-0 on DORA metrics)                            │\n│                                                                              │\n│ Experiment suggests: COGNITIVE LOAD decomposition led to better outcomes.   │\n│ • Lead time improved by 0.4 days (13% faster)                               │\n│ • Change fail rate reduced by 4.3% points                                   │\n│ • Understanding level is a stronger discriminant than time estimate         │\n└──────────────────────────────────────────────────────────────────────────────┘\n\nKeybindings: [a]ssign [d]ecompose [p]olicy [s]tart sprint | Tab:view Space:pause +/-:speed [c]ompare [e]xport [q]uit\n```\n\n## Quick Start\n\n### With Nix\n\n```bash\nnix develop\ngo run cmd/sofdevsim/main.go\n```\n\n### Without Nix\n\n```bash\ngo mod download\ngo run cmd/sofdevsim/main.go\n```\n\n## CLI Flags\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `--seed` | 0 | Random seed for reproducibility (0 = use current time) |\n| `--api-port` | 8080 | HTTP API port |\n| `--mix` | `healthy` | Backlog mix profile (see \"Backlog Mix Profiles\" below) |\n| `--phase-wip` | none | Per-phase WIP caps as `phase=cap,...` (see \"Per-Phase WIP Caps\" below) |\n| `--phase-wip-profile` | `uncapped` | Bundled WIP profile shortcut (`uncapped` or `balanced`) |\n| `--release-mode` | `push` | Release controller mode (`push` or `demand`; see \"Demand-Driven Release\" below) |\n\n**Example:** Run with fixed seed for reproducible results:\n```bash\ngo run cmd/sofdevsim/main.go --seed 42\n```\n\n## Backlog Mix Profiles\n\nThe `--mix` flag selects a named backlog generation profile. Mix profiles control how the simulation's initial backlog is composed across ticket types (UC37: heterogeneous ticket types). Each ticket type has a different phase-effort distribution, so changing the mix can shift the system's bottleneck phase.\n\n| Profile | Ticket types | Use for |\n|---|---|---|\n| `healthy` (default) | all Feature | Today's baseline — homogeneous backlog, regression-safe default |\n| `overloaded` | all Feature | Existing: high WIP stress, all-Feature |\n| `uncertain` | all Feature | Existing: high Low-understanding variance, all-Feature |\n| `mixed` | all Feature | Existing: varied understanding/estimate/priority, all-Feature (name predates UC37) |\n| `uc37-default` | 60% Feature / 25% Bug / 10% Spike / 5% Migration | Demonstrates a moderately mixed backlog with Implement-dominant aggregate |\n| `bug-heavy` | 30% F / 50% Bug / 5% Spike / 10% Migration / 5% Infra | Bug-fix-heavy quarter |\n| `migration-quarter` | 30% F / 15% B / 5% Spike / 45% Migration / 5% Infra | Migration-heavy quarter (Verify-shifting) |\n| `infra-push` | 35% F / 15% B / 5% Spike / 10% Migration / 35% Infra | Infra/platform-heavy quarter (CI/CD-shifting) |\n| `research-shop` | 5% F / 5% B / 85% Spike / 0% Migration / 5% Infra | Heavy-research-mode shop (Research-dominant aggregate; useful contrast to uc37-default) |\n\n**Example:** Run a comparison between contrasting mixes:\n```bash\ngo run cmd/sofdevsim/main.go --seed 42 --mix uc37-default\ngo run cmd/sofdevsim/main.go --seed 42 --mix research-shop\n```\n\nUnknown mix names are rejected at startup with a diagnostic listing registered scenarios. Mix profile selection is also available via the REST API: `POST /simulations` accepts an optional `scenarioName` field (default `healthy`).\n\nSee `docs/design.md` §\"Heterogeneous Ticket Types (UC37)\" for per-type phase-effort distributions and the design rationale.\n\n## Per-Phase WIP Caps\n\nThe `--phase-wip` flag (or `--phase-wip-profile` shortcut) caps how many concurrent tickets each phase may host. Cap-blocked queues surface as head-of-line blocking in the new Phase Queues panel (UC38: per-phase WIP caps).\n\n| Profile | Research | Sizing | Planning | Implement | Verify | CI/CD | Review | Use case |\n|---|---:|---:|---:|---:|---:|---:|---:|---|\n| `uncapped` (default) | nil | nil | nil | nil | nil | **2 (via CICDSlots)** | nil | Most-regression-safe; nil = unlimited; CI/CD effective cap of 2 reflects the existing `CICDSlots` declaration now wired into the cap path |\n| `balanced` | nil | nil | nil | 4 | 2 | 1 | 2 | Demonstrates head-of-line blocking under heterogeneous mix; CI/CD=1 (explicit, overrides CICDSlots fallback) |\n\n**Example:** Run with explicit per-phase caps:\n```bash\ngo run cmd/sofdevsim/main.go --seed 42 --mix uc37-default \\\n  --phase-wip Implement=4,Verify=2,CICD=1,Review=2\n```\n\nThe flag's phase-name parser accepts the canonical phase names (`Research`, `Sizing`, `Planning`, `Implement`, `Verify`, `CI/CD`, `Review`) AND the slash-free `CICD` alias for `CI/CD` (parser-friendly); matching is case-insensitive. Invalid configs are rejected at simulation startup with a typed diagnostic identifying the failing phase, the cap value, and the rule that was violated. The four diagnostic categories are:\n\n| Sentinel | Trigger |\n|---|---|\n| `ErrCapZero` | Any cap = 0 — would deadlock that phase |\n| `ErrCapNegative` | Any cap \u003c 0 — semantic error |\n| `ErrCapBelowMentorMin` | `Implement` cap \u003c 2 — mentor-pair minimum |\n| `ErrCapConflict` | Per-phase cap exceeds the aggregate rope-style WIP ceiling on the Implement→Review span |\n\nPer-phase caps are also available via the REST API: `POST /simulations` accepts an optional `phaseWIPConfig` object field (e.g., `{\"Implement\": 4, \"Verify\": 2}`). Validation errors return HTTP 422 (Unprocessable Entity) with sentinel-differentiated diagnostics.\n\n**Behavior-change note**: pre-UC38 the `CICDSlots` field was declared but never enforced. Post-UC38, `PhaseWIPCap(CICD)` falls back to `CICDSlots` (default 2), so CI/CD throughput is now bound to ≤ 2 concurrent tickets in the absence of an explicit override. For typical mixes (CI/CD phase effort ≈ 5%) this is invisible; for CI/CD-bound pathological runs it surfaces as observable head-of-line blocking on the CI/CD queue.\n\nSee `docs/design.md` §\"Per-Phase WIP Caps (UC38)\" for the schema, dual-checkpoint enforcement, and direct-CICDSlots-reader migration notes.\n\n## Demand-Driven Release\n\nThe `--release-mode` flag selects between two release controllers (UC39: demand-driven release):\n\n| Mode | Behavior |\n|---|---|\n| `push` (default) | Current commit-then-flow behavior — `StartSprint` commits to capacity; assignment + phase-advance flow as today. Zero-value default for regression-safety |\n| `demand` | `StartSprint` skips bulk-commit; release controller drips one ticket per tick when downstream headroom permits. Warm-up phase forces push behavior until the TOC analyzer locks a constraint with at least medium confidence |\n\n**Example:** Run in demand mode for the same backlog as a push baseline:\n```bash\ngo run cmd/sofdevsim/main.go --seed 42 --mix uc37-default --release-mode demand\ngo run cmd/sofdevsim/main.go --seed 42 --mix uc37-default --release-mode push\n```\n\nAggregate WIP under demand mode should be materially lower (UC39 §Postconditions/Success); verifiable from the `avg_wip` column in `sprints.csv` exports.\n\n**Mode indicator**: the TUI header displays one of 4 states:\n- `Mode: push` — push mode (zero-value default)\n- `Mode: demand (warming)` — warmup running (waiting for analyzer lock)\n- `Mode: demand (push fallback)` — warmup-timeout fired (sim falls back to push behavior; terminal for the run)\n- `Mode: demand` — post-warmup-exit (release controller is dripping)\n\n**Headroom formula**: `floor((1 - Buffer.Penetration) × MaxBacklogDrip)`. With MaxBacklogDrip default 1, fully-green admits 1 ticket/tick; fully-red (Penetration=1.0) throttles to 0.\n\n**Warmup-timeout**: hard-coded to N=5 sprints. If the TOC analyzer can't lock a constraint within 5 sprints (e.g., on a degenerate mix), the `WarmupTimedOut` event fires, `WarmupFailed` becomes true, and the sim falls back to effective push behavior for the rest of its life. The TUI Mode indicator reflects this as `demand (push fallback)`.\n\nValidation errors map to:\n\n| Sentinel | Trigger |\n|---|---|\n| `ErrInvalidReleaseMode` | Unknown mode name (e.g., `--release-mode garbage`); HTTP 422 from REST |\n| `ErrAnalyzerNotReady` | Defensive guard — controller called before analyzer has any ticks |\n| `ErrWarmupTimeout` | Returned (non-fatal) by the release controller alongside the `WarmupTimedOut` event |\n\nDemand mode is also available via the REST API: `POST /simulations` accepts an optional `releaseMode` field. Invalid mode values return HTTP 422.\n\nSee `docs/design.md` §\"Demand-Driven Release (UC39)\" for the state machine, ShouldAdmit pseudocode, and warmup-exit-vs-timeout race resolution.\n\n## Investment Moves\n\nBetween sprints, the operator spends a finite **Budget** on capacity-changing investments targeted at the analyzer-identified constraint (UC40: closes the 5FS EXPLOIT/ELEVATE game loop). The investment window opens automatically when a sprint ends; press 's' to start the next sprint (which closes the window).\n\n**Starting budget**: 10. **Per-option costs**:\n\n| Option | Cost | Effect |\n|---|---:|---|\n| `hire` (Hire developer) | 5 | Adds a new developer (auto-generated ID; default velocity 1.0) |\n| `cicd-slot` (Buy CI/CD slot) | 3 | Increments CI/CD pipeline-slot count (works with UC38's PhaseWIPCap fallback) |\n| `review-tool` (Upgrade Review tooling) | 2 | Multiplies Review-phase velocity by 1.2 (stacks across investments) |\n| `verify-paydown` (Pay down Verify tech debt) | 2 | Multiplies Verify-phase variance by 0.8 (stacks; lower = less variance) |\n\n**Budget: $N** is always visible in the TUI header alongside Mode and Policy.\n\n**TUI**: When the investment window is open, the Execution view body renders numbered options `[1]Hire($5) [2]CICDSlot($3) [3]ReviewTool($2) [4]VerifyPaydown($2)` (grayed when unaffordable). Press 1–4 to spend the corresponding option.\n\n**REST**: `POST /simulations/{id}/investments` with body `{\"option\": \"hire|cicd-slot|review-tool|verify-paydown\"}`. Returns updated sim state on success.\n\nValidation errors map to:\n\n| Sentinel | Trigger |\n|---|---|\n| `ErrInsufficientBudget` | Cost \u003e remaining budget; HTTP 422 |\n| `ErrInvalidInvestment` | Unknown option name; HTTP 422 |\n| `ErrInvestmentWindowClosed` | Spend called mid-sprint OR before first sprint; HTTP 409 |\n\n**Atomicity**: each investment is a single `InvestmentApplied` event — budget debit + capacity change applied atomically in the projection handler. CSV `sprints.csv` exports `budget_remaining` + `investment_applied` columns per sprint.\n\nSee `docs/design.md` §\"Investment Moves (UC40)\" for the state machine, options table, and 5FS-loop wiring.\n\n## HTTP API\n\nThe TUI and HTTP API share the same simulation state. Control the TUI's simulation programmatically via REST:\n\n```bash\n# List simulations (find the TUI's simulation ID)\ncurl http://localhost:8080/simulations\n\n# Assign a ticket\ncurl -X POST http://localhost:8080/simulations/{id}/assignments \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"ticketId\": \"TKT-001\"}'\n\n# Start sprint\ncurl -X POST http://localhost:8080/simulations/{id}/sprints\n\n# Advance one tick\ncurl -X POST http://localhost:8080/simulations/{id}/tick\n\n# Run policy comparison\ncurl -X POST http://localhost:8080/comparisons \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"seed\": 42, \"sprints\": 3}'\n```\n\nThe API follows HATEOAS - responses include `_links` showing available actions based on current state.\n\nSee [docs/design.md](docs/design.md) for full API documentation.\n\n### Same-process co-tenancy (TUI + REST)\n\nWhen the TUI and REST API run in the same process (default mode), the TUI auto-tick yields to REST writers per UC10's single-writer principle. **Observable state**: when a REST writer has been observed during the session, the TUI header renders a `[READ-ONLY]` badge and keeps rendering it until process restart. The badge is the load-bearing operational signal:\n\n- **Badge visible** → auto-tick is suppressed; TUI is consuming the event stream as a projection. Safe to issue REST writes; the TUI will reflect changes.\n- **Badge absent** → no REST writer has been observed in this session. TUI auto-tick still active.\n\n**Limitations:**\n\n- The badge-latched state is **one-way** — once `[READ-ONLY]` appears, the TUI remains read-only until process restart (deliberate per UC10's conservative read of \"TUI becomes a read-only projection\"). Restart the TUI process to recover the writer role.\n\n**Complete safety contract** (closed via #18913): When the `[READ-ONLY]` badge is visible, ALL TUI mutation keypresses (`s`/start-sprint, `a`/assign, `d`/decompose, `p`/policy, `1`-`4`/invest) are gated — they record a status message + `*Attempted{Failed{Conflict}}` event but do NOT write to the engine. The badge is now a complete safety signal. SpendInvestment (`1`-`4`) uses status-message-only (no event); the other 4 actions record events in `app.uiProjection`.\n\n**Resize artifacts**: If the TUI's rendering appears corrupted after an interactive `tmux split-window` mid-session (partial redraw, blank rows), press **Ctrl+L** to force a full redraw (UC34 workaround). The root cause is environmental (tmux + alt-screen + SIGWINCH interaction); scripted `tmux resize-window` does NOT reproduce the symptom.\n\n## Tutorial\n\nFor a hands-on walkthrough with checkpoints, see [docs/tutorial.md](docs/tutorial.md).\n\n## Usage\n\n### Views\n\nPress **Tab** to switch between views:\n\n| View | Shows |\n|------|-------|\n| **Planning** | Backlog, team status, ticket assignment |\n| **Execution** | Active work, fever chart, event log |\n| **Metrics** | DORA dashboard, sparklines, completed tickets |\n| **Comparison** | A/B policy test results |\n\n### Keybindings\n\n| Key | Action | Available In |\n|-----|--------|--------------|\n| **Tab** | Switch view | All |\n| **Space** | Pause/resume simulation | Execution |\n| **+/-** | Adjust simulation speed | Execution |\n| **p** | Cycle sizing policy | Planning |\n| **s** | Start sprint | Planning |\n| **a** | Assign selected ticket to developer | Planning |\n| **d** | Decompose selected ticket | Planning |\n| **c** | Run policy comparison | All |\n| **e** | Export data to CSV | All (after sprints complete) |\n| **j/k** or **↑/↓** | Navigate backlog | Planning |\n| **Ctrl+L** | Force full screen redraw (UC34 workaround) | All |\n| **q** | Quit | All |\n\n### Typical Workflow\n\n1. Launch the simulation (starts in Planning view)\n2. Press **a** to assign tickets to developers\n3. Press **s** to start a sprint\n4. Watch the simulation run in Execution view\n5. Press **Tab** to check Metrics view\n6. Press **c** to run a DORA vs TameFlow comparison\n\n## Understanding the Results\n\n### DORA Metrics\n\n| Metric | Meaning | Better |\n|--------|---------|--------|\n| **Lead Time** | Time from start to deploy | Lower |\n| **Deploy Frequency** | Deploys per day | Higher |\n| **MTTR** | Mean time to recover from incidents | Lower |\n| **Change Fail Rate** | Incidents per deploy | Lower |\n\n### Fever Chart\n\n| Color | Buffer Used | Meaning |\n|-------|-------------|---------|\n| **Green** | \u003c 33% | On track |\n| **Yellow** | 33-66% | At risk |\n| **Red** | \u003e 66% | Over budget |\n\n### Comparison Mode\n\nWhen you press **c**, the simulation:\n1. Generates a fresh backlog with a random seed\n2. Runs 3 sprints with DORA-Strict policy\n3. Runs 3 sprints with TameFlow-Cognitive policy (same seed)\n4. Compares the four DORA metrics\n5. Declares a winner and explains why\n\n### Data Export\n\nPress **e** to export simulation data for external analysis. Creates a timestamped directory with CSV files:\n\n```\nsofdevsim-export-20260103-143052/\n├── metadata.csv      # Seed, policy, timestamp\n├── tickets.csv       # Per-ticket variance vs theoretical bounds\n├── sprints.csv       # Buffer consumption, WIP (TOC)\n├── incidents.csv     # Per-incident MTTR detail\n├── metrics.csv       # DORA metrics summary\n└── comparison.csv    # Policy comparison (if run)\n```\n\n**Sample tickets.csv row:**\n```csv\nticket_id,understanding,estimated_days,actual_days,variance_ratio,expected_var_min,expected_var_max,within_expected,...\nTKT-001,Medium,4.5,5.2,1.16,0.80,1.20,true,...\n```\n\nThe `within_expected` column shows whether actual variance fell within theoretical bounds—making hypothesis validation as simple as `=COUNTIF(within_expected, \"true\")`.\n\n**Use cases:**\n- **Validate the variance model**: Check if actual variance falls within theoretical bounds (High ±5%, Medium ±20%, Low ±50%)\n- **Test the sizing hypothesis**: Run multiple comparisons, export each, analyze statistically\n- **Teach TOC principles**: Project the CSV in a workshop to show buffer consumption patterns\n\n## Architecture\n\n```\ncmd/sofdevsim/main.go    # Entry point\ninternal/\n  tui/                   # Bubbletea views\n  engine/                # Simulation logic\n  metrics/               # DORA calculations\n  model/                 # Domain types\n```\n\nSee [docs/design.md](docs/design.md) for detailed architecture and algorithms.\n\nSee [docs/use-cases.md](docs/use-cases.md) for user scenarios.\n\n## License\n\nMIT License\n\nCopyright (c) 2026\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinaryphile%2Fsofdevsim-2026","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinaryphile%2Fsofdevsim-2026","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinaryphile%2Fsofdevsim-2026/lists"}