Minimal STRUCTURAL shape of the approval stream event this hub fans out.
ACYCLIC LAYERING: approval-api already imports FROM do-runner (e.g.
TENANT_ID_PATTERN), so do-runner must NOT import ApprovalStreamEvent back
from approval-api — that would be a dependency cycle. The hub only reads
event.record.tenantId (the defense-in-depth tenant assertion) and
re-serializes the whole event to subscribers, so this local subset is
sufficient. The real ApprovalStreamEvent (approval-api/contract.ts) is
bridged onto the hub's POST body by host-kit through createHubTopology,
which may import both packages.
Minimal STRUCTURAL shape of the approval stream event this hub fans out.
ACYCLIC LAYERING: approval-api already imports FROM do-runner (e.g. TENANT_ID_PATTERN), so do-runner must NOT import ApprovalStreamEvent back from approval-api — that would be a dependency cycle. The hub only reads
event.record.tenantId(the defense-in-depth tenant assertion) and re-serializes the whole event to subscribers, so this local subset is sufficient. The real ApprovalStreamEvent (approval-api/contract.ts) is bridged onto the hub's POST body by host-kit throughcreateHubTopology, which may import both packages.