`bynk.tier.*` and `bynk.stub.*` errors
These diagnostics come from the tier dial (the as <tier> clause) and from
stub test doubles (v0.118). See Test tiers,
the stub reference, and the
tiers reference.
A tier on a property
Section titled “A tier on a property”[bynk.parse.expected_token] expected `{` to open the property body, found `as`Cause: an as <tier> clause is attached to a property header. Tiers are a
case-only clause, so the grammar has no place for one on a property. A
property generates its subjects and does not promote — promoting it would
multiply generation by real-collaborator cost and re-admit the ambient
nondeterminism a tier removes.
Fix: remove the tier from the property. A suite-level as binds its case
members only, so a property under a tiered suite is fine. To check a generated
input end to end, promote that witness as a concrete case … as integration.
bynk.tier.system_needs_wire
Section titled “bynk.tier.system_needs_wire”[bynk.tier.system_needs_wire] a `system` case must span at least two contexts, but only `shop.orders` is reachedCause: a case as system’s inferred participant set — the unit under test plus
its transitive consumes closure — is fewer than two contexts. system describes
the cross-context, wired tier, so it needs a wire to cross.
Fix: if the flow genuinely stays within one context, use as integration (real
collaborators, one context, no wire) instead. If it should cross a boundary, make
sure the unit under test actually consumes the other context — participants are
inferred from that graph, never listed.
bynk.tier.cross_context_needs_system
Section titled “bynk.tier.cross_context_needs_system”[bynk.tier.cross_context_needs_system] case `"pays"` calls `check`, which calls `shop.payment.authorise` in another context, but it is a `unit`-tier caseCause: a unit or integration case, or a property, reaches another
context’s service: directly (Payment.authorise(…)), or through a service or
agent handler of the unit under test that calls one. A property has no tier and
always runs in-process, so it can’t cross a context at all; drive that flow
from a case in a system suite. Below system a case runs in-process. No
consumed context is stood up, and stub doubles capabilities, not a context’s
services, so there would be nothing on the other side of the call.
Fix: move the case into a system suite, which stands the contexts up as
Workers on either side of the real wire. There a service is addressed by its
context path:
suite shop.orders as system { case "pays" { let r <- shop.orders.check(100) expect r is Ok(_) }}To test the unit’s own logic in-process instead, drive a service that stays in the context.
bynk.tier.mixed_system_suite
Section titled “bynk.tier.mixed_system_suite”[bynk.tier.mixed_system_suite] case `"pays"` is `as system`, but other cases in its suite run below `system`Cause: a suite mixes system cases with unit or integration ones. A
system case runs against deployed Workers and addresses services by context
path (shop.orders.place(…)), while a lower-tier case calls place.call(…)
in-process, and one suite is emitted one way or the other, not both.
Fix: keep a target’s in-process cases and its system cases in separate
suites, one suite shop.orders { … } and one suite shop.orders as system { … }
(they may sit in separate files).
bynk.stub.not_a_seam
Section titled “bynk.stub.not_a_seam”[bynk.stub.not_a_seam] `Rates` is not a capability the unit under test consumes; only a consumed capability can be providedCause: a stub clause targets something that is not a capability seam the
unit under test consumes / has in scope via given — for example an agent, a type,
or a capability the unit does not depend on. stub is capability-only: an
agent’s realness is the tier’s job, not a provider’s.
Fix: provide a capability the unit actually consumes. To change the realness of
an agent or a whole context, promote the tier (as integration / as system)
instead.
bynk.stub.unknown_op
Section titled “bynk.stub.unknown_op”[bynk.stub.unknown_op] capability `Rates` has no operation named `looup`Cause: the Cap.method(…) left-hand side names an operation the capability does
not declare (typically a typo).
Fix: use one of the capability’s declared operations (check the capability
block).
bynk.stub.rhs_type
Section titled “bynk.stub.rhs_type”[bynk.stub.rhs_type] `returns "1.25"` has type `String`, but `Rates.lookup` returns `Float`Cause: a returns <value> supplies a value whose type disagrees with the
operation’s declared return type.
Fix: return a value of the operation’s result type. To inject a fault rather
than a value, write fails; an in-band Err outcome is an ordinary value you
assert directly in the case.
bynk.stub.bad_sequence
Section titled “bynk.stub.bad_sequence”[bynk.stub.bad_sequence] `returns each []` is empty; a sequence needs at least one outcomeCause: a returns each [<outcome>, …] sequence is malformed — most commonly
empty, so there is no outcome to serve on the first call.
Fix: give the sequence at least one outcome. Each outcome is a value (a
success), the atom fails (a fault), or ok(v); the last outcome repeats once
the sequence is exhausted, so [fails, fails, ok(resp)] is “fails twice, then
succeeds forever”.