Websites — worked graph designs
These designs describe intended system behavior and qualification requirements. Inspect the system atlas for named ports and relation participants.
Content website: browser, edge cache and source publication
Which revision did a reader receive through a cache?
Inspect this design · Definition JSON · revision fd73fca88045
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 |
| ↗ N19 | Tool / external API adapter |
| ⇄ N25 | Cache / replica / sync agent |
| ▰ N21 | Database / state authority |
| λ N34 | Build / compiler pass |
| ▷ P11 | Execution / continuation |
| ⇆ P02 | Request / response |
| ▧ P23 | Artifact / schema reference |
| ◎ P24 | Inspection / evidence |
| ○ P01 | Value / immutable snapshot |
| ↪ H36 | Navigation / interaction route |
| ⇆ H05 | Request / reply binding |
| → H02 | Value flow |
| ▧ H26 | Artifact dependency |
| ⊢ H27 | Derivation / provenance |
Logic and ownership
An ordinary Kotlin renderer can compose a page model and apply URL routing. Cache keys include source and rendering revisions.
Failure and qualification
- A cached page must name the served revision rather than imply it is the newest.
- Public and authenticated render variants use separate visibility checks and cache policies.
- Page render, edge publication and source ownership are separate projections of the same identified feature.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| route | H36 — Navigation / interaction route {#h36--navigation--interaction-route} | provider[0]: route.page; consumer[0]: reader.route |
| fetch | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: edge.read; consumer[0]: reader.fetch |
| cache | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: cache.lookup; consumer[0]: edge.cache |
| source | H02 — Value flow {#h02--value-flow} | provider[0]: cms.content; consumer[0]: build.source |
| publish | H26 — Artifact dependency {#h26--artifact-dependency} | provider[0]: build.page; consumer[0]: cache.artifact |
| provenance | H27 — Derivation / provenance {#h27--derivation--provenance} | source[0]: cms.source; artifact[1]: build.artifact; served[2]: cache.served |
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("web-content", "fd73fca88045ec746eb62d7e7fc93f25ca2aa0e690cc658cc2b300ec679e6cf5") {
region("browser", "Browser")
region("edge", "Edge services")
region("data", "Data authorities")
node("route", "URL routes", "N12", "browser", ports = listOf(
PortDefinition("page", "P11", "PageRouteV1", PortPolarity.Offer)
))
node("reader", "Page renderer", "N11", "browser", ports = listOf(
PortDefinition("route", "P11", "PageRouteV1", PortPolarity.Require),
PortDefinition("fetch", "P02", "PageReadV1", PortPolarity.Require)
))
node("edge", "Edge page service", "N19", "edge", ports = listOf(
PortDefinition("read", "P02", "PageReadV1", PortPolarity.Offer),
PortDefinition("cache", "P02", "VersionedPageV1", PortPolarity.Require)
))
node("cache", "Revision cache", "N25", "edge", ports = listOf(
PortDefinition("lookup", "P02", "VersionedPageV1", PortPolarity.Offer),
PortDefinition("artifact", "P23", "PageArtifactV1", PortPolarity.Require),
PortDefinition("served", "P24", "PublicationRefV1", PortPolarity.Neutral)
))
node("cms", "Content authority", "N21", "data", ports = listOf(
PortDefinition("content", "P01", "ContentRevisionV1", PortPolarity.Offer),
PortDefinition("source", "P24", "RevisionRefV1", PortPolarity.Neutral)
))
node("build", "Page compiler", "N34", "data", ports = listOf(
PortDefinition("source", "P01", "ContentRevisionV1", PortPolarity.Require),
PortDefinition("page", "P23", "PageArtifactV1", PortPolarity.Offer),
PortDefinition("artifact", "P24", "ArtifactRefV1", PortPolarity.Neutral)
))
relation("route", "H36",
Incidence("route", "page", "provider", 0),
Incidence("reader", "route", "consumer", 0)
)
relation("fetch", "H05",
Incidence("edge", "read", "provider", 0),
Incidence("reader", "fetch", "consumer", 0)
)
relation("cache", "H05",
Incidence("cache", "lookup", "provider", 0),
Incidence("edge", "cache", "consumer", 0)
)
relation("source", "H02",
Incidence("cms", "content", "provider", 0),
Incidence("build", "source", "consumer", 0)
)
relation("publish", "H26",
Incidence("build", "page", "provider", 0),
Incidence("cache", "artifact", "consumer", 0)
)
relation("provenance", "H27",
Incidence("cms", "source", "source", 0),
Incidence("build", "artifact", "artifact", 1),
Incidence("cache", "served", "served", 2)
)
}
Commerce website: checkout, stock reservation and compensation
How do independent payment and inventory authorities coordinate?
Inspect this design · Definition JSON · revision b8f8390ef70a
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 |
| ⇢ N06 | Workflow / saga |
| ⊂ N33 | Policy / principal boundary |
| ▰ N21 | Database / state authority |
| ⊟ N30 | External system boundary |
| ≋ N24 | Queue / log / pubsub resource |
| ↦ P04 | Push event |
| ⊂ P20 | Authorization request / grant |
| ⇆ P02 | Request / response |
| ▣ P03 | Durable command / receipt |
| ◎ P24 | Inspection / evidence |
| → H02 | Value flow |
| ⊂ H23 | Scoped authorization |
| ⇆ H05 | Request / reply binding |
| ↶ H17 | Compensation relation |
Logic and ownership
A Kotlin state machine chooses reserve, charge, commit or compensate from durable saga state and observed receipts.
Failure and qualification
- An H17 relation describes compensation obligations; it does not turn refunds into an exact inverse.
- Recheck stock and price at the owning authority before committing.
- Timeout is an unknown outcome until reconciled; repeated dispatch must be idempotent.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| intent | H02 — Value flow {#h02--value-flow} | provider[0]: view.order; consumer[0]: order.intent |
| grant | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: auth.grant; consumer[0]: order.authority |
| stock | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: stock.reserve; consumer[0]: order.reserve |
| payment | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: payment.charge; consumer[0]: order.payment |
| dispatch | H02 — Value flow {#h02--value-flow} | provider[0]: order.dispatch; consumer[0]: fulfil.command |
| saga | H17 — Compensation relation {#h17--compensation-relation} | reservation[0]: stock.reservation; charge[1]: payment.chargeRef; coordinator[2]: order.compensation |
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("web-commerce", "b8f8390ef70aa6f93223c465061ddbb86b45c2508669fbe8f280f44aeee945ca") {
region("browser", "Browser")
region("edge", "Edge services")
region("data", "Data authorities")
node("view", "Checkout Surface", "N11", "browser", ports = listOf(
PortDefinition("order", "P04", "OrderIntentV1", PortPolarity.Offer)
))
node("order", "Order saga", "N06", "edge", ports = listOf(
PortDefinition("intent", "P04", "OrderIntentV1", PortPolarity.Require),
PortDefinition("authority", "P20", "CheckoutGrantV1", PortPolarity.Require),
PortDefinition("reserve", "P02", "ReservationV1", PortPolarity.Require),
PortDefinition("payment", "P02", "ChargeV1", PortPolarity.Require),
PortDefinition("dispatch", "P03", "DispatchV1", PortPolarity.Offer),
PortDefinition("compensation", "P24", "SagaRefV1", PortPolarity.Neutral)
))
node("auth", "Tenant / principal gate", "N33", "edge", ports = listOf(
PortDefinition("grant", "P20", "CheckoutGrantV1", PortPolarity.Offer)
))
node("stock", "Inventory authority", "N21", "data", ports = listOf(
PortDefinition("reserve", "P02", "ReservationV1", PortPolarity.Offer),
PortDefinition("reservation", "P24", "ReservationRefV1", PortPolarity.Neutral)
))
node("payment", "Payment provider", "N30", "data", ports = listOf(
PortDefinition("charge", "P02", "ChargeV1", PortPolarity.Offer),
PortDefinition("chargeRef", "P24", "ChargeRefV1", PortPolarity.Neutral)
))
node("fulfil", "Fulfilment queue", "N24", "data", ports = listOf(
PortDefinition("command", "P03", "DispatchV1", PortPolarity.Require)
))
relation("intent", "H02",
Incidence("view", "order", "provider", 0),
Incidence("order", "intent", "consumer", 0)
)
relation("grant", "H23",
Incidence("auth", "grant", "provider", 0),
Incidence("order", "authority", "consumer", 0)
)
relation("stock", "H05",
Incidence("stock", "reserve", "provider", 0),
Incidence("order", "reserve", "consumer", 0)
)
relation("payment", "H05",
Incidence("payment", "charge", "provider", 0),
Incidence("order", "payment", "consumer", 0)
)
relation("dispatch", "H02",
Incidence("order", "dispatch", "provider", 0),
Incidence("fulfil", "command", "consumer", 0)
)
relation("saga", "H17",
Incidence("stock", "reservation", "reservation", 0),
Incidence("payment", "chargeRef", "charge", 1),
Incidence("order", "compensation", "coordinator", 2)
)
}
Collaborative editor: sessions, replicas and workspace authority
What is shared state and what is ephemeral presence?
Inspect this design · Definition JSON · revision 5c6fa3ef17b1
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 |
| ⇄ N25 | Cache / replica / sync agent |
| ▣ N05 | Actor / statechart |
| ⊂ N33 | Policy / principal boundary |
| ≋ N24 | Queue / log / pubsub resource |
| ⌕ N22 | Query / materialized view |
| ↦ P04 | Push event |
| ⇄ P07 | Duplex session |
| ◎ P24 | Inspection / evidence |
| ⇆ P02 | Request / response |
| ⊂ P20 | Authorization request / grant |
| → H02 | Value flow |
| ⌬ H06 | Multiparty session |
| ⇆ H05 | Request / reply binding |
| ⊂ H23 | Scoped authorization |
| ⇄ H14 | Replica group |
Logic and ownership
Kotlin applies a specified CRDT merge algorithm to deltas; graph queries expose participants and log position while ordinary code implements the algorithm.
Failure and qualification
- Replica membership alone proves no convergence: cite the chosen CRDT operations and compaction rules.
- Presence can expire without deleting durable document edits.
- Read, write and invite grants differ; the server mediates every admitted update.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| edit | H02 — Value flow {#h02--value-flow} | provider[0]: editor.delta; consumer[0]: replica.delta |
| session | H06 — Multiparty session {#h06--multiparty-session} | provider[0]: room.session; consumer[0]: replica.session |
| persist | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: log.append; consumer[0]: room.log |
| grant | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: policy.grant; consumer[0]: room.authority |
| presence | H02 — Value flow {#h02--value-flow} | provider[0]: room.presence; consumer[0]: presence.events |
| replicas | H14 — Replica group {#h14--replica-group} | local[0]: replica.state; durable[1]: log.position; coordinator[2]: room.epoch |
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("web-collaboration", "5c6fa3ef17b10ec413e1e7580cdf88574aee3e4f70888ee887e8c3e6b1c1f0f9") {
region("browser", "Browser")
region("edge", "Edge services")
region("data", "Data authorities")
node("editor", "Document Surface", "N11", "browser", ports = listOf(
PortDefinition("delta", "P04", "CRDTDeltaV1", PortPolarity.Offer)
))
node("replica", "Local CRDT replica", "N25", "browser", ports = listOf(
PortDefinition("delta", "P04", "CRDTDeltaV1", PortPolarity.Require),
PortDefinition("session", "P07", "DocumentSessionV1", PortPolarity.Require),
PortDefinition("state", "P24", "ReplicaRefV1", PortPolarity.Neutral)
))
node("room", "Room actor", "N05", "edge", ports = listOf(
PortDefinition("session", "P07", "DocumentSessionV1", PortPolarity.Offer),
PortDefinition("log", "P02", "DocumentAppendV1", PortPolarity.Require),
PortDefinition("authority", "P20", "DocumentGrantV1", PortPolarity.Require),
PortDefinition("presence", "P04", "PresenceV1", PortPolarity.Offer),
PortDefinition("epoch", "P24", "ActivationRefV1", PortPolarity.Neutral)
))
node("policy", "Workspace policy", "N33", "edge", ports = listOf(
PortDefinition("grant", "P20", "DocumentGrantV1", PortPolarity.Offer)
))
node("log", "Document update log", "N24", "data", ports = listOf(
PortDefinition("append", "P02", "DocumentAppendV1", PortPolarity.Offer),
PortDefinition("position", "P24", "LogPositionV1", PortPolarity.Neutral)
))
node("presence", "Presence TTL view", "N22", "edge", ports = listOf(
PortDefinition("events", "P04", "PresenceV1", PortPolarity.Require)
))
relation("edit", "H02",
Incidence("editor", "delta", "provider", 0),
Incidence("replica", "delta", "consumer", 0)
)
relation("session", "H06",
Incidence("room", "session", "provider", 0),
Incidence("replica", "session", "consumer", 0)
)
relation("persist", "H05",
Incidence("log", "append", "provider", 0),
Incidence("room", "log", "consumer", 0)
)
relation("grant", "H23",
Incidence("policy", "grant", "provider", 0),
Incidence("room", "authority", "consumer", 0)
)
relation("presence", "H02",
Incidence("room", "presence", "provider", 0),
Incidence("presence", "events", "consumer", 0)
)
relation("replicas", "H14",
Incidence("replica", "state", "local", 0),
Incidence("log", "position", "durable", 1),
Incidence("room", "epoch", "coordinator", 2)
)
}
Manna documentation: native reader, cited questions and PDF jobs
How is a question or PDF tied to one documentation revision?
Inspect this design · Definition JSON · revision d8473f6e841e
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 |
| ↗ N19 | Tool / external API adapter |
| ▱ N26 | Blob / buffer / asset store |
| ⌕ N22 | Query / materialized view |
| ∑ N18 | Model inference |
| ⇢ N06 | Workflow / saga |
| ⇆ P02 | Request / response |
| ○ P01 | Value / immutable snapshot |
| ◎ P24 | Inspection / evidence |
| ▣ P03 | Durable command / receipt |
| ⇆ H05 | Request / reply binding |
| → H02 | Value flow |
| ≺ H03 | Control precedence |
| ✓ H28 | Evidence supports claim |
Logic and ownership
Lexical retrieval ranks source sections and passes a bounded context into the answer pipeline. A durable workflow renders the pinned edition separately from the request.
Failure and qualification
- The implemented documentation feature has focused tests and a local preview; the whole Manna release is gated separately.
- A source citation demonstrates where a statement came from, not that a design claim is implemented.
- Export requires read and write authority, workspace ownership, pinned rendering revision and matching asset hashes.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| request | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: api.read; consumer[0]: reader.request |
| source | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: corpus.fetch; consumer[0]: api.corpus |
| sections | H02 — Value flow {#h02--value-flow} | provider[0]: api.sections; consumer[0]: retrieval.documents |
| context | H02 — Value flow {#h02--value-flow} | provider[0]: retrieval.context; consumer[0]: model.context |
| answer | H02 — Value flow {#h02--value-flow} | provider[0]: model.answer; consumer[0]: reader.answer |
| export | H03 — Control precedence {#h03--control-precedence} | provider[0]: api.export; consumer[0]: job.start |
| store | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: pdf.put; consumer[0]: job.output |
| evidence | H28 — Evidence supports claim {#h28--evidence-supports-claim} | question[0]: reader.questionRef; sources[1]: retrieval.sourceRefs; answer[2]: model.answerRef |
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("web-manna-docs", "d8473f6e841ee283895170c8af56c0af28ae8781077ec50ec1da959a23a840fe") {
region("browser", "Browser")
region("edge", "Edge services")
region("data", "Data authorities")
node("reader", "Native documentation reader", "N11", "browser", ports = listOf(
PortDefinition("request", "P02", "DocumentationReadV1", PortPolarity.Require),
PortDefinition("answer", "P01", "CitedAnswerV1", PortPolarity.Require),
PortDefinition("questionRef", "P24", "QuestionRefV1", PortPolarity.Neutral)
))
node("api", "Documentation service", "N19", "edge", ports = listOf(
PortDefinition("read", "P02", "DocumentationReadV1", PortPolarity.Offer),
PortDefinition("corpus", "P02", "CorpusReadV1", PortPolarity.Require),
PortDefinition("sections", "P01", "SectionPackV1", PortPolarity.Offer),
PortDefinition("export", "P03", "ExportIntentV1", PortPolarity.Offer)
))
node("corpus", "Revisioned docs corpus", "N26", "data", ports = listOf(
PortDefinition("fetch", "P02", "CorpusReadV1", PortPolarity.Offer)
))
node("retrieval", "Bounded section retrieval", "N22", "edge", ports = listOf(
PortDefinition("documents", "P01", "SectionPackV1", PortPolarity.Require),
PortDefinition("context", "P01", "CitedContextV1", PortPolarity.Offer),
PortDefinition("sourceRefs", "P24", "SourceRefSetV1", PortPolarity.Neutral)
))
node("model", "Answer model adapter", "N18", "edge", ports = listOf(
PortDefinition("context", "P01", "CitedContextV1", PortPolarity.Require),
PortDefinition("answer", "P01", "CitedAnswerV1", PortPolarity.Offer),
PortDefinition("answerRef", "P24", "AnswerRefV1", PortPolarity.Neutral)
))
node("job", "PDF export workflow", "N06", "edge", ports = listOf(
PortDefinition("start", "P03", "ExportIntentV1", PortPolarity.Require),
PortDefinition("output", "P02", "EditionPutV1", PortPolarity.Require)
))
node("pdf", "Reading edition store", "N26", "data", ports = listOf(
PortDefinition("put", "P02", "EditionPutV1", PortPolarity.Offer)
))
relation("request", "H05",
Incidence("api", "read", "provider", 0),
Incidence("reader", "request", "consumer", 0)
)
relation("source", "H05",
Incidence("corpus", "fetch", "provider", 0),
Incidence("api", "corpus", "consumer", 0)
)
relation("sections", "H02",
Incidence("api", "sections", "provider", 0),
Incidence("retrieval", "documents", "consumer", 0)
)
relation("context", "H02",
Incidence("retrieval", "context", "provider", 0),
Incidence("model", "context", "consumer", 0)
)
relation("answer", "H02",
Incidence("model", "answer", "provider", 0),
Incidence("reader", "answer", "consumer", 0)
)
relation("export", "H03",
Incidence("api", "export", "provider", 0),
Incidence("job", "start", "consumer", 0)
)
relation("store", "H05",
Incidence("pdf", "put", "provider", 0),
Incidence("job", "output", "consumer", 0)
)
relation("evidence", "H28",
Incidence("reader", "questionRef", "question", 0),
Incidence("retrieval", "sourceRefs", "sources", 1),
Incidence("model", "answerRef", "answer", 2)
)
}
Tenant dashboard: scoped routes and mediated data access
Where does tenant identity become an enforced constraint?
Inspect this design · Definition JSON · revision d818d03b6443
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 |
| ⊂ N33 | Policy / principal boundary |
| ↗ N19 | Tool / external API adapter |
| ▰ N21 | Database / state authority |
| ▷ P11 | Execution / continuation |
| ⇆ P02 | Request / response |
| ⊂ P20 | Authorization request / grant |
| ◎ P24 | Inspection / evidence |
| ↪ H36 | Navigation / interaction route |
| ⊂ H23 | Scoped authorization |
| ⇆ H05 | Request / reply binding |
| ⌕ H34 | Data access / lineage |
Logic and ownership
Common Kotlin builds a typed query from validated request fields; server adapters materialize the verified tenant and principal context.
Failure and qualification
- A tenant ID supplied by a browser does not authenticate tenancy.
- Cross-workspace inspection is a separate capability and authority decision.
- The same rules must apply to cached, background and agent-initiated reads.
Hyperedge roles
| Relation | Pattern | Participants, preserving role positions |
|---|---|---|
| route | H36 — Navigation / interaction route {#h36--navigation--interaction-route} | provider[0]: route.workspace; consumer[0]: surface.route |
| grant | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: verify.context; consumer[0]: service.principal |
| read | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: service.dashboard; consumer[0]: surface.read |
| policy | H23 — Scoped authorization {#h23--scoped-authorization} | provider[0]: policy.grant; consumer[0]: service.policy |
| query | H05 — Request / reply binding {#h05--request--reply-binding} | provider[0]: db.query; consumer[0]: service.storage |
| scope | H34 — Data access / lineage {#h34--data-access--lineage} | principal[0]: verify.principalRef; policy[1]: policy.policyRef; authority[2]: db.authorityRef |
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("web-multitenant", "d818d03b64431dcd22809056e58e4e456ba90b6e7b2afdcbddce938cf6d7f0ef") {
region("browser", "Browser")
region("edge", "Edge services")
region("data", "Data authorities")
node("route", "Workspace route", "N12", "browser", ports = listOf(
PortDefinition("workspace", "P11", "WorkspaceRouteV1", PortPolarity.Offer)
))
node("surface", "Dashboard Surface", "N11", "browser", ports = listOf(
PortDefinition("route", "P11", "WorkspaceRouteV1", PortPolarity.Require),
PortDefinition("read", "P02", "DashboardReadV1", PortPolarity.Require)
))
node("verify", "Principal verifier", "N33", "edge", ports = listOf(
PortDefinition("context", "P20", "VerifiedContextV1", PortPolarity.Offer),
PortDefinition("principalRef", "P24", "PrincipalRefV1", PortPolarity.Neutral)
))
node("service", "Dashboard service", "N19", "edge", ports = listOf(
PortDefinition("principal", "P20", "VerifiedContextV1", PortPolarity.Require),
PortDefinition("dashboard", "P02", "DashboardReadV1", PortPolarity.Offer),
PortDefinition("policy", "P20", "DataGrantV1", PortPolarity.Require),
PortDefinition("storage", "P02", "ScopedQueryV1", PortPolarity.Require)
))
node("policy", "Row / resource policy", "N33", "data", ports = listOf(
PortDefinition("grant", "P20", "DataGrantV1", PortPolarity.Offer),
PortDefinition("policyRef", "P24", "PolicyRefV1", PortPolarity.Neutral)
))
node("db", "Workspace authority", "N21", "data", ports = listOf(
PortDefinition("query", "P02", "ScopedQueryV1", PortPolarity.Offer),
PortDefinition("authorityRef", "P24", "AuthorityRefV1", PortPolarity.Neutral)
))
relation("route", "H36",
Incidence("route", "workspace", "provider", 0),
Incidence("surface", "route", "consumer", 0)
)
relation("grant", "H23",
Incidence("verify", "context", "provider", 0),
Incidence("service", "principal", "consumer", 0)
)
relation("read", "H05",
Incidence("service", "dashboard", "provider", 0),
Incidence("surface", "read", "consumer", 0)
)
relation("policy", "H23",
Incidence("policy", "grant", "provider", 0),
Incidence("service", "policy", "consumer", 0)
)
relation("query", "H05",
Incidence("db", "query", "provider", 0),
Incidence("service", "storage", "consumer", 0)
)
relation("scope", "H34",
Incidence("verify", "principalRef", "principal", 0),
Incidence("policy", "policyRef", "policy", 1),
Incidence("db", "authorityRef", "authority", 2)
)
}