Command Palette

Search for a command to run...

Arbtr

Command Palette

Search for a command to run...

Decision Relationships

Core Concept

Relationships are the edges in your decision graph. They show how decisions connect.

The Six Relationship Types

Arbtr supports six relationship types. Each has a specific semantic meaning.

TypeMeaningExample
depends_onB requires A to be true"Use TypeScript" depends_on "Use Node.js"
conflicts_withA and B are mutually exclusive"Use MySQL" conflicts_with "Use PostgreSQL"
supersedesB replaces A"Use React 18" supersedes "Use React 17"
enablesA makes B possible"Add auth" enables "Add user profiles"
constrainsA limits options for B"HIPAA compliance" constrains "Data storage"
derived_fromB is based on A"API design" derived_from "REST vs GraphQL"

depends_on vs enables

These two relationships are often confused. Here's the key difference:

depends_on

Technical requirement. The dependent decision literally cannot work without the parent.

"React Query depends_on React" — You can't use React Query without React installed.

enables

Strategic enablement. The first decision opens up possibilities for the second.

"Auth system enables User profiles" — Auth makes profiles possible, but profiles aren't technically dependent on auth.

tip
Ask yourself: "If I removed the first decision, would the second one break at runtime?" If yes, use depends_on. If no (but it wouldn't make strategic sense), use enables.

When to Use Each Type

depends_on

Use when one decision cannot exist without another. The dependent decision assumes the parent decision is true.

Good examples:

  • • "Supabase" depends_on "PostgreSQL" (Supabase requires Postgres)
  • • "React Query" depends_on "React" (library requires framework)
  • • "Deploy to Vercel" depends_on "Next.js" (platform requires framework)
tip
Ask: "If the parent decision changed, would this decision become invalid?" If yes, use depends_on.

conflicts_with

Use when two decisions are mutually exclusive. Approving one effectively rejects the other.

Good examples:

  • • "Use MySQL" conflicts_with "Use PostgreSQL" (can't use both as primary)
  • • "Monolith" conflicts_with "Microservices" (architectural choice)
  • • "REST API" conflicts_with "GraphQL API" (if only one allowed)
!
conflicts_with is symmetric—if A conflicts with B, B conflicts with A. Don't create both directions manually.

supersedes

Use when one decision replaces another. The old decision is effectively deprecated.

Good examples:

  • • "Use React 18" supersedes "Use React 17" (version upgrade)
  • • "New auth system" supersedes "Legacy auth" (replacement)
  • • "Zustand" supersedes "Redux" (library migration)
i
This is key for tracking migrations. The superseding decision should explain why the old approach was replaced.

enables

Use when one decision makes another possible. The enabled decision couldn't happen without the enabler.

Good examples:

  • • "Add auth system" enables "User profiles" (can't have profiles without auth)
  • • "Internationalization" enables "Launch in EU" (requirement for expansion)
  • • "API versioning" enables "Breaking changes safely" (process enablement)

constrains

Use when one decision limits the options for another. The constrained decision must work within boundaries set by the constraint.

Good examples:

  • • "HIPAA compliance" constrains "Data storage choices"
  • • "Budget: $5k/month" constrains "Infrastructure decisions"
  • • "Must support IE11" constrains "Frontend framework choice"

derived_from

Use when one decision is loosely related to another. This is the default for general connections.

Good examples:

  • • "API design guidelines" derived_from "REST vs GraphQL decision"
  • • "Component library choice" derived_from "Design system decision"
  • • "Testing strategy" derived_from "Code quality standards"
tip
When in doubt, use derived_from. It's the least prescriptive relationship and can be refined later.

Visual Representation

In the decision graph, relationships are displayed as colored lines connecting nodes. Each relationship type has a distinct color for easy identification.

Solid Line

Committed relationships in the main graph. These are real, established connections.

Dashed Line

Proposed relationships in a branch. These are hypothetical and not yet merged.

tip
When viewing a branch, look for dashed lines to quickly identify which relationships are being proposed versus which already exist in the main graph.

Technical Details

Directionality

Relationships are stored as directed edges from source_id to target_id. The direction semantics differ by type:

  • depends_on: Target depends on Source (A → B means B depends on A)
  • supersedes: Source replaces Target (A → B means A supersedes B)
  • conflicts_with: Symmetric — if A conflicts with B, B conflicts with A (only store once)
  • enables: Source enables Target (A → B means A enables B)
  • constrains: Source constrains Target (A → B means A constrains B)
  • derived_from: Source is based on Target (A → B means A is derived from B)

Cascade Behavior

When a decision is deleted, all its relationships are also deleted (ON DELETE CASCADE). Archiving preserves relationships but hides them from the default graph view.

Multiple Relationships

You can have multiple relationships between the same two decisions. For example, A can both depend_on and constrains B. Each relationship is stored as a separate row with its own note field.

Data Model

Database table: decision_relationships

lib/types.ts
type RelationshipType =
  | "depends_on"      // Target requires source to be true
  | "supersedes"      // Source replaces target (target is deprecated)
  | "conflicts_with"  // Mutually exclusive (symmetric)
  | "enables"         // Source makes target possible
  | "constrains"      // Source limits options for target
  | "derived_from"    // Source is based on or related to target

interface DecisionRelationship {
  id: string
  source_id: string         // Decision UUID (from)
  target_id: string         // Decision UUID (to)
  type: RelationshipType
  note?: string             // Optional annotation (shown on edge label)
  created_by: string        // User ID who created this relationship
  created_at: Date
  team_id: string           // For RLS

  // Scenario support
  scenario_id?: string      // NULL = live, UUID = ghost in scenario
}

// Graph query returns relationships with decision details
interface RelationshipWithDecisions extends DecisionRelationship {
  source: { id: string; title: string; slug: string; status: DecisionStatus }
  target: { id: string; title: string; slug: string; status: DecisionStatus }
}
i
Relationships are versioned in the audit log. Changes are tracked in decision_audit_logwith event types relationship.dependency_added, relationship.dependency_removed, etc.

Previous

The Graph
    Relationships | Arbtr Docs