Item dependency model
Read dependency edges, gate satisfaction and the canonical blocker model.
Table: item_dependencies
Inter-item edge authority. Use yoke items dependency add and yoke items dependency list; read their --help before authoring. Activation, integration and closure edges enforce directional waits. coordination_only records an attested independent-overlap decision and does not block. Claims/dependency reconciliation lives in path-claims.md.
id INTEGER PRIMARY KEY
dependent_item_id INTEGER NOT NULL REFERENCES items(id)
blocking_item_id INTEGER NOT NULL REFERENCES items(id)
gate_point TEXT NOT NULL DEFAULT 'activation' -- activation | integration | closure | coordination_only
satisfaction TEXT NOT NULL DEFAULT 'status:done' -- status:<stage-id> | fact:merged | fact:deployed:<environment-name>
source TEXT NOT NULL -- shepherd | conduct | operator | migration | feed | idea | refine | dash
session_id TEXT -- nullable; the session that added or last changed the edge
rationale TEXT NOT NULL DEFAULT '' -- human-readable explanation of the edge
evidence_json TEXT NOT NULL DEFAULT '{}' -- structured provenance payload
created_at TIMESTAMPTZ NOT NULL
UNIQUE(dependent_item_id, blocking_item_id, gate_point)
Storage is integer foreign keys to items.id. Public PREFIX-N remains
the API and display token (yoke items dependency list PREFIX-N
projects direction / other_item). Cross-project edges store the
counterpart's internal id and still list as that project's prefix.
Indexes:
idx_id_dependent ON item_dependencies(dependent_item_id)idx_id_blocking ON item_dependencies(blocking_item_id)
yoke items dependency add on an existing edge updates it in place (source, rationale,
satisfaction, evidence) and replies with the stored row: created dependency #N,
updated existing dependency #N: <field> old -> new, or unchanged: existing dependency #N.
update also accepts --source and --evidence. Updates preserve created_at; to wait for another landing after an already satisfied edge, remove that edge and add a new one before the next landing.
Canonical blocker model
Activation, integration and closure edges have directional meaning: the dependent cannot pass that gate until the blocker satisfies the condition. Coordination-only edges are excluded from blocker evaluation.
Gate point (gate_point) -- when in the dependent's lifecycle the dependency is enforced:
activation-- do not start the dependent yet (checked before advancing toimplementing)integration-- may work in parallel, but the dependent must land (merge) after the blockerclosure-- the dependent may not close before the blocker satisfies its conditioncoordination_only-- attested independent overlap; no lifecycle wait
Satisfaction condition (satisfaction) -- what must be true about the blocker:
status:<stage-id>-- blocking item must reach that stage in its pinned workflow. Usestatus:donefor the usual item-to-item wait, including required deployment and closeout. Authoring a stage that workflow version does not have refuses and lists the stages it doesfact:merged-- a blocker atdonesatisfies the edge regardless of its age. For an unfinished blocker, its recorded landing (merged_at) must be strictly after this edge'screated_at; earlier landings, branch ancestry and other lifecycle statuses do not clear the waitfact:deployed:<environment-name>-- the blocker must be done and its delivery stamp must attribute completion to that registered environment. The persisted attribution names the exact run, member, environment, project and candidate, including source-bound cross-project delivery. Readers never re-check current whole-run status or QA acceptance; subsequent sibling failure or cancellation leaves completed delivery satisfied. Ordinary completion dependencies usestatus:doneand ignore run and environment.
Explanation fields:
rationale-- short human-readable reason for the edge (e.g., "Operator-declared activation dependency")evidence_json-- structured evidence/provenance payload (e.g.,{"created_by":"operator"})
Evaluation owner: yoke_core.domain.dependency_planning shares single-item
gate evaluation, batched frontier evaluation and topologically ordered
candidate planning. Registered readers return structured blockers; internal
Python service clients are not an agent recipe.
Enforcement: advance.preflight.hard_blocks exposes the shared evaluate_blockers evaluator through yoke advance preflight hard-blocks PREFIX-N --gate-point activation. It evaluates on the selected control plane over HTTPS or local Postgres. implement / conduct / usher share it. The authoritative status write runs it for listed check_hard_blocks at activation, and on every write to done at closure (not skippable by force or QA bypass). items.block refuses a wait a live activation/integration/closure edge already carries — use yoke items dependency add. The frontier uses evaluate_batch_gates() for activation.
Loop refusal: items.dependency.add and items.dependency.update (when it changes the gate or satisfaction) refuse with dependency_cycle a write that would leave unsatisfied activation/integration/closure edges among live items in a loop, because no item in it could move first. The refusal names every edge in the loop with its id, the items it would strand, and the recovery: make one edge coordination_only (yoke items dependency update DEPENDENT BLOCKING --match-gate-point GATE --gate-point coordination_only --rationale TEXT), or route the ordering decision to steering. Nothing is written. coordination_only edges, satisfied edges and terminal dependents never count. yoke_core.domain.dependency_cycles is the one detector: frontier.list and charge.schedule serve its loops as dependency_cycles, the fleet watch raises fleet ALARM deadlock, and the steering report lists them under dependency deadlocks.