Mobile apps — worked graph designs
These designs describe intended system behavior and qualification requirements. Inspect the system atlas for named ports and relation participants.
Community app: nested navigation and authenticated messaging
How does opening a deep link lead to a scoped service effect?
Inspect this design · Definition JSON · revision 57940c5ac864
Diagram legend. Frames are named graph regions. Left/right pins show required/offered participation, not a universal schedule. Filled pins are connected; hollow pins are unbound. A junction card preserves one relation's role slots.
| Marker | Meaning in this diagram |
|---|---|
| ↪ N12 | Route / navigation |
| ▤ N11 | Surface / view component |
| ↯ N02 | Effectful operation |
| ⊂ N33 | Policy / principal boundary |
| ↗ N19 | Tool / external API adapter |
| ▰ N21 | Database / state authority |
| ◎ N38 | Observer / query / visitor |
| ▷ P11 | Execution / continuation |
| ↦ P04 | Push event |
| ⊂ P20 | Authorization request / grant |
| ⇆ P02 | Request / response |
| ◎ P24 | Inspection / evidence |
| ↪ H36 | Navigation / interaction route |
| → H02 | Value flow |
| ⊂ H23 | Scoped authorization |
| ⇆ H05 | Request / reply binding |
| ↦ H04 | Event subscription |
Logic and ownership
Validate a draft with an ordinary Kotlin function, then invoke the typed send port. Derive trace context from the selected route and operation ID.
Failure and qualification
- A route is an address, not an authorization grant. The service rechecks the current principal and conversation membership.
- Back stack and nested container activation stay local to the device; no distributed back stack is inferred.
- Retries carry the same operation ID; one local call does not establish durable delivery.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| nav | H36 — Navigation / interaction route {#h36--navigation--interaction-route} | provider[0]: route.destination; consumer[0]: screen.route |
| intent | H02 — Value flow {#h02--value-flow} | provider[0]: screen.intent; consumer[0]: controller.input |
| grant | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: auth.grant; consumer[0]: controller.authority |
| service | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: chat.send; consumer[0]: controller.send |
| persist | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: log.append; consumer[0]: chat.storage |
| observe | H04 — Event subscription {#h04--event-subscription} | provider[0]: controller.span; consumer[0]: trace.span |
| scope | H23 — Scoped authorization {#h23--scoped-authorization} | principal[0]: auth.principal; effect[1]: controller.effect; resource[2]: log.resource |
Kotlin common declaration
Import dev.shibasis.reaktor.portgraph.definition.* for this structural declaration. Behavior stays in ordinary Kotlin and binds through qualified runtime ports and adapters. Declaring a graph does not activate a system.
graphDefinition("mobile-community", "57940c5ac864e359093ec40028152376c918b29435b97abe63e86e70495f3139") {
region("device", "Mobile device")
region("edge", "Edge services")
node("route", "App routes", "N12", "device", ports = listOf(
PortDefinition("destination", "P11", "ConversationRouteV1", PortPolarity.Offer)
))
node("screen", "Conversation Surface", "N11", "device", ports = listOf(
PortDefinition("route", "P11", "ConversationRouteV1", PortPolarity.Require),
PortDefinition("intent", "P04", "MessageIntentV1", PortPolarity.Offer)
))
node("controller", "Conversation logic", "N02", "device", ports = listOf(
PortDefinition("input", "P04", "MessageIntentV1", PortPolarity.Require),
PortDefinition("authority", "P20", "ScopedGrantV1", PortPolarity.Require),
PortDefinition("send", "P02", "SendMessageV1", PortPolarity.Require),
PortDefinition("span", "P24", "TraceEnvelopeV1", PortPolarity.Offer),
PortDefinition("effect", "P24", "EffectRefV1", PortPolarity.Neutral)
))
node("auth", "Session boundary", "N33", "edge", ports = listOf(
PortDefinition("grant", "P20", "ScopedGrantV1", PortPolarity.Offer),
PortDefinition("principal", "P24", "PrincipalV1", PortPolarity.Neutral)
))
node("chat", "Messaging service", "N19", "edge", ports = listOf(
PortDefinition("send", "P02", "SendMessageV1", PortPolarity.Offer),
PortDefinition("storage", "P02", "MessageLedgerV1", PortPolarity.Require)
))
node("log", "Message authority", "N21", "edge", ports = listOf(
PortDefinition("append", "P02", "MessageLedgerV1", PortPolarity.Offer),
PortDefinition("resource", "P24", "ConversationRefV1", PortPolarity.Neutral)
))
node("trace", "Trace exporter", "N38", "edge", ports = listOf(
PortDefinition("span", "P24", "TraceEnvelopeV1", PortPolarity.Require)
))
relation("nav", "H36",
Incidence("route", "destination", "provider", 0),
Incidence("screen", "route", "consumer", 0)
)
relation("intent", "H02",
Incidence("screen", "intent", "provider", 0),
Incidence("controller", "input", "consumer", 0)
)
relation("grant", "H23",
Incidence("auth", "grant", "provider", 0),
Incidence("controller", "authority", "consumer", 0)
)
relation("service", "H05",
Incidence("chat", "send", "provider", 0),
Incidence("controller", "send", "consumer", 0)
)
relation("persist", "H05",
Incidence("log", "append", "provider", 0),
Incidence("chat", "storage", "consumer", 0)
)
relation("observe", "H04",
Incidence("controller", "span", "provider", 0),
Incidence("trace", "span", "consumer", 0)
)
relation("scope", "H23",
Incidence("auth", "principal", "principal", 0),
Incidence("controller", "effect", "effect", 1),
Incidence("log", "resource", "resource", 2)
)
}
Offline field notebook: local edits and reconciled sync
Who owns an edit when a mobile device is disconnected?
Inspect this design · Definition JSON · revision 49761185d049
Diagram legend. Frames are named graph regions. Left/right pins show required/offered participation, not a universal schedule. Filled pins are connected; hollow pins are unbound. A junction card preserves one relation's role slots.
| Marker | Meaning in this diagram |
|---|---|
| ▤ N11 | Surface / view component |
| ↯ N02 | Effectful operation |
| ▰ N21 | Database / state authority |
| ⇄ N25 | Cache / replica / sync agent |
| ↗ N19 | Tool / external API adapter |
| ⊂ N33 | Policy / principal boundary |
| ↦ P04 | Push event |
| ⇆ P02 | Request / response |
| ○ P01 | Value / immutable snapshot |
| ◎ P24 | Inspection / evidence |
| ⊂ P20 | Authorization request / grant |
| → H02 | Value flow |
| ⇆ H05 | Request / reply binding |
| ⊂ H23 | Scoped authorization |
| ⊢ H27 | Derivation / provenance |
Logic and ownership
A common Kotlin merge function computes a candidate from base, local and remote values; conflicts remain explicit values for the Surface.
Failure and qualification
- Local durability and remote acceptance are separate receipts.
- Offline grants expire; sensitive effects can require reauthentication before upload.
- The merge law and tombstone retention must be specified for each data type; a replica relation does not make every edit commutative.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| input | H02 — Value flow {#h02--value-flow} | provider[0]: view.edit; consumer[0]: edit.input |
| local | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: store.commit; consumer[0]: edit.store |
| pending | H02 — Value flow {#h02--value-flow} | provider[0]: store.pending; consumer[0]: sync.pending |
| remote | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: api.reconcile; consumer[0]: sync.remote |
| write | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: authority.conditional; consumer[0]: api.storage |
| grant | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: policy.grant; consumer[0]: api.authority |
| lineage | H27 — Derivation / provenance {#h27--derivation--provenance} | localRevision[0]: store.revision; remoteRevision[1]: authority.revision; reconciler[2]: sync.reconciler |
Kotlin common declaration
Import dev.shibasis.reaktor.portgraph.definition.* for this structural declaration. Behavior stays in ordinary Kotlin and binds through qualified runtime ports and adapters. Declaring a graph does not activate a system.
graphDefinition("mobile-offline", "49761185d049a8802597968e03c4942f3e314819d581eea6dc6068cdab35abbd") {
region("device", "Mobile device")
region("edge", "Edge services")
node("view", "Notebook Surface", "N11", "device", ports = listOf(
PortDefinition("edit", "P04", "EditIntentV1", PortPolarity.Offer)
))
node("edit", "Local edit logic", "N02", "device", ports = listOf(
PortDefinition("input", "P04", "EditIntentV1", PortPolarity.Require),
PortDefinition("store", "P02", "LocalMutationV1", PortPolarity.Require)
))
node("store", "Local durable store", "N21", "device", ports = listOf(
PortDefinition("commit", "P02", "LocalMutationV1", PortPolarity.Offer),
PortDefinition("pending", "P01", "PendingBatchV1", PortPolarity.Offer),
PortDefinition("revision", "P24", "RevisionRefV1", PortPolarity.Neutral)
))
node("sync", "Sync agent", "N25", "device", ports = listOf(
PortDefinition("pending", "P01", "PendingBatchV1", PortPolarity.Require),
PortDefinition("remote", "P02", "SyncBatchV1", PortPolarity.Require),
PortDefinition("reconciler", "P24", "ImplementationRefV1", PortPolarity.Neutral)
))
node("api", "Notebook service", "N19", "edge", ports = listOf(
PortDefinition("reconcile", "P02", "SyncBatchV1", PortPolarity.Offer),
PortDefinition("storage", "P02", "ConditionalWriteV1", PortPolarity.Require),
PortDefinition("authority", "P20", "WorkspaceGrantV1", PortPolarity.Require)
))
node("authority", "Notebook authority", "N21", "edge", ports = listOf(
PortDefinition("conditional", "P02", "ConditionalWriteV1", PortPolarity.Offer),
PortDefinition("revision", "P24", "RevisionRefV1", PortPolarity.Neutral)
))
node("policy", "Workspace policy", "N33", "edge", ports = listOf(
PortDefinition("grant", "P20", "WorkspaceGrantV1", PortPolarity.Offer)
))
relation("input", "H02",
Incidence("view", "edit", "provider", 0),
Incidence("edit", "input", "consumer", 0)
)
relation("local", "H05",
Incidence("store", "commit", "provider", 0),
Incidence("edit", "store", "consumer", 0)
)
relation("pending", "H02",
Incidence("store", "pending", "provider", 0),
Incidence("sync", "pending", "consumer", 0)
)
relation("remote", "H05",
Incidence("api", "reconcile", "provider", 0),
Incidence("sync", "remote", "consumer", 0)
)
relation("write", "H05",
Incidence("authority", "conditional", "provider", 0),
Incidence("api", "storage", "consumer", 0)
)
relation("grant", "H23",
Incidence("policy", "grant", "provider", 0),
Incidence("api", "authority", "consumer", 0)
)
relation("lineage", "H27",
Incidence("store", "revision", "localRevision", 0),
Incidence("authority", "revision", "remoteRevision", 1),
Incidence("sync", "reconciler", "reconciler", 2)
)
}
Camera pipeline: permission, native buffers and inference
Which boundary can carry a pointer and which requires bytes?
Inspect this design · Definition JSON · revision 90903c09d808
Diagram legend. Frames are named graph regions. Left/right pins show required/offered participation, not a universal schedule. Filled pins are connected; hollow pins are unbound. A junction card preserves one relation's role slots.
| Marker | Meaning in this diagram |
|---|---|
| ▤ N11 | Surface / view component |
| ⊂ N33 | Policy / principal boundary |
| ⚙ N15 | Device / platform adapter |
| ▱ N26 | Blob / buffer / asset store |
| ◆ N16 | Native resource / engine |
| ↗ N19 | Tool / external API adapter |
| ◉ P08 | Signal / reactive state |
| ○ P01 | Value / immutable snapshot |
| ⇆ P02 | Request / response |
| ⊂ P20 | Authorization request / grant |
| ◆ P16 | Owned resource transfer |
| ◎ P24 | Inspection / evidence |
| ◇̸ P17 | Borrowed buffer / view |
| ⊂ H23 | Scoped authorization |
| → H02 | Value flow |
| — H01 | Exclusive binding |
| ⇆ H05 | Request / reply binding |
| ⊏ H19 | Ownership / containment |
Logic and ownership
Use ordinary Kotlin to crop and decide whether to upload. Invoke native compute through the qualified FFI adapter; the graph exposes the lease contract.
Failure and qualification
- A borrowed view expires at its owner-defined scope; asynchronous retention needs a separate ownership transfer.
- A local pointer never becomes a network address. Serialize an encoded artifact for the edge upload.
- JNI/cinterop evidence must match the target, ABI, alignment, thread affinity and release path; the diagram supplies no universal zero-copy guarantee.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| permission | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: permission.grant; consumer[0]: camera.permission |
| preview | H02 — Value flow {#h02--value-flow} | provider[0]: camera.preview; consumer[0]: surface.preview |
| frame | H02 — Value flow {#h02--value-flow} | provider[0]: camera.frame; consumer[0]: pool.frame |
| borrow | H01 — Exclusive binding {#h01--exclusive-binding} | provider[0]: pool.borrow; consumer[0]: native.input |
| result | H02 — Value flow {#h02--value-flow} | provider[0]: native.result; consumer[0]: surface.result |
| upload | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: upload.put; consumer[0]: surface.upload |
| storage | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: blob.put; consumer[0]: upload.store |
| lifetime | H19 — Ownership / containment {#h19--ownership--containment} | owner[0]: pool.owner; borrower[1]: native.borrower; release[2]: camera.release |
Kotlin common declaration
Import dev.shibasis.reaktor.portgraph.definition.* for this structural declaration. Behavior stays in ordinary Kotlin and binds through qualified runtime ports and adapters. Declaring a graph does not activate a system.
graphDefinition("mobile-camera", "90903c09d808b0d844575eca374673893ee42048ed9bcbf4517d71788f8cae26") {
region("device", "Mobile device")
region("edge", "Edge services")
node("surface", "Capture Surface", "N11", "device", ports = listOf(
PortDefinition("preview", "P08", "PreviewStateV1", PortPolarity.Require),
PortDefinition("result", "P01", "DetectionV1", PortPolarity.Require),
PortDefinition("upload", "P02", "MediaUploadV1", PortPolarity.Require)
))
node("permission", "Camera permission", "N33", "device", ports = listOf(
PortDefinition("grant", "P20", "DeviceGrantV1", PortPolarity.Offer)
))
node("camera", "Camera adapter", "N15", "device", ports = listOf(
PortDefinition("permission", "P20", "DeviceGrantV1", PortPolarity.Require),
PortDefinition("preview", "P08", "PreviewStateV1", PortPolarity.Offer),
PortDefinition("frame", "P16", "OwnedFrameV1", PortPolarity.Offer),
PortDefinition("release", "P24", "ReleaseRefV1", PortPolarity.Neutral)
))
node("pool", "Owned frame pool", "N26", "device", ports = listOf(
PortDefinition("frame", "P16", "OwnedFrameV1", PortPolarity.Require),
PortDefinition("borrow", "P17", "FrameLeaseV1", PortPolarity.Offer),
PortDefinition("owner", "P24", "ResourceOwnerV1", PortPolarity.Neutral)
))
node("native", "Native inference kernel", "N16", "device", ports = listOf(
PortDefinition("input", "P17", "FrameLeaseV1", PortPolarity.Require),
PortDefinition("result", "P01", "DetectionV1", PortPolarity.Offer),
PortDefinition("borrower", "P24", "BorrowScopeV1", PortPolarity.Neutral)
))
node("upload", "Upload service", "N19", "edge", ports = listOf(
PortDefinition("put", "P02", "MediaUploadV1", PortPolarity.Offer),
PortDefinition("store", "P02", "ObjectPutV1", PortPolarity.Require)
))
node("blob", "Object store", "N26", "edge", ports = listOf(
PortDefinition("put", "P02", "ObjectPutV1", PortPolarity.Offer)
))
relation("permission", "H23",
Incidence("permission", "grant", "provider", 0),
Incidence("camera", "permission", "consumer", 0)
)
relation("preview", "H02",
Incidence("camera", "preview", "provider", 0),
Incidence("surface", "preview", "consumer", 0)
)
relation("frame", "H02",
Incidence("camera", "frame", "provider", 0),
Incidence("pool", "frame", "consumer", 0)
)
relation("borrow", "H01",
Incidence("pool", "borrow", "provider", 0),
Incidence("native", "input", "consumer", 0)
)
relation("result", "H02",
Incidence("native", "result", "provider", 0),
Incidence("surface", "result", "consumer", 0)
)
relation("upload", "H05",
Incidence("upload", "put", "provider", 0),
Incidence("surface", "upload", "consumer", 0)
)
relation("storage", "H05",
Incidence("blob", "put", "provider", 0),
Incidence("upload", "store", "consumer", 0)
)
relation("lifetime", "H19",
Incidence("pool", "owner", "owner", 0),
Incidence("native", "borrower", "borrower", 1),
Incidence("camera", "release", "release", 2)
)
}
Mobile purchase: deep link, payment and durable receipt
What survives a repeated checkout request?
Inspect this design · Definition JSON · revision 5d30a93454eb
Diagram legend. Frames are named graph regions. Left/right pins show required/offered participation, not a universal schedule. Filled pins are connected; hollow pins are unbound. A junction card preserves one relation's role slots.
| Marker | Meaning in this diagram |
|---|---|
| ↪ N12 | Route / navigation |
| ↯ N02 | Effectful operation |
| ⊂ N33 | Policy / principal boundary |
| ⊟ N30 | External system boundary |
| ▰ N21 | Database / state authority |
| ≋ N24 | Queue / log / pubsub resource |
| ▷ P11 | Execution / continuation |
| ⊂ P20 | Authorization request / grant |
| ⇆ P02 | Request / response |
| ◎ P24 | Inspection / evidence |
| ▣ P03 | Durable command / receipt |
| ↪ H36 | Navigation / interaction route |
| ⊂ H23 | Scoped authorization |
| ⇆ H05 | Request / reply binding |
| → H02 | Value flow |
| ⊗ H16 | Atomic authority scope |
Logic and ownership
Compute totals with a shared Kotlin pricing function. Reuse one idempotency key across retried payment attempts and reconcile provider receipts.
Failure and qualification
- H16 identifies the ledger authority. It does not atomically include the external payment provider.
- A webhook must authenticate its own source and reconcile against provider transaction identity.
- Navigation success is not a purchase receipt; show pending, committed and disputed states separately.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| entry | H36 — Navigation / interaction route {#h36--navigation--interaction-route} | provider[0]: route.order; consumer[0]: checkout.order |
| auth | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: session.grant; consumer[0]: checkout.grant |
| pay | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: payment.charge; consumer[0]: checkout.pay |
| commit | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: ledger.commit; consumer[0]: checkout.commit |
| outbox | H02 — Value flow {#h02--value-flow} | provider[0]: ledger.receipt; consumer[0]: events.receipt |
| purchase | H16 — Atomic authority scope {#h16--atomic-authority-scope} | authority[0]: ledger.authority; intent[1]: checkout.intent; externalEffect[2]: payment.effect |
Kotlin common declaration
Import dev.shibasis.reaktor.portgraph.definition.* for this structural declaration. Behavior stays in ordinary Kotlin and binds through qualified runtime ports and adapters. Declaring a graph does not activate a system.
graphDefinition("mobile-purchase", "5d30a93454eb79a62928dba66a0ff1fcc78f79f081b07b972a19bee696c90b66") {
region("device", "Mobile device")
region("edge", "Edge services")
node("route", "Purchase route", "N12", "device", ports = listOf(
PortDefinition("order", "P11", "OrderRouteV1", PortPolarity.Offer)
))
node("checkout", "Checkout logic", "N02", "device", ports = listOf(
PortDefinition("order", "P11", "OrderRouteV1", PortPolarity.Require),
PortDefinition("grant", "P20", "PurchaseGrantV1", PortPolarity.Require),
PortDefinition("pay", "P02", "ChargeV1", PortPolarity.Require),
PortDefinition("commit", "P02", "PurchaseCommitV1", PortPolarity.Require),
PortDefinition("intent", "P24", "PurchaseIntentV1", PortPolarity.Neutral)
))
node("session", "Principal boundary", "N33", "edge", ports = listOf(
PortDefinition("grant", "P20", "PurchaseGrantV1", PortPolarity.Offer)
))
node("payment", "Payment adapter", "N30", "edge", ports = listOf(
PortDefinition("charge", "P02", "ChargeV1", PortPolarity.Offer),
PortDefinition("effect", "P24", "ExternalEffectRefV1", PortPolarity.Neutral)
))
node("ledger", "Purchase ledger", "N21", "edge", ports = listOf(
PortDefinition("commit", "P02", "PurchaseCommitV1", PortPolarity.Offer),
PortDefinition("receipt", "P03", "PurchaseReceiptV1", PortPolarity.Offer),
PortDefinition("authority", "P24", "TransactionAuthorityV1", PortPolarity.Neutral)
))
node("events", "Receipt outbox", "N24", "edge", ports = listOf(
PortDefinition("receipt", "P03", "PurchaseReceiptV1", PortPolarity.Require)
))
relation("entry", "H36",
Incidence("route", "order", "provider", 0),
Incidence("checkout", "order", "consumer", 0)
)
relation("auth", "H23",
Incidence("session", "grant", "provider", 0),
Incidence("checkout", "grant", "consumer", 0)
)
relation("pay", "H05",
Incidence("payment", "charge", "provider", 0),
Incidence("checkout", "pay", "consumer", 0)
)
relation("commit", "H05",
Incidence("ledger", "commit", "provider", 0),
Incidence("checkout", "commit", "consumer", 0)
)
relation("outbox", "H02",
Incidence("ledger", "receipt", "provider", 0),
Incidence("events", "receipt", "consumer", 0)
)
relation("purchase", "H16",
Incidence("ledger", "authority", "authority", 0),
Incidence("checkout", "intent", "intent", 1),
Incidence("payment", "effect", "externalEffect", 2)
)
}
Mobile feature region: signed subgraph code push
Which feature can be replaced while an old screen is still active?
Inspect this design · Definition JSON · revision dfd0f654fb38
Diagram legend. Frames are named graph regions. Left/right pins show required/offered participation, not a universal schedule. Filled pins are connected; hollow pins are unbound. A junction card preserves one relation's role slots.
| Marker | Meaning in this diagram |
|---|---|
| ▸ N27 | Runtime host / executor |
| ↪ N12 | Route / navigation |
| ⌘ N10 | Function / blueprint region |
| ⚙ N15 | Device / platform adapter |
| λ N34 | Build / compiler pass |
| ▧ N35 | Artifact / release manifest |
| ⊂ N33 | Policy / principal boundary |
| ⊕ P19 | Capability descriptor |
| ⇆ P02 | Request / response |
| ◎ P24 | Inspection / evidence |
| ▧ P23 | Artifact / schema reference |
| ⊂ P20 | Authorization request / grant |
| ⇥ H30 | Boundary export / alias |
| ⇆ H05 | Request / reply binding |
| ▧ H26 | Artifact dependency |
| ⊂ H23 | Scoped authorization |
| ⏻ H29 | Activation cohort |
Logic and ownership
The graph DSL constructs the exported feature boundary; arbitrary common logic compiles to Kotlin/JS. A host-qualified loader publishes a new activation only after contract and artifact checks.
Failure and qualification
- Existing calls remain pinned to their original generation until quiescence or explicit migration.
- State conversion, native handles and UI thread ownership are separate admission obligations.
- Code-push policy, signature verification and rollback are target-specific. This example is a design, not proof that app-store targets admit it.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| routes | H30 — Boundary export / alias {#h30--boundary-export--alias} | provider[0]: routes.export; consumer[0]: shell.routes |
| calls | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: old.feature; consumer[0]: shell.feature |
| bundle | H26 — Artifact dependency {#h26--artifact-dependency} | provider[0]: build.bundle; consumer[0]: artifact.input |
| fetch | H26 — Artifact dependency {#h26--artifact-dependency} | provider[0]: artifact.bundle; consumer[0]: loader.bundle |
| admit | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: gate.decision; consumer[0]: loader.admission |
| cohort | H29 — Activation cohort {#h29--activation-cohort} | oldActivation[0]: old.epoch; candidate[1]: artifact.revision; publisher[2]: loader.publisher |
Kotlin common declaration
Import dev.shibasis.reaktor.portgraph.definition.* for this structural declaration. Behavior stays in ordinary Kotlin and binds through qualified runtime ports and adapters. Declaring a graph does not activate a system.
graphDefinition("mobile-feature-update", "dfd0f654fb38c3b54d0b8241a5bfe11e1505a653c827882767c264dc12b251c5") {
region("device", "Mobile device")
region("edge", "Edge services")
node("shell", "Stable app shell", "N27", "device", ports = listOf(
PortDefinition("routes", "P19", "RouteExportsV1", PortPolarity.Require),
PortDefinition("feature", "P02", "FeatureContractV1", PortPolarity.Require)
))
node("routes", "Feature route exports", "N12", "device", ports = listOf(
PortDefinition("export", "P19", "RouteExportsV1", PortPolarity.Offer)
))
node("old", "Active feature epoch", "N10", "device", ports = listOf(
PortDefinition("feature", "P02", "FeatureContractV1", PortPolarity.Offer),
PortDefinition("epoch", "P24", "ActivationRefV1", PortPolarity.Neutral)
))
node("loader", "JS host / FFI adapter", "N15", "device", ports = listOf(
PortDefinition("bundle", "P23", "BundleRefV1", PortPolarity.Require),
PortDefinition("admission", "P20", "AdmissionV1", PortPolarity.Require),
PortDefinition("publisher", "P24", "HostRefV1", PortPolarity.Neutral)
))
node("build", "Feature packager", "N34", "edge", ports = listOf(
PortDefinition("bundle", "P23", "BundleRefV1", PortPolarity.Offer)
))
node("artifact", "Signed bundle", "N35", "edge", ports = listOf(
PortDefinition("input", "P23", "BundleRefV1", PortPolarity.Require),
PortDefinition("bundle", "P23", "BundleRefV1", PortPolarity.Offer),
PortDefinition("revision", "P24", "RevisionRefV1", PortPolarity.Neutral)
))
node("gate", "Host admission gate", "N33", "device", ports = listOf(
PortDefinition("decision", "P20", "AdmissionV1", PortPolarity.Offer)
))
relation("routes", "H30",
Incidence("routes", "export", "provider", 0),
Incidence("shell", "routes", "consumer", 0)
)
relation("calls", "H05",
Incidence("old", "feature", "provider", 0),
Incidence("shell", "feature", "consumer", 0)
)
relation("bundle", "H26",
Incidence("build", "bundle", "provider", 0),
Incidence("artifact", "input", "consumer", 0)
)
relation("fetch", "H26",
Incidence("artifact", "bundle", "provider", 0),
Incidence("loader", "bundle", "consumer", 0)
)
relation("admit", "H23",
Incidence("gate", "decision", "provider", 0),
Incidence("loader", "admission", "consumer", 0)
)
relation("cohort", "H29",
Incidence("old", "epoch", "oldActivation", 0),
Incidence("artifact", "revision", "candidate", 1),
Incidence("loader", "publisher", "publisher", 2)
)
}