Skip to main content

Governance Segments

Most AxonFlow policies apply to a whole organization. A governance segment narrows a policy to an organizational unit inside that organization: a team, a business unit, a cost center. The classic case is one shared backend used by everybody, where the governing rule differs by who is acting. Redact PII for the support team's chat, block it outright for finance, against the same Jira instance, the same database, the same connector.

Segment targeting is orthogonal to the organization boundary. It does not isolate data. It selects which policy applies.

Enterprise feature

Governance segments are an Enterprise capability, because they resolve from the SCIM-synced directory and Community builds have no identity-attribute resolver. The segment_id column exists in every deployment and is always empty in Community, where segment targeting is inert rather than partially applied.

What a segment is

A governance segment is a SCIM group. There is no parallel team directory to maintain, no second place for membership to drift out of sync. If your identity provider already syncs groups to AxonFlow through SCIM provisioning, you already have segments.

Three properties follow from that, and they are the reason segments are the right dimension for policy that must not be self-selected:

  • Membership is verified, not asserted. AxonFlow resolves the caller's segments server-side from the directory, keyed on the caller's verified identity. Membership is never read from a claim inside a token and never from a field in the request body. This is the same trust model already used for role resolution, and for the same reason: an identity-provider misconfiguration must not be able to escalate.
  • Membership is administered where your other access decisions are. Adding someone to the finance group in your IdP puts them in the finance segment. Removing them removes it. Policy follows the directory.
  • A segment is org-scoped. Segments belong to one organization and are meaningless outside it.

Segments versus the tenant label

AxonFlow has an older sub-organization dimension that also selects policy: the tenant label carried on the request, described in the Auth And Header Matrix. It remains supported and is the right tool for separating credentials and applications.

It is the wrong tool for governance that must hold against the person it governs, because it is chosen by the caller rather than resolved from a directory. A governance dimension a caller supplies is one a caller can select. Segments exist so that policy targeting rests on a fact the platform verifies rather than on a value the request carries.

Both dimensions coexist. A policy can be scoped by tenant, by segment, by both, or by neither.

How a policy becomes segment-scoped

A policy row carries a nullable segment_id:

  • segment_id is empty: the policy is not segment-scoped. It applies exactly as it did before segment targeting existed. This is the default and it covers the overwhelming majority of policies.
  • segment_id is set: the policy applies only to callers whose resolved segment set contains that value.

Two details matter when you author one:

The value is the stable group id, not the group's display name. Renaming a group in your identity provider must not silently re-target a policy that was authored against it, so the targeting key is the identifier rather than the label.

segment_id is independent of the policy's tier. A policy is segment-scoped if and only if segment_id is set, whether its tier is system, organization or tenant. There is no separate segment tier, and adding a segment to a policy does not change what tier it belongs to.

A caller can belong to more than one segment. Every policy scoped to any of the caller's segments is selected, alongside every policy that is not segment-scoped at all, so widening someone's group membership can only add restrictions to the set evaluated against them.

Authoring surface

On platform v10.0.0 the segment targeting key is enforcement-side only. The policy APIs and the customer portal policy editor do not yet carry a segment field, so a segment-scoped policy cannot currently be created or edited through them. Enforcement is complete on the planes listed below and reads whatever segment_id the policy row holds. If you want to pilot segment-scoped governance before the authoring surface lands, raise it with your AxonFlow contact rather than writing to the policy tables yourself.

Where segments are enforced

Segment targeting was delivered per enforcement surface rather than everywhere at once. This table describes platform v10.0.0. Read it before you rely on a segment-scoped policy: the point of publishing it is that a gap is a stated fact rather than something discovered later.

Enforcement surfacePolicies it evaluatesSegment-scoped policiesFirst enforced
Agent request plane (POST /api/request)staticEnforcedv9.14.0
Orchestrator dynamic-policy evaluation, which backs the request plane, MAP and the workflow planesdynamicEnforcedv9.17.0
MAP (Multi-Agent Planning), pre-execution and per-step gatesdynamicEnforced, through the orchestrator evaluation abovev9.17.0
Gateway pre-check (POST /api/policy/pre-check)static only, by designEnforcedv10.0.0
Workflow Control Plane HTTP step-gatedynamicEnforcedv10.0.0
MCP-server check_policy and check_output toolsstaticEnforcedv10.0.0
MCP REST policy checks (/api/v1/mcp/check-input, /api/v1/mcp/check-output) and the MCP query and execute routesstatic and dynamicEnforcedv10.0.0
Decision API (POST /api/v1/decide)static onlyEnforcedv10.0.0
MCP policy evaluation (POST /api/v1/mcp/evaluate-policies)dynamicEnforced, against the segment set the agent resolved and passed throughv10.0.0
Policy preview (POST /api/policies/test) and the portal policy simulatorbothEnforced, and deliberately faithful to the enforcement pathtracks the plane it previews
OpenAI-compatible chat completions (POST /v1/chat/completions)staticNot consulted

First enforced records when segment-scoped policies were first honoured on that surface. It is not a promise that the surface behaved in every other respect as it does today: in particular the fail-closed refusal described below is the v10.0.0 contract, and earlier releases did not refuse uniformly across planes. If you are running an earlier release, treat this page as describing where you are going rather than where you are.

The policies it evaluates column is load-bearing, so read the row before relying on it. Gateway pre-check evaluates static policies only and never calls the orchestrator, so a segment-scoped dynamic policy does not apply there even though the row reads "Enforced". Conversely a segment-scoped static policy is not what a Workflow Control Plane step-gate consults. Match the kind of policy you authored to the surface you expect it to hold on.

The preview surfaces are converged with enforcement on purpose: they resolve segments the same way and fail closed the same way, so a preview does not report an outcome the real plane would not produce.

The one surface that does not consult them

POST /v1/chat/completions, the OpenAI-compatible endpoint, is the single enforcement surface where a segment-scoped policy is not part of the evaluation. Be precise about the consequence in both directions:

  • It is not a mis-application. The plane never applies the wrong segment's policy to a caller. There is no escalation path here.
  • It is incomplete coverage. A rule you expect to constrain the finance team does not constrain them on this surface, because the rule is not consulted at all.

The cause is structural rather than an oversight, and it is the same one that governs the whole feature: segment membership resolves from a verified human identity, and this endpoint has none to resolve from. It mirrors OpenAI's wire shape, which has no field in which to carry a per-user token, so an Enterprise caller authenticates with the shared credential alone and its identity is a synthetic per-credential one rather than a validated person. There is no human principal on the request, so there is nothing to look up in the directory. Extending segment governance to callers that are machines rather than people is separate, larger work: it needs a verified machine principal first.

What to do about it. If POST /v1/chat/completions is in your request path and you depend on a segment-scoped control, pair it with a policy that carries no segment. A policy that is not segment-scoped is consulted on every surface that evaluates policies of its kind, so it holds the floor there while the segment-scoped rule adds the narrower restriction everywhere segments are enforced. Routing that traffic through a plane that does carry a per-user identity is the other option: see Choosing a Mode.

What happens when no identity is presented

A governed request that carries no verified per-user identity is the ordinary, supported case, not an error. It resolves to no segments and proceeds organization-only:

  • Policies that are not segment-scoped enforce exactly as they always have.
  • Segment-scoped policies do not apply, because there is no membership to match.

The same result follows when the deployment has no segment resolver configured, and when resolution succeeds and the caller genuinely belongs to no group. All three are legitimate outcomes and none of them is treated as a failure.

This is why enabling segments does not by itself break existing traffic. Every request that worked before segment targeting existed continues to take the same path.

One posture changes this

There is a deployment and per-organization setting that makes a per-user token required rather than optional on the enterprise gate points. It exists because "no identity resolves to no segments" is the safe answer for a genuine non-member and the wrong answer for a member who simply declined to identify themselves: without it, dropping one header switches a segment-scoped control off for exactly the person it was written to restrict.

It is off by default, deployment-wide and per organization, so the paragraph above is the default behaviour. Where it is turned on, a caller presenting no verified per-user identity is refused instead of proceeding organization-only. Turn it on deliberately, alongside adopting segment-scoped policies, and confirm your callers present a token first. See Per-User Token Provisioning.

What happens when resolution fails

A genuine resolution failure is different from an absent identity. If AxonFlow can reach a verified identity but cannot determine its segments because the directory lookup itself failed, the request is denied.

This is deliberate and it is the whole point of the design. Treating a lookup failure as "proceed with no segments" would mean an outage in the directory path silently disables every segment-scoped restriction, which is exactly the fail-open bypass segments exist to close.

Two things about the shape of that denial matter to anyone writing a client:

The HTTP status differs by plane, so do not key on it either. The gateway pre-check answers 200 with the request not approved, and the Workflow Control Plane step-gate answers 200 carrying a block decision, because on those planes a refusal is a governance verdict rather than a failure to serve the request. The agent request plane, the Decision API and the MCP REST routes all answer 403. The MCP-server tools answer at the tool level, carrying the guard identifier rather than an HTTP status of their own.

None of them answers a 5xx, so a client that treats "denied" as an infrastructure error will misread every one of them. The Decision API does have a 503, but it means something different: policy evaluation was unavailable, which is not a segment-resolution refusal.

Key on the identifier, never on the reason text. The refusal carries the reserved policy identifier:

segment_resolution_failed

It appears in the response field that lists the policies which fired, and on the audit record for the denial. Every plane emits that exact identifier. The accompanying human-readable reason is not a stable contract: its wording and punctuation differ between planes, so a client that matches on the sentence will work on one surface and silently fail on another. Match the identifier.

A second refusal on the MCP-server plane

The MCP-server check_policy and check_output tools carry a second, distinct refusal, and it is conditional on what you have authored:

segment_identity_unresolved

It fires when the call presents no verified per-user identity and either of the following holds for that organization and phase: the policy set contains at least one enabled segment-scoped policy, or the policy set could not be read at all, leaving it unknown whether the verdict depends on segments. In both cases the call is refused before evaluation rather than evaluated against a segment set known to be, or possibly, incomplete.

A deployment that has never authored a segment-scoped policy never reaches this refusal, and neither does one with no segment resolver configured.

The operational consequence is worth stating plainly, because it is the one way authoring a segment-scoped policy changes behaviour for callers the policy was never aimed at: on and after v10.0.0, enabling a segment-scoped policy for a phase makes a verified per-user token effectively required on that phase's MCP-server tool. Callers that were passing without one begin to be refused. Organizations with no segment-scoped policy are unaffected, which is why the requirement is conditional rather than global.

Plan for that before you enable the first segment-scoped policy: confirm your MCP-server callers present a per-user token, or expect the refusal.

On the preview surfaces the same condition is reported rather than enforced: the simulator answers with the verdict a real request would have received, so a preview never disagrees with the plane it is previewing.

Telling "no segment applied" from "a segment was considered"

The policy preview response carries an informational segments_resolved flag. It is true only when resolution succeeded and returned at least one segment, which lets an administrator distinguish two verdicts that otherwise look identical:

  • allowed because no segment-scoped policy restricted this caller, and
  • allowed after a real, non-empty segment membership was genuinely considered.

The flag never changes a verdict. It is false for every ordinary organization-only case and for the fail-closed denial above.