skills/decomposing-dags-into-disjoint-chains/SKILL.md
Decompose DAGs into execution chains using width bounds, stratification, virtual nodes, and matching. Use when minimizing workflow lanes in dependency graphs. NOT for cyclic graphs, generic scheduling, or one-off queries with no preprocessing payoff.
npx skillsauth add curiositech/windags-skills decomposing-dags-into-disjoint-chainsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when the important question is not merely whether a dependency graph is valid, but how many independent chains it truly requires and how to assign nodes without inventing fake coordination.
This skill is not the primary tool for:
The width of the DAG, not the raw edge count, tells you the minimum number of chains you must sustain. If the width is six, every "five-lane" design is pretending away real independence.
Layering the DAG creates adjacent-level interfaces where matching can be solved locally. That is what makes the global chain decomposition tractable rather than mystical.
If a node cannot yet be placed without making a brittle decision, keep a virtual placeholder and resolve it later from a better-informed level. Deferred commitment is a design move, not a failure.
At each level transition, use matching to reuse existing chains before opening new ones. Every unmatched node is a justified new lane; every unnecessary lane is coordination tax.
See the deeper visual set in diagrams/INDEX.md.
flowchart TD
A[Dependency graph] --> B{Acyclic after preprocessing?}
B -->|No| C[Stop and condense cycles first]
B -->|Yes| D[Measure width and stratify levels]
D --> E{Need exact minimum chains or practical minimum now?}
E -->|Exact practical minimum| F[Build adjacent-level bipartite matchings]
E -->|Exploratory sizing only| G[Use width as lower bound and sketch lanes]
F --> H{Node cannot be placed safely?}
H -->|Yes| I[Create virtual node and defer]
H -->|No| J[Assign to existing chain]
I --> K[Resolve deferred nodes top-down]
J --> L[Validate resulting chain count against width]
K --> L
Symptoms: the team talks about the longest path when the real pain is too many simultaneous lanes.
Recovery: compute the maximum antichain explicitly and treat that as the coordination floor.
Symptoms: early assignments force unnecessary new chains later.
Recovery: allow virtual nodes and resolve them after more context accumulates.
Symptoms: local assignments are made before levels exist, then "explained" as if they were optimal.
Recovery: stratify first, then solve adjacent-level matching problems.
Symptoms: the proposed decomposition uses fewer chains than the width permits.
Recovery: reject the design immediately; it is violating the partial order, not being clever.
Symptoms: the decomposition is minimal in chains but awful for latency, ownership, or resource balancing.
Recovery: treat chain count as one objective and hand off to a richer scheduler once the structural bound is understood.
A large build graph looks chaotic, but its width is only four. Stratification plus matching shows most work can stay inside four review lanes, with virtual nodes handling late-bound packaging steps. The insight is that the pipeline was noisy, not intrinsically eight-team work.
An orchestrator wants parallel document-analysis agents. The graph of prerequisites reveals width three even though there are dozens of edges. The system creates three stable execution chains and only opens a fourth lane for one unmatched synthesis node that truly cannot share an existing chain.
| File | Load when |
| --- | --- |
| references/width-as-coordination-bound.md | You need the formal lower-bound logic behind lane count. |
| references/stratification-for-local-reasoning.md | You are implementing or reviewing level construction. |
| references/matching-as-resource-allocation.md | You need the matching formulation for chain reuse. |
| references/virtual-nodes-deferred-decisions.md | Deferred assignment and two-phase resolution are the core difficulty. |
| references/correctness-through-induction.md | You need the proof intuition that local steps compose globally. |
| references/compression-through-decomposition.md | The main goal is reachability compression rather than workflow design. |
data-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.