A Grain Call may complete on this Silo or on another Silo. Callers can rely on the same outcome rules. Location transparency guarantees exactly that.
Cross-Silo behavior is part of the Cluster preview. It is not part of the 0.1.0 product contract.
Location transparency does not preserve in-process error objects. Concrete types, fields, and wrapping do not become a Cross-Silo contract.
When callers need to make decisions based on errors, the application must declare a stable error code. Error codes are the application's public vocabulary, not text for log searching.
An error code is an owner name plus a name, both lowercase ASCII, separated by a dot. Example: shadow.workshop_id_required. The name may contain lowercase letters, digits, and underscores. The owner name must be owned by the application. gor is reserved as the library's owner name; applications must not declare gor.*.
Applications declare their codes as package-level gor.Code constants and return the constant, or an error wrapping it, as the method result:
const ErrWorkshopIDRequired gor.Code = "shadow.workshop_id_required"
return fmt.Errorf("workshop ID is required: %w", ErrWorkshopIDRequired)Callers check the constant with Go's errors.Is. Error text is for humans, logs, and diagnostics. It is not a branching condition.
gor's own codes are a closed set. The library only uses the published gor.* codes. Full list and the meaning of each code: ../design/errors.md.
| Outcome | Local Call | Cross-Silo Call |
|---|---|---|
| Error with a stable code | The original error matches the code. | A new error matches the same code. Text may differ. |
| Error with no determinate code | The original error object is returned as-is. | Only displayable text remains. |
| Caller cancels or times out | The caller gets its own cancellation or timeout error. | Same. The target Silo can still run the Call. |
| Send, connect, or reply-receive failure | This is a delivery failure. | Same. It cannot prove that the target Silo did not run the Call. |
This parity applies only to one determinate stable code. The complete error tree must contain exactly one unique code. No code means that no determinate code exists. Several different codes also mean that no determinate code exists. Merged errors use the same rule.
An error with a determinate code matches that code across Silos. An error with
no determinate code keeps only text. errors.As and concrete types need not
match across Silos.
An uncoded error can still be displayed and logged across Silos. Callers must not use its text, type, fields, or wrapping for decisions.
Caller cancellation or timeout means the caller is no longer waiting. It does not mean the business action did not happen.
A local Call gives the caller's cancellation to the method. A Cross-Silo Call does not send the cancellation or deadline. The target method can still finish and change State.
This boundary gives the caller an Unknown Result. The Application must define a Safe Repeat or a recovery rule for the Business Action.
When a method has already returned a business error, that error wins. The runtime does not try to encode the same call's return value, so a return-value encoding failure cannot override the business error.
When a method succeeds but its return value cannot be encoded, the caller gets gor.reply_encode_failed. No return value is available. If not even the call result came back, the caller sees a delivery failure; that equally does not prove the method did not execute.
This version does not restore arbitrary error types or fields. Applications must put Cross-Silo business data in results or persistent State.
Application code can replace a sentinel with a declared gor.Code. It can
then keep using errors.Is across Silos.
Simulators and tests must classify only by stable codes or the caller's own cancellation errors. Errors without a determinate code must be reported as unclassified, not categorized by guessing at text.
The Single Silo error contract is implemented. The Cluster preview preserves determinate stable codes across Silos. Cancellation remains local to each Silo.