Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions TRACKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

**Last updated:** 2026-05-24
**Current phase:** Phase 1 — Ingestion + Knowledge Store
**Next action:** Phase 1 Step 1.1aCore type & SPI refactor (RequestContext, typed ACL, dtype, BlobRef, QueryPlan, ChunkRef, StageEvent)
**Next action:** Phase 1 Step 1.1b — SPI split (Retrieval/Index, bulk + streaming + ID-only methods, IndexHint)

> **Refactor window (Steps 1.1a–1.1f):** Before resuming the connectors framework (1.2), we insert a six-step refactor that locks in architecture + optimization decisions which are very expensive to retrofit later (PolicyEngine PDP, RequestContext-threaded SPIs, split Retrieval/Index backends, bulk + streaming + ID-only methods, Pipeline + Batcher primitives, three-way cache split, hot-path discipline). See [docs/adr/ADR-0005…0009] and [docs/architecture/policy-engine.md], [request-context.md], [caching.md], [performance.md].

Expand All @@ -32,14 +32,14 @@
| Phase | Title | Steps | ✅ Done | Remaining |
|-------|-------|------:|-------:|----------:|
| 0 | Foundation | 13 | **13** | 0 |
| 1 | Ingestion + Knowledge Store | 16 | **1** | 15 |
| 1 | Ingestion + Knowledge Store | 16 | **2** | 14 |
| 2 | Retrieval Engine | 11 | 0 | 11 |
| 3 | Gateway & Agent Runtime | 11 | 0 | 11 |
| 4 | Reliability | 6 | 0 | 6 |
| 5 | Eval & Observability | 7 | 0 | 7 |
| 6 | Governance & Tenancy | 10 | 0 | 10 |
| 7 | Pilot, Harden, GA | 10 | 0 | 10 |
| **Total** | | **84** | **14** | **70** |
| **Total** | | **84** | **15** | **69** |

---

Expand Down Expand Up @@ -68,7 +68,7 @@
| Step | Title | Status | Branch | PR | Key Deliverables |
|------|-------|--------|--------|----|-----------------|
| 1.1 | Storage backends | ✅ | `build/phase-1/step-1.1-storage-backends` | [#40](https://github.com/officialCodeWork/AgentContextOS/pull/40) | `rag-backends` package: `PgVectorStore` (asyncpg + pgvector, ivfflat), `QdrantVectorStore` (query_points API), `RedisCache`, `S3Storage` (aioboto3, MinIO-compatible), `LocalFileStorage`; integration tests (skip-if-no-service); MinIO added to dev stack; `task test-integration` + `task test-backends`; ADR-0004 |
| 1.1a | Core type & SPI refactor | | | | `RequestContext` frozen model threaded through every SPI; `tenant_id` + `acl_labels` typed required on `Chunk`/`Embedding` (not metadata dict); `trust_level` on `Chunk` for prompt-injection defense; `dtype` on `Embedding` (float32/int8/binary); `BlobRef` for lazy chunk text; `QueryPlan` + `ChunkRef` types; typed `StageEvent`. Conformance tests updated. ADR-0005 (PolicyEngine) + ADR-0008 (cost-aware planner) referenced. |
| 1.1a | Core type & SPI refactor | | `build/phase-1/step-1.1a-core-type-spi-refactor` | _pending_ | `RequestContext` frozen model threaded through every SPI; `tenant_id` + `acl_labels` typed required on `Chunk`/`Embedding` (not metadata dict); `trust_level` on `Chunk` for prompt-injection defense; `dtype` on `Embedding` (float32/int8/binary); `BlobRef` for lazy chunk text; `QueryPlan` + `ChunkRef` + `Cost` + `PlanNode` types; typed `StageEvent`. `tests/contract/spi_signature.py` linter (RequestContext-first); rag-backends (`PgVectorStore`, `QdrantVectorStore`, `RedisCache`, `S3Storage`, `LocalFileStorage`) migrated; conformance + integration tests updated; `Budget.spend()` for agent-loop sub-turn budgets; schemas regenerated. ADR-0005 / ADR-0007 / ADR-0008 / ADR-0009 referenced. |
| 1.1b | SPI split — Retrieval/Index, bulk + streaming + ID-only | ⏳ | 1.1a | — | Split `VectorStore`/`KeywordStore`/`GraphStore` into `RetrievalBackend` (read) + `IndexBackend` (write); add `bulk_embed`/`bulk_index`/`bulk_delete`; add async-iterator ingest variants; add `retrieve_ids` + `hydrate` pair; add `IndexHint` parameter for scale-tier index selection. ADR-0009 (vector index strategy) authored. |
| 1.1c | PolicyEngine package | ⏳ | 1.1a | — | New `packages/policy/` (`rag-policy`): `PolicyEngine` SPI + noop impl; single decision point consulted by every retrieval/ingest path for ACL, PII, quotas, redaction. Replaces scattered checks across Steps 1.7, 4.5, 6.3, 6.5. ADR-0005 finalized. |
| 1.1d | Pipeline + Batcher primitives | ⏳ | 1.1a | — | `Pipeline` primitive in `rag-core`: async DAG with bounded queues, per-stage worker counts, backpressure (used by Step 1.10 write path). `Batcher[Req, Resp]` middleware (DataLoader pattern) coalescing concurrent SPI calls into batched provider calls; sits under Embedder/Reranker SPIs. |
Expand Down
86 changes: 82 additions & 4 deletions dist/schemas/Chunk.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,53 @@
{
"description": "A contiguous piece of a Document produced by the chunking pipeline.",
"$defs": {
"BlobRef": {
"description": "Reference to a blob stored in the ``Storage`` SPI rather than inline.\n\nUsed by chunks whose text exceeds the inline-storage threshold (see\nADR-0007 tiered storage). Callers must hydrate via ``Storage.get(uri)``\nonly when the text is actually needed.",
"properties": {
"uri": {
"title": "Uri",
"type": "string"
},
"size_bytes": {
"title": "Size Bytes",
"type": "integer"
},
"content_type": {
"default": "text/plain; charset=utf-8",
"title": "Content Type",
"type": "string"
},
"sha256": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Sha256"
}
},
"required": [
"uri",
"size_bytes"
],
"title": "BlobRef",
"type": "object"
},
"TrustLevel": {
"description": "Provenance of a chunk's text \u2014 used by the prompt-injection defense.\n\n``trusted`` \u2014 first-party content authored under tenant control.\n``ingested`` \u2014 content fetched from a known external source (vetted feed,\n enterprise SharePoint, etc.).\n``user_supplied`` \u2014 content directly contributed by an end-user channel\n (web upload, chat-attached file, \u2026) which may contain\n adversarial instructions.",
"enum": [
"trusted",
"ingested",
"user_supplied"
],
"title": "TrustLevel",
"type": "string"
}
},
"description": "A contiguous piece of a Document produced by the chunking pipeline.\n\nStep 1.1a promoted three governance-relevant fields out of the\n``metadata`` dict into typed required fields:\n\n- ``acl_labels`` \u2014 set of ACL labels the PolicyEngine compares against\n the requesting principal's ``acl_labels``.\n- ``trust_level`` \u2014 provenance, used by the prompt-injection defense.\n- ``content_ref`` \u2014 optional ``BlobRef`` for tiered text storage; when set,\n ``content`` may be ``None`` and callers must hydrate via Storage.",
"properties": {
"id": {
"title": "Id",
Expand All @@ -18,8 +66,27 @@
"type": "string"
},
"content": {
"title": "Content",
"type": "string"
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Content"
},
"content_ref": {
"anyOf": [
{
"$ref": "#/$defs/BlobRef"
},
{
"type": "null"
}
],
"default": null
},
"position": {
"title": "Position",
Expand Down Expand Up @@ -49,6 +116,18 @@
"default": null,
"title": "Token Count"
},
"acl_labels": {
"items": {
"type": "string"
},
"title": "Acl Labels",
"type": "array",
"uniqueItems": true
},
"trust_level": {
"$ref": "#/$defs/TrustLevel",
"default": "ingested"
},
"metadata": {
"additionalProperties": true,
"title": "Metadata",
Expand All @@ -64,7 +143,6 @@
"document_id",
"tenant_id",
"corpus_id",
"content",
"position"
],
"title": "Chunk",
Expand Down
31 changes: 30 additions & 1 deletion dist/schemas/Embedding.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
{
"description": "Dense vector representation of a Chunk.",
"$defs": {
"EmbeddingDtype": {
"description": "Numeric representation of an embedding vector at rest.\n\n``float32`` \u2014 full-precision (default).\n``int8`` \u2014 quantized 8-bit integers (\u22484\u00d7 smaller, slight recall loss).\n``binary`` \u2014 1-bit per dim packed (\u224832\u00d7 smaller, larger recall loss,\n used as a coarse first-stage in two-stage retrieval).\n\nSee ADR-0009 for the vector index + quantization strategy.",
"enum": [
"float32",
"int8",
"binary"
],
"title": "EmbeddingDtype",
"type": "string"
}
},
"description": "Dense vector representation of a Chunk.\n\nStep 1.1a promoted ``tenant_id`` and ``acl_labels`` to typed required\nfields and added ``dtype`` to capture int8 / binary quantization.",
"properties": {
"chunk_id": {
"title": "Chunk Id",
"type": "string"
},
"tenant_id": {
"title": "Tenant Id",
"type": "string"
},
"model": {
"title": "Model",
"type": "string"
Expand All @@ -20,6 +36,18 @@
"title": "Dimension",
"type": "integer"
},
"dtype": {
"$ref": "#/$defs/EmbeddingDtype",
"default": "float32"
},
"acl_labels": {
"items": {
"type": "string"
},
"title": "Acl Labels",
"type": "array",
"uniqueItems": true
},
"created_at": {
"format": "date-time",
"title": "Created At",
Expand All @@ -28,6 +56,7 @@
},
"required": [
"chunk_id",
"tenant_id",
"model",
"vector",
"dimension"
Expand Down
10 changes: 9 additions & 1 deletion dist/schemas/Principal.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"type": "string"
}
},
"description": "Authenticated identity \u2014 user, service account, or group.",
"description": "Authenticated identity \u2014 user, service account, or group.\n\n``acl_labels`` is the set of ACL labels the principal carries; it is the\n*typed* counterpart of the ``acl_labels`` field on ``Chunk`` /\n``Embedding``. The PolicyEngine compares the two during retrieval.",
"properties": {
"id": {
"title": "Id",
Expand Down Expand Up @@ -46,6 +46,14 @@
},
"title": "Roles",
"type": "array"
},
"acl_labels": {
"items": {
"type": "string"
},
"title": "Acl Labels",
"type": "array",
"uniqueItems": true
}
},
"required": [
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
|------|-------------|
| [ragctl.md](reference/ragctl.md) | Full `ragctl` command reference — public usage, internals, extension points |
| [backends.md](reference/backends.md) | `rag-backends` reference — PgVectorStore, QdrantVectorStore, RedisCache, S3Storage, LocalFileStorage |
| [rag-core.md](reference/rag-core.md) | `rag-core` type surface — `RequestContext`, `Budget`, `BlobRef`, `QueryPlan`, `ChunkRef`, `StageEvent` |

## guides/

Expand Down
14 changes: 9 additions & 5 deletions docs/architecture/request-context.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# RequestContext — the per-request envelope

**Status:** Implemented in Step 1.1a (PR landing the `RequestContext` type,
ctx-first SPI signatures, and the `tests/contract/spi_signature.py` linter).

## Overview

`RequestContext` is a frozen Pydantic v2 model that travels with every SPI call. It carries everything downstream layers need to make correct, governed, budgeted decisions without reaching back to global state or guessing.
Expand All @@ -22,14 +25,15 @@ A single typed envelope on every call signature eliminates all three.
class RequestContext(BaseModel):
model_config = {"frozen": True}

request_id: str # ULID; round-trips with the trace
tenant_id: str # required; non-empty
principal: Principal # user/service identity + ACL set
pii_policy: PiiPolicy # per-tenant: redact | mask | encrypt | tag-only | block
request_id: RequestId # ULID-like ID; round-trips with the trace
tenant_id: TenantId # required; matched against principal.tenant_id
principal: Principal # user/service identity + ACL labels
pii_policy: PiiPolicy # per-tenant: redact | mask | encrypt | tag_only | block | allow
trace: TraceContext # OTel span + correlation IDs
budget: Budget # tokens, cost (dollars), wall_ms, max_iter
budget: Budget # tokens, dollars, wall_ms, max_iter
feature_flags: frozenset[str] # for shadow mode, A/B, killswitches
corpus_routing_hint: str | None # optional sticky routing across agent-loop turns
created_at: datetime # autopopulated at construction
```

`Principal`, `PiiPolicy`, `TraceContext`, `Budget` are all frozen Pydantic models in `rag_core.types`.
Expand Down
Loading
Loading