ADR-0017: The follower acts as the application¶
Status: Accepted
Date: 2026-10-12
Deciders: Alex Nodeland
Amends: lattice RFC-0001's subject_of table, its SourceActor row: the source artifactr is the application's own principal, not a service principal of that source's
Context¶
A follower opens each workspace in both libraries, and since lattice RFC-0001 every Workspace method asks authorize with the action it takes. With grantr wired, the template's subject_of maps each actor to a grantr subject, and checks are deny by default. RFC-0002 names the actor on every bridged envelope, SourceActor("artifactr"), and warns that no client may ever resolve to it, since rules trust it until reflexr can reserve a type to one source (lattice #8). It doesn't say whom the follower reads artifactr as, or what either actor may do.
Decision¶
- In artifactr, the follower is
SystemActor(name="relayr")(relayr.inbound.FOLLOWER). It only reads:artifactr:openandartifactr:read_events. Its cursor is in the ledger, so it needs noartifactr:save_cursororread_cursors. - In reflexr, it is
SourceActor(name="artifactr")(relayr.inbound.SOURCE), the actor RFC-0002 gives every bridged envelope. It takesreflexr:openandreflexr:publish. - In grantr, both are the application's own service principal. The template's
subject_ofmaps aSystemActorthere already, by lattice RFC-0001's table, and maps the sourceartifactrthere too, rather than to a principal of that source's own. Theapplicationrole planned in grantr's ADR-0019 holds all four actions in every tenant: everyopenand read, andreflexr:publish. - No client resolves to
SourceActor("artifactr"). The template's resolvers make users, external agents and service principals' clients, never that source.
Options considered¶
| Option | For | Against |
|---|---|---|
| The application's principal (chosen) | relayr is the application's own code, in its process; one grant, made when the application starts, covers every tenant | The application's role must hold what relayr does |
| A service principal of relayr's own | Its grants apart from the application's | A grant in every tenant, made as each is created, or the bridge stops in new tenants |
| A user, such as the workspace's admin | Nothing new in grantr | Acts with a person's authority, and misattributes every bridged event |
Consequences¶
- Easier: a new tenant's workspaces are bridged as soon as they are opened, with no grant to remember.
- Harder: until grantr's
applicationrole lands, and the template wiressubject_of(grantr's phase 4), an application that closes access with grantr must grant those four actions itself. - The test that pins the four actions is
tests/inbound/test_followers.py.