Skip to content

Commit cde2d4c

Browse files
committed
feat: add context abi contracts
1 parent 9c791dd commit cde2d4c

28 files changed

Lines changed: 1454 additions & 13 deletions

.blitz/test_state_v1/indexes/task_states.ndjson

Lines changed: 215 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ The workspace currently contains these active families:
7878
`outer_brain_persistence`, `outer_brain_runtime`,
7979
`outer_brain_restart_authority`, and `outer_brain_quality` for the core
8080
semantic runtime.
81-
- `outer_brain_prompting`, `prompt_fabric`, `context_budget`,
82-
`memory_contracts`, `memory_engine`, `guardrail_contracts`,
81+
- `outer_brain_context_abi`, `outer_brain_prompting`, `prompt_fabric`,
82+
`context_budget`, `memory_contracts`, `memory_engine`, `guardrail_contracts`,
8383
`guardrail_engine`, `eval_runner`, and `token_meter` for prompt/context,
8484
memory, guardrail, eval, and cost-sensitive semantic support.
8585
- `outer_brain_authority_evidence`, `ai_artifact_contracts`, and
@@ -181,6 +181,8 @@ Adaptive layer additions:
181181
- `core/ai_artifact_contracts`: ref-only artifact identity for prompt, role,
182182
skill, GEPA, eval, replay, router, provider, endpoint, promotion, and
183183
rollback refs.
184+
- `core/context_abi`: ref-only Context ABI packet/unit/receipt/failure
185+
contracts and deterministic packet hashes for governed model execution.
184186
- `core/optimization_artifact_store`: ref-only artifact graph history for
185187
candidate lineage, eval evidence, promotion, and rollback decisions.
186188

build_support/dependency_sources.config.exs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,28 @@ siblings_root = Path.expand("..", repo_root)
33

44
%{
55
deps: %{
6+
ground_plane_contracts: %{
7+
path: Path.join(siblings_root, "ground_plane/core/ground_plane_contracts"),
8+
github: %{
9+
repo: "nshkrdotcom/ground_plane",
10+
branch: "main",
11+
subdir: "core/ground_plane_contracts"
12+
},
13+
hex: "~> 0.1.0",
14+
default_order: [:path, :github, :hex],
15+
publish_order: [:hex]
16+
},
17+
jido_integration_provider_classification: %{
18+
path: Path.join(siblings_root, "jido_integration/core/provider_classification"),
19+
github: %{
20+
repo: "agentjido/jido_integration",
21+
branch: "main",
22+
subdir: "core/provider_classification"
23+
},
24+
hex: "~> 0.1.0",
25+
default_order: [:path, :github, :hex],
26+
publish_order: [:hex]
27+
},
628
citadel_domain_surface: %{
729
path: Path.join(siblings_root, "citadel/surfaces/citadel_domain_surface"),
830
github: %{

build_support/weld.exs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ defmodule OuterBrain.Build.WeldContract do
1111

1212
@repo_root Path.expand("..", __DIR__)
1313

14+
@manifest_dependencies [
15+
:ground_plane_contracts,
16+
:jido_integration_provider_classification,
17+
:mezzanine_eval_engine
18+
]
19+
1420
@artifact_docs [
1521
"README.md",
1622
"docs/overview.md",
@@ -33,6 +39,7 @@ defmodule OuterBrain.Build.WeldContract do
3339
publication: [
3440
internal_only: [
3541
".",
42+
"core/context_abi",
3643
"core/memory_contracts",
3744
"core/memory_engine",
3845
"core/context_budget",
@@ -77,22 +84,37 @@ defmodule OuterBrain.Build.WeldContract do
7784
end
7885

7986
defp dependencies do
80-
[
81-
mezzanine_eval_engine: manifest_dependency(:mezzanine_eval_engine)
82-
]
87+
Enum.map(@manifest_dependencies, fn app ->
88+
{app, manifest_dependency(app)}
89+
end)
8390
end
8491

8592
defp manifest_dependency(app) do
86-
case DependencySources.deps(@repo_root, publish?: true) |> List.keyfind(app, 0) do
87-
{^app, requirement} when is_binary(requirement) ->
88-
[requirement: requirement]
93+
config = Map.fetch!(dependency_configs(), app)
94+
github = Map.fetch!(config, :github)
95+
96+
[opts: github_opts(github)]
97+
end
98+
99+
defp dependency_configs do
100+
{config, _binding} =
101+
@repo_root
102+
|> Path.join("build_support/dependency_sources.config.exs")
103+
|> Code.eval_file()
104+
105+
Map.new(config[:deps], fn {app, dep_config} -> {app, Map.new(dep_config)} end)
106+
end
107+
108+
defp github_opts(github) do
109+
github = Map.new(github)
110+
repo = Map.fetch!(github, :repo)
89111

90-
{^app, requirement, opts} when is_binary(requirement) ->
91-
[requirement: requirement, opts: opts]
112+
opts =
113+
github
114+
|> Map.take([:branch, :ref, :tag, :subdir])
115+
|> Enum.sort_by(fn {key, _value} -> key end)
92116

93-
{^app, opts} when is_list(opts) ->
94-
[opts: opts]
95-
end
117+
Keyword.merge([github: repo], opts)
96118
end
97119
end
98120

build_support/workspace_contract.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ defmodule OuterBrain.Build.WorkspaceContract do
66
"core/outer_brain_journal",
77
"core/outer_brain_persistence",
88
"core/outer_brain_core",
9+
"core/context_abi",
910
"core/outer_brain_prompting",
1011
"core/outer_brain_quality",
1112
"core/outer_brain_runtime",

core/context_abi/.formatter.exs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[
2+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
3+
]

core/context_abi/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# OuterBrain Context ABI
2+
3+
Ref-only Context ABI contracts for governed model execution.
4+
5+
This package owns the MVP context packet surface, deterministic packet hashes,
6+
context unit validation, context packet receipts, and owner-local failure
7+
reason-code shape. It does not render provider-native payloads, authorize
8+
restricted context, execute models, or persist workflow truth.
9+
10+
The package uses `GroundPlane.Boundary.Codec` through GroundPlane contracts for
11+
canonical boundary encoding and `sha256:` digest generation.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
defmodule OuterBrain.ContextABI do
2+
@moduledoc """
3+
Public facade for the OuterBrain Context ABI MVP.
4+
"""
5+
6+
alias OuterBrain.ContextABI.{Compiler, ContextPacket, ContextPacketReceipt, Failure}
7+
8+
@spec compile(Compiler.compile_request(), keyword()) ::
9+
{:ok, ContextPacket.t(), ContextPacketReceipt.t()} | {:error, Failure.t()}
10+
def compile(request, opts \\ []) do
11+
compiler = Keyword.get(opts, :compiler, Compiler)
12+
compiler.compile(request, Keyword.delete(opts, :compiler))
13+
end
14+
end
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
defmodule OuterBrain.ContextABI.Canonical do
2+
@moduledoc """
3+
Canonical encoding and digest helpers for Context ABI facts.
4+
"""
5+
6+
alias GroundPlane.Boundary.Codec
7+
alias OuterBrain.ContextABI.ContextPacket
8+
9+
@spec digest(term()) :: String.t()
10+
def digest(term), do: term |> normalize_for_boundary() |> Codec.digest()
11+
12+
@spec packet_hash(ContextPacket.t()) :: String.t()
13+
def packet_hash(%ContextPacket{} = packet) do
14+
packet
15+
|> ContextPacket.hash_input()
16+
|> digest()
17+
end
18+
19+
@spec normalize_for_boundary(term()) :: term()
20+
def normalize_for_boundary(%{__struct__: _} = value),
21+
do: value |> Map.from_struct() |> normalize_for_boundary()
22+
23+
def normalize_for_boundary(%{} = map) do
24+
map
25+
|> Enum.map(fn {key, value} -> {to_string(key), normalize_for_boundary(value)} end)
26+
|> Map.new()
27+
end
28+
29+
def normalize_for_boundary(values) when is_list(values),
30+
do: Enum.map(values, &normalize_for_boundary/1)
31+
32+
def normalize_for_boundary(value) when is_atom(value), do: Atom.to_string(value)
33+
def normalize_for_boundary(value), do: value
34+
end
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
defmodule OuterBrain.ContextABI.Compiler do
2+
@moduledoc """
3+
Behaviour and deterministic MVP compiler for Context ABI packets.
4+
"""
5+
6+
alias OuterBrain.ContextABI.{ContextPacket, ContextPacketReceipt, Failure}
7+
8+
@type compile_request :: %{
9+
required(:tenant_ref) => String.t(),
10+
required(:user_request_ref) => String.t(),
11+
required(:system_instruction_ref) => String.t(),
12+
optional(:memory_refs) => [String.t()],
13+
required(:budget_ref) => String.t(),
14+
required(:model_class_allowlist) => [String.t()],
15+
required(:route_policy_ref) => String.t(),
16+
required(:trace_ref) => String.t()
17+
}
18+
19+
@callback compile(compile_request(), keyword()) ::
20+
{:ok, ContextPacket.t(), ContextPacketReceipt.t()} | {:error, Failure.t()}
21+
22+
@spec compile(compile_request(), keyword()) ::
23+
{:ok, ContextPacket.t(), ContextPacketReceipt.t()} | {:error, Failure.t()}
24+
def compile(request, opts \\ [])
25+
26+
def compile(request, opts) when is_map(request) and is_list(opts) do
27+
request
28+
|> ContextPacket.new()
29+
|> case do
30+
{:ok, packet} -> {:ok, packet, ContextPacketReceipt.compiled(packet)}
31+
{:error, %Failure{} = failure} -> {:error, failure}
32+
end
33+
end
34+
35+
def compile(_request, _opts) do
36+
{:ok, failure} =
37+
Failure.new(%{
38+
owner: :outer_brain,
39+
reason_code: "outer_brain.context.invalid_compile_request.v1",
40+
safe_message: "context compile request is invalid"
41+
})
42+
43+
{:error, failure}
44+
end
45+
end

0 commit comments

Comments
 (0)