Charter: orion

Generated from docs/ai/charters/orion.md. Edit that file, then regenerate: python docs/portfolio/_build/generate_reference_pages.py.


Status: written 2026-08-24, from the code and the commit history, with the origin confirmed by its author.

What it is

A clean-sheet engine. Orion was developed independently of DataADK — not forked from it, not a variant of it — and moved to ADK 2.0 afterwards.

That is worth stating plainly, because the repository invites the opposite reading: orion/ sits beside argus/ under systems/, both trees reach the same initial commit, and Orion is the only engine on ADK 2.x. “The 2.0 port of the old pipeline” is the natural inference from those three facts, and it is wrong.

The history agrees with the account. Argus reaches the initial import through a rename from dataadk/ (d098ed93); Orion does not, and no commit moves files between the two trees. By 2026-04-04 — four days after the ai/ import, and four days before Argus was renamed at all — 2d59afe0 records “Orion passes all E2E tests and registers in verified systems registry”.

The file inventories say the same thing. The two share only the interface every engine must implement — __init__.py, agent.py, system.py, tools_adapter.py. Beyond that:

argus (the DataADK line) orion
auth.py, config.py, response_converter.py investigation_manager.py, context_manager.py, context_models.py
six eval/diagnostic scripts sql_guardrails.py, memory_service.py, t3_memory.py, eval_cdc.py

An investigation manager, a context manager with its own models, explicit SQL guardrails and a three-tier memory service are a different architecture, not a re-expression of the same one. DataADK and Argus have no counterpart to any of them.

ADK 2.0 came later

Orion runs on ADK 2.x and the other engines do not. ai/pyproject.toml carries two features for exactly this reason, and says so:

# ── Feature: adk (Google ADK 1.x — KavApps kavai_server parity) ────
# Kept version-identical with KavApps backend/kavai_server pins …
# Orion does NOT run here (its Workflow pipeline requires ADK 2.x).
google-adk = ">=1.26.0,<2"

# ── Feature: adk2 (Google ADK 2.x — main line) ─────────────────────
google-adk = ">=2.5.0,<3"

The 2.x dependency was acquired, not original. On 2026-07-18, fc4e7071 — “port pipeline from deprecated SequentialAgent to ADK 2.0 Workflow (#294)” — moved Orion off SequentialAgent onto Workflow. Before that it ran the same 1.x primitive the others do.

So the sequence is: built independently, then upgraded. Orion is the engine that went first to ADK 2.0, four months after it existed — which is why it is the only one there, and why the 1.x feature in pyproject.toml has to say “Orion does NOT run here”.

Today agent.py chains three LlmAgent nodes as workflow nodes under google.adk.workflow.Workflow.

What it is for

The next-generation multi-agent pipeline: investigation management, managed context, SQL guardrails, and T3 memory. Where Argus is the improvement track of a known-good design, Orion is where a different design is tried.

Standing as measured

Engine certification 2026-08-09: 8 of 9 rows, certifiable — level with Argus and Kawa, skipping only provenance. Its climb was 5/8 → 5/8 → 5/8 → 6/8 → 7/9 → 8/9; it became certifiable on 08-09, a day after Argus and Kawa.

Cross-engine benchmark 2026-07-19: 85% pass — the lowest of the four — with the highest median latency of the ADK engines (18.7 s) and the fewest median tool calls (1), producing the shortest median responses. One single-turn miss, the same multi-turn context-carryover image failures as Argus, and two late infra/auth errors.

That benchmark predates the ADK 2.0 port (#294, 2026-07-18) by one day and the transient-retry fix (#301) by a day more. It is measuring an Orion that no longer exists, and nothing has re-run it since.

Must never

The invariants are the same for every engine, and each names its mechanism:

  • Answer over data the caller cannot see — scope row (FR-AI-08, mandatory), CONTRACT-API-001 RLS.
  • Emit a signed URL or storage path — CONTRACT-CDC-001 §7.4.1, image-browsing row.
  • Emit an undefined AG-UI event — CONTRACT-CDC-001, lint-enforced.
  • Leave test residue in a real dataset — test-data-hygiene row, mandatory.

sql_guardrails.py — what it is, and what it is not

Orion alone holds sql_guardrails.py. The name invites the wrong reading, so:

It is not an access control. Tenancy is RLS’s job, and the module never mentions an organization, auth.uid, or a service role — a test now asserts that it never starts to. A second, weaker copy of a control the database already enforces would rot silently.

It is a determinism control. It makes two model behaviours reliable that would otherwise be probabilistic:

enforce_entity_scope injects WHERE i.id IN (…) for the entities under discussion, whether or not the model wrote the clause
ensure_distinct_on_annotation_join + deduplicate_result_rows stop annotation joins fanning out duplicate rows, in the SQL and again in the result

The distinction from RLS is worth holding precisely. RLS answers may this caller see this row. The guardrails answer is this query about the right rows, and does it return each of them once. A caller-scoped connection with perfect RLS will still answer “how many anomalies?” with a count inflated by a join, or answer about a whole dataset when the user said “in these three images” — and every row it returned was one the caller was entitled to see. RLS cannot help with a confidently wrong number.

What it guarantees is an upper bound, not a match. Injection is by AND, so the guardrail can only narrow. A query the model scoped to a subset of the context stays a subset; a query scoped outside the context intersects to nothing. The second direction fails closed, which is the important half. The first produces a narrow answer, and no amount of injecting fixes it — a real fix would have to replace the model’s clause, which is a different design.

Coverage: 39 unit tests in ai/tests/systems/orion/test_sql_guardrails.py, including the limits above. No certification row exercises any of it — the scope row is FR-AI-08 tenancy scope, a different property. So a regression in entity scoping or de-duplication would surface as a plausible wrong number rather than a failed gate.

Open

  • No certification row covers the guardrails. They have unit tests; the engine suite has no row that would fail if entity scoping or de-duplication broke in a deployed engine.
  • ensure_distinct_on_annotation_join matches table names as substrings. Fixed 2026-08-24: it now matches the table in table position — after FROM or JOIN, schema-qualification allowed — so a column called annotations_count no longer draws a DISTINCT that would collapse rows a query legitimately repeats.
  • T3 memory crosses a tenancy boundary by construction — it persists across turns and possibly across sessions. Nothing in the certification suite tests that memory is scoped to the caller.
  • The only cross-engine benchmark predates the ADK 2.0 port. Orion’s 85% is a number for a pipeline that has since been replaced.