Atlassian: Jira and Confluence
Genesis reads and writes the customer's Jira and Confluence — their issues, their pages, their service account. Reads are ordinary. Writes are proposals: Genesis never lands a comment, a worklog, a transition or a page edit on a customer's system without a distinct human approving that specific write first.
Two tiers can own a site. A tenant has one Atlassian connection, used by everything under it. A product — the git-less grouping tier above projects — may instead point at its own site: its own host, its own service account, its own token. That exists because one tenant's work can span several customers, and one customer's issue comment must never reach another customer's Jira.
Status (2026-09): the product tier is default-off. The tenant lane is the shipped behaviour. Product sites are behind the
product-atlassian-sitesfeature (default off at the deploy level) and take effect only for a product that has been explicitly bound. A tenant with no bound product takes no new behaviour at all.
1. Operator guide
1.1 The three features
Atlassian is gated by three entries of the feature catalog, each with the usual two
levels: a deploy bit in the release values (services.core.features.<key>.enabled) and a per-tenant
switch on Settings → Features. They stopped being platform-config keys in the 2026-09 consolidation:
config_set on the old key names is now refused and points at the feature.
| Feature | Deploy default | Tenant default | What it gates |
|---|---|---|---|
atlassian | off | on | The whole surface. Off means every verb refuses feature_disabled. |
atlassian-writes | off | on | The write verbs only. Reads keep working when it is off. |
product-atlassian-sites | off | on | Whether a product's own site binding is honoured. |
The tenant default is ON for all three, so turning a feature on at the deploy level turns it on for every tenant that has not opted out — the behaviour the single platform-wide row used to give. A tenant admin can now opt out of any of them without a deployment, and an unreadable tenant toggle fails CLOSED (with an attention request) rather than assuming ON.
1.2 Binding the tenant's site
One connection per capability (WorkItem for Jira, KnowledgeBase for Confluence), carrying the host
and the acting account email; plus one credential — that account's API token. Atlassian Cloud
authenticates as email:token, so a connection without an email is not a partial configuration, it is
a call authenticated as somebody else. The resolver refuses it rather than sending it.
1.3 Binding a product's own site
product_atlassian_site_set (or PUT /api/v1/products/{id}/atlassian-site) takes a host, an acting
email and an API token, stores the token as a product-scoped credential, and points the product at
it. product_atlassian_site_get shows the binding without the token; product_atlassian_site_delete
removes both.
Three properties are worth knowing before you bind one:
- The flag must be on first. Binding while the tier is dark is refused, because a bound product never falls back to the tenant's site — the binding would take effect as an outage.
- Turning the flag off is not a rollback. A bound product with the flag off refuses every Atlassian
call (
product_site_disabled). The rollback is deleting the binding. - Same host is allowed, same account is not. A product may sit on the tenant's own Atlassian host, provided it uses a different account with its own token. That is the point of the tier; the credential is resolved by identity, never by host, so the two can never be confused for each other.
1.4 What a product write does
Every write to a product's own site parks for human approval, whatever the tenant's connection policy says. A tenant that opened its own writes has said nothing about a different customer's system, and consent for one is not consent for the other.
1.5 Approving a parked write
The approver sees the proposed content and whose site it is going to — host and acting account are named on the request. Approving executes the write; rejecting discards it.
If the site moved between approval and execution — re-pointed, re-credentialed, or the acting account
swapped — the write is refused, not sent (park_scope_drift). A human approved a specific write to
a specific system; that approval does not transfer to a different one. Re-propose the write against the
current binding.
1.6 Reading a refusal
| Answer | Means | What to do |
|---|---|---|
feature_disabled | A flag is off. | Turn it on. |
connection_missing | No connection, or no acting email on it. | Configure the connection. |
connection_unavailable | The lookup itself failed — whether a connection exists is unknown. | Retry; check the database. |
credential_missing | No credential with that identity. | Fix the binding. |
credential_unreadable | The row exists; its secret cannot be read (denied, absent, or no longer decryptable). | Fix the secret store or its policy. Retrying will not help. |
credential_unavailable | The secret store did not answer. | Retry. |
product_site_disabled | This product is bound, and the tier's flag is off. | Turn the flag on, or delete the binding. |
atlassian_scope_indeterminate | The call could not say which product it is acting for, and this tenant binds at least one. | Look at the caller's project binding. |
awaiting_approval | The write parked. Not a failure. | Approve or reject it. |
park_scope_drift | The site changed after the write was approved. | Re-propose against the current binding. |
The distinction between credential_missing, credential_unreadable and credential_unavailable
exists because the operator's next action is different for each, and a single "not found" sent people
to re-bind products whose bindings were already correct.
2. Architecture
2.1 The site is three headers
Every Atlassian call goes through a per-tenant sidecar. Which site it reaches is decided entirely by three request headers — the token, the acting email and the base URL. Nothing about routing changes between the tenant lane and the product lane; only which row supplied those three values.
2.2 One election
A single resolver elects the target for every read, every gated write and every approved replay, and the result it returns is threaded to both the wire and the write gate. This matters because the gate reads an approval policy off a connection: if the gate elected its own row while the client elected another, the gate could decide on one site's policy while the write went to a different site's host. One election makes that unrepresentable.
2.3 Scope: four states, two of which are opposites
A call declares its scope. Tenant is the operator surface, tenant by construction. Product names a
product. Unbound means the scope was determined and the project belongs to no bound product — it
uses the tenant's site and never refuses. Indeterminate means the scope could not be determined,
and it refuses: a call that cannot say whose Jira it is asking for must not guess. A failed read is
always Indeterminate, never Unbound — collapsing the two is how a database blip becomes a silent
wrong-site write.
2.4 The fuse
Every refusal the product tier introduces is gated on the tenant having at least one binding. A tenant that has not adopted the tier — including one whose call scope is indeterminate — behaves exactly as it did before the tier existed. There is no product site to get wrong, so the historical answer is not merely safe, it is the only correct one.
2.5 Bound means bound
Once a product carries a binding there is no fallback to the tenant's site. A missing flag, a missing credential, a dangling credential id, an unreadable secret and a blank acting email all refuse before any network call. Falling back would send one customer's write to another customer's Jira, which is the single outcome this tier exists to make impossible.
2.6 Credentials resolve by identity
A product's credential is looked up by (product, credential id) — never by (host, type). That is
what lets a product sit on the tenant's own host with a different service account, and what stops a
binding from ever authenticating with another product's credential or the tenant's. The reverse holds
too: the tenant's own credential walk excludes product rows explicitly, so a product's token can never
win a tenant lookup.
2.7 Parking and replay
A parked write stores the coordinates needed to execute it later, plus a stamp of the site it was authorised against — host, credential, acting account, and for a product its binding's row version. On approval the site is resolved fresh and compared against the stamp; a difference refuses rather than sends. A stamp compares only the parts it actually carries, so approvals raised before the stamp existed still replay exactly as they did.
Product parks additionally carry their own source discriminator. A binary older than the product tier reads such a park as foreign and never replays it — after a rollback the proposal is discarded instead of being sent to the tenant's site.
2.8 Deleting things
The bindings are protected by RESTRICT in both directions. Deleting a product that still has a
binding is refused and says so. Deleting the credential a binding points at is refused too, so a
binding that reads as bound can never point at a credential that no longer exists. The teardown order is
therefore: unbind the site (which removes its credential), then delete the product.
2.9 What is observable
Every resolution is counted by which tier's site it elected (tenant or product), and every refusal
by its code, so an operator can see both the adoption of the tier and its failure modes. Every call
records an attribution row naming the credential kind that served it — a product call attributed as a
tenant call would be a forensic lie.