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.
Creating a blocking fact:merged edge refuses with
dependency_blocker_already_landed when the blocker has a recorded landing and
its pinned workflow places it past code work (release or terminal). The refusal
names the blocker and landing; no merge dependency is needed. Reopened code work
can take a new edge before its next landing. Existing edges keep their creation
time and evaluation rules; coordination-only records and other satisfaction
conditions are unaffected.
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 or staff yet (checked before advancing toimplementing)integration-- work, test and open the pull request now; merge only after the condition clearsclosure-- work and merge now; close only after the condition clearscoordination_only-- attested independent overlap; no lifecycle wait
Release creation, batch compatibility and carried-item enrollment ignore closure
edges. They still enforce activation and integration edges. Member close-out
checks closure before writing done, so a release may wait at settling for a
closure blocker instead of refusing creation.
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 only while an activation/integration/closure edge is unsatisfied and names only unsatisfied blockers. Wait for the blocking item, or remove the edge with yoke items dependency remove; satisfied edges permit an unrelated hold. 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.
Wait on another item's merge or delivery
Record the wait first, then park only at the step the gate holds. Name the
skill you are working in as the source (dash, conduct, implement, …);
operator is for steering.
yoke items dependency list ITEM
yoke items dependency add ITEM BLOCKER dash --gate-point integration \
--satisfaction fact:merged --rationale "needs BLOCKER merged"
yoke sessions touch --mode parked --reason "awaiting BLOCKER merge"
Add the edge before the landing you need; an earlier landing does not count.
Park only after the write succeeds, and keep your claim and lane while you
wait. The blocker's landing or delivery wakes you. Your own item's release
wait needs no edge. After failed QA, record a closure edge only when the
finding is in your own item and another item must land first;
yoke items dependency add --help says which satisfaction to use.