8.1 KiB
Assumptions — assumptions and decisions of this RI
This document explains what was assumed when building the Reference Implementation (RI) and
why, distinguishing that from what is an architectural guarantee of the reference
architecture. It is a synthesis — not a copy — of the decision history recorded
in docs/adr/; each ADR remains the canonical record of an individual
decision, this document groups the "why" by theme for whoever is evaluating the RI.
Target audience: whoever is going to evaluate or adapt this RI for a real scenario and needs to know what was assumed versus what is a guarantee of the architecture.
General scope
We assume that an RI proves security properties, it is not a production-ready product.
Every decision below prioritizes verifiably demonstrating the architecture's invariants
(MaximumEntitlement as a ceiling, fail-closed, never elevate privilege by context) over
operational completeness (HA, scale, UI). Where the two collided, we chose the simplest RI
that still proves the real property against a real dependency — never a mock of the very
point being tested.
Identity and PDP: closed technologies, not hypotheses to revisit
We assume Keycloak as Identity Provider and OPA/Rego as PDP because they are OSS (Apache-2.0)
and adherent to open standards (OAuth 2.1/OIDC, Rego), not out of arbitrary preference. This
resolves two gaps that the reference architecture left open (README.md §48, questions
1 and 3) with a definitive technical decision, not an assumption — they were never revisited
throughout the implementation. See docs/adr/ADR-019-identity-extension.md,
docs/adr/ADR-025-engine-do-pdp.md.
We rejected a custom PDP engine in Python (more control, but reinvents policy evaluation with no real gain) and Cedar (also would be adequate, but OPA has greater adherence to "open standards" and a more mature Rego community for the scope of this RI).
Operational reference Python/LangGraph/Langfuse (Agent Platform OCI)
We assume as the concrete operational reference the Agent Platform OCI project by Christiano
Hoshikawa (docs/research/hoshikawa-agent-platform-oci.md) for the
LangGraph/Langfuse/FastMCP layer, instead of inventing a generic pattern from scratch — faster,
fewer ad hoc decisions, and a real point of comparison for what "multiagent orchestration"
means in practice. We reuse from that reference: StateGraph with a router/supervisor per
backend, pluggable checkpointing, the IC/NOC/GRL observability taxonomy with hybrid
instrumentation (automatic spans + fail-open manual events), identity.yaml/BusinessContext
to normalize identity across channels, FastMCP as the MCP server standard.
We explicitly rejected a single element of that reference: its tool authorization model via
a static allowlist evaluated over an agent_id that arrives as data from the conversation's
input payload, not as a claim from an independently verified authenticated identity — the
reference project itself admits that this does not replace real authentication/authorization.
That is exactly the anti-pattern form that the architecture forbids
(ADR-001/ADR-002/ADR-003). The RI reuses the proxy shape of that Gateway
(invocation/result contracts, per-tool cache, catalog) only at the Fabric/conversational UX
layer — the ALLOW/DENY decision remains 100% in our PEP/PDP, never in a self-declared
agent_id. See docs/adr/ADR-022-referencia-hoshikawa-agent-platform-oci.md,
docs/adr/ADR-023-autorizacao-nunca-vem-do-payload.md. This finding also motivated a dedicated
adversarial scenario (tests/adversarial/test_payload_identity_spoofing.py).
Downstream identity
We assume token exchange (RFC 8693) when the backend supports OIDC, with a fallback to a
service account isolated per adapter when it does not — because always reusing the client's
token (the simpler alternative) is exactly the "blind token passthrough" that the architecture
forbids (inbound ≠ outbound identity). See docs/adr/ADR-020-downstream-identity.md.
Client profile granularity
We assume domain + risk tier (e.g.: Sales.Read=R1, Sales.Write=R2,
Finance.Payments=R3) as the client profile granularity, instead of a single "enterprise
admin" client or domain-only without tier — because only this granularity allows proving
blast-radius segmentation between risk tiers within the same domain (README.md §7, §17,
§31). See docs/adr/ADR-008-segmentacao-por-dominio-e-risco.md.
Profile Intelligence: deterministic stub, not "real AI"
We assume that "generic and replaceable" Profile Intelligence (README.md §6.10) does not
prescribe an algorithm, taxonomy, or real data source — because the reference architecture does
not define any of these, deliberately. The RI implements a stub based on deterministic rules
over synthetic attributes, behind a replaceable interface (ProfileIntelligenceProvider),
which fulfills the contract, not the "intelligence" itself. A production fork replaces only
the implementation, never the contract (ProfileView) nor the point where it connects (never
to the PDP).
Domain scope: two, not full federation
We assume two example domains (Sales, Finance) as sufficient to prove segmentation/blast-radius between distinct domains, without needing full multi-domain federation. Federation is deliberately out of scope for this RI — it is addressed in the reference architecture's roadmap as a later phase (§47, Phase 5), not an implementation gap.
Environment: 100% local via Docker Compose
We assume that an RI runs entirely locally via docker compose, with environment
separation demonstrated by a configuration overlay (config/env/{dev,ci}.yaml) instead of
real cloud/hybrid infrastructure — proving the architecture does not require multi-cloud, and
simulating multi-cloud without real multi-cloud would prove nothing beyond the simulation
itself.
Substitutions to enable testing without heavy infrastructure
- Local JWKS server as a stand-in for Keycloak in most of the e2e suite — valid because
what is being tested there is the token validation logic (signature,
exp,iss,aud, extraction ofazp), which is identical against any valid RS256 JWKS. Real protocol integration with Keycloak (client_credentialsgrant, real claims issued by a real IdP, RFC 8693) is covered separately, against a real Keycloak 26.7.3 via Docker (tests/e2e/test_real_keycloak.py) — it is not the same test, it is a complementary test that covers exactly what the stand-in cannot. - SQLite instead of Postgres for the Registry and for the LangGraph checkpointer — valid to
prove the contract/behavior (schema, lifecycle, graph pause/resume); it is not a claim
about performance or concurrency under production load (see
Production-Recommendations.md). policy_versionas a file hash, not a real OPA bundle revision — a SHA-256 of the content of the.regofiles on disk is enough to prove thatpolicy_versionflows end to end through every decision and audit event; it is not a claim about policy distribution in a production cluster.
Items deliberately out of scope
- REST adapter without a live path through the Gateway (EP-06-T04): implemented and tested standalone; none of this RI's example backends is REST, so there is no live path through the Gateway exercising it. It would only become relevant if a future domain needed a non-MCP-native backend.
- LangGraph deliberately absent from the Gateway/Fabric — used only where there is real
state, cycles, or checkpointing (Service Orchestrator, EP-11; Agent Runtime handoff, EP-12-T03).
No simple routing (Gateway EP-05, Fabric EP-06, Offering Filter EP-10) uses LangGraph —
using a stateful graph for stateless routing would be over-engineering, not a neutral choice.
See
docs/adr/ADR-021-escopo-langgraph-langfuse.md. - Rate limiting and anti-replay: real, conscious gaps, not oversights — documented and
covered by a dedicated adversarial test (
tests/adversarial/test_protocol_identity.py), never silently ignored. SeeProduction-Recommendations.mdfor what a real deployment needs to add.