rememberstack 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rememberstack/__init__.py +9 -0
- rememberstack/adapters/__init__.py +42 -0
- rememberstack/adapters/codex_writer.py +221 -0
- rememberstack/adapters/markitdown_converter.py +42 -0
- rememberstack/adapters/openrouter.py +136 -0
- rememberstack/adapters/selfhost/__init__.py +54 -0
- rememberstack/adapters/selfhost/forget.py +66 -0
- rememberstack/adapters/selfhost/git.py +374 -0
- rememberstack/adapters/selfhost/lance.py +328 -0
- rememberstack/adapters/selfhost/minio.py +279 -0
- rememberstack/adapters/selfhost/mounts.py +249 -0
- rememberstack/adapters/selfhost/object_store.py +130 -0
- rememberstack/adapters/selfhost/projection.py +80 -0
- rememberstack/adapters/selfhost/queue.py +137 -0
- rememberstack/adapters/selfhost/telemetry.py +45 -0
- rememberstack/adapters/selfhost/watcher.py +70 -0
- rememberstack/adapters/testing/__init__.py +15 -0
- rememberstack/adapters/testing/cost_meter.py +13 -0
- rememberstack/adapters/testing/model_provider.py +83 -0
- rememberstack/adapters/testing/queue.py +43 -0
- rememberstack/adapters/testing/telemetry.py +22 -0
- rememberstack/client.py +19 -0
- rememberstack/core/__init__.py +127 -0
- rememberstack/core/blockizer.py +189 -0
- rememberstack/core/chunker.py +216 -0
- rememberstack/core/consumption_skill.py +275 -0
- rememberstack/core/conversion.py +76 -0
- rememberstack/core/core_manifest.py +598 -0
- rememberstack/core/extension_packs.py +124 -0
- rememberstack/core/forget.py +17 -0
- rememberstack/core/knowledge_authored.py +276 -0
- rememberstack/core/knowledge_compile.py +215 -0
- rememberstack/core/knowledge_fact_sheet.py +210 -0
- rememberstack/core/knowledge_hashing.py +68 -0
- rememberstack/core/knowledge_planner.py +64 -0
- rememberstack/core/knowledge_writer.py +175 -0
- rememberstack/core/ranking.py +200 -0
- rememberstack/core/recipe_linter.py +149 -0
- rememberstack/core/section_snap.py +209 -0
- rememberstack/core/storage_routing.py +27 -0
- rememberstack/eval/__init__.py +53 -0
- rememberstack/eval/consumption.py +141 -0
- rememberstack/eval/contradiction.py +184 -0
- rememberstack/eval/harness.py +136 -0
- rememberstack/eval/lifecycle.py +400 -0
- rememberstack/eval/operational_scale.py +49 -0
- rememberstack/eval/resolution.py +255 -0
- rememberstack/eval/retrieval_spikes.py +50 -0
- rememberstack/eval/skeleton.py +231 -0
- rememberstack/llm/__init__.py +1 -0
- rememberstack/model/__init__.py +589 -0
- rememberstack/model/adjudication.py +100 -0
- rememberstack/model/auth.py +27 -0
- rememberstack/model/blocks.py +30 -0
- rememberstack/model/chunks.py +190 -0
- rememberstack/model/claims.py +162 -0
- rememberstack/model/client.py +98 -0
- rememberstack/model/clustering.py +54 -0
- rememberstack/model/component_version.py +124 -0
- rememberstack/model/consumption.py +88 -0
- rememberstack/model/conversion.py +31 -0
- rememberstack/model/deployment.py +53 -0
- rememberstack/model/documents.py +168 -0
- rememberstack/model/envelope.py +513 -0
- rememberstack/model/evaluation.py +72 -0
- rememberstack/model/forget.py +143 -0
- rememberstack/model/git.py +13 -0
- rememberstack/model/knowledge.py +840 -0
- rememberstack/model/knowledge_authored.py +325 -0
- rememberstack/model/knowledge_planner.py +431 -0
- rememberstack/model/lifecycle.py +42 -0
- rememberstack/model/model_provider.py +78 -0
- rememberstack/model/mounts.py +24 -0
- rememberstack/model/object_store.py +21 -0
- rememberstack/model/operational_scale.py +59 -0
- rememberstack/model/operations.py +153 -0
- rememberstack/model/processing.py +228 -0
- rememberstack/model/queue.py +73 -0
- rememberstack/model/recipes.py +83 -0
- rememberstack/model/relations.py +79 -0
- rememberstack/model/resolution.py +83 -0
- rememberstack/model/retrieval_spikes.py +62 -0
- rememberstack/model/sections.py +120 -0
- rememberstack/model/telemetry.py +30 -0
- rememberstack/ports/__init__.py +29 -0
- rememberstack/ports/auth.py +16 -0
- rememberstack/ports/connector.py +23 -0
- rememberstack/ports/cost_meter.py +17 -0
- rememberstack/ports/forget.py +20 -0
- rememberstack/ports/git.py +20 -0
- rememberstack/ports/model_provider.py +28 -0
- rememberstack/ports/mounts.py +16 -0
- rememberstack/ports/object_store.py +27 -0
- rememberstack/ports/p1_index.py +92 -0
- rememberstack/ports/purge.py +93 -0
- rememberstack/ports/queue.py +23 -0
- rememberstack/ports/telemetry.py +21 -0
- rememberstack/profiles/__init__.py +22 -0
- rememberstack/profiles/selfhost.py +324 -0
- rememberstack/profiles/selfhost_forget.py +158 -0
- rememberstack/profiles/selfhost_operations.py +95 -0
- rememberstack/py.typed +1 -0
- rememberstack/spine/__init__.py +93 -0
- rememberstack/spine/admission.py +26 -0
- rememberstack/spine/backfill.py +168 -0
- rememberstack/spine/catalog_contract.py +742 -0
- rememberstack/spine/chunk_catalog.py +237 -0
- rememberstack/spine/claim_catalog.py +298 -0
- rememberstack/spine/clustering.py +740 -0
- rememberstack/spine/component_versions.py +208 -0
- rememberstack/spine/consumption.py +81 -0
- rememberstack/spine/deployment_bootstrap.py +445 -0
- rememberstack/spine/document_catalog.py +621 -0
- rememberstack/spine/entity_registry.py +205 -0
- rememberstack/spine/extension_packs.py +220 -0
- rememberstack/spine/fact_catalog.py +571 -0
- rememberstack/spine/forget.py +1753 -0
- rememberstack/spine/knowledge.py +5467 -0
- rememberstack/spine/lifecycle.py +1071 -0
- rememberstack/spine/migrations/__init__.py +1 -0
- rememberstack/spine/migrations/_helpers.py +153 -0
- rememberstack/spine/migrations/env.py +58 -0
- rememberstack/spine/migrations/script.py.mako +27 -0
- rememberstack/spine/migrations/versions/__init__.py +1 -0
- rememberstack/spine/migrations/versions/p0_02_0001_extensions_enums.py +189 -0
- rememberstack/spine/migrations/versions/p0_02_0002_infrastructure_registries.py +321 -0
- rememberstack/spine/migrations/versions/p0_02_0003_entities_evaluation_e0_e1.py +631 -0
- rememberstack/spine/migrations/versions/p0_02_0004_claims_facts_evidence.py +411 -0
- rememberstack/spine/migrations/versions/p0_02_0005_projection_knowledge_retrieval.py +391 -0
- rememberstack/spine/migrations/versions/p0_02_0006_partitions_views.py +158 -0
- rememberstack/spine/migrations/versions/p2_06_0007_invalidated_outcome.py +26 -0
- rememberstack/spine/migrations/versions/p3_01_0008_document_version_target.py +58 -0
- rememberstack/spine/migrations/versions/p3_05_0009_reconcile_stage.py +27 -0
- rememberstack/spine/migrations/versions/p3_07_0010_lifecycle_eval_suite.py +25 -0
- rememberstack/spine/migrations/versions/p4_01_0011_survivor_view_rewrite.py +57 -0
- rememberstack/spine/migrations/versions/p6_02_0012_knowledge_compile_recovery.py +58 -0
- rememberstack/spine/migrations/versions/p6_04_0013_knowledge_writer_ledger.py +46 -0
- rememberstack/spine/migrations/versions/p6_05_0014_knowledge_planner_runtime.py +217 -0
- rememberstack/spine/migrations/versions/p6_06_0015_authored_dispatch_runtime.py +38 -0
- rememberstack/spine/migrations/versions/p7_02_0016_operational_eval_suite.py +19 -0
- rememberstack/spine/migrations/versions/p7_05_0017_hard_forget.py +55 -0
- rememberstack/spine/observation_adjudication.py +778 -0
- rememberstack/spine/operations.py +298 -0
- rememberstack/spine/projection.py +662 -0
- rememberstack/spine/recipes.py +276 -0
- rememberstack/spine/resolver.py +763 -0
- rememberstack/spine/review.py +650 -0
- rememberstack/spine/settings.py +22 -0
- rememberstack/spine/supersession.py +510 -0
- rememberstack/spine/sync.py +128 -0
- rememberstack/spine/work_ledger.py +816 -0
- rememberstack/surfaces/__init__.py +110 -0
- rememberstack/surfaces/cli.py +447 -0
- rememberstack/surfaces/consumption_skill.py +87 -0
- rememberstack/surfaces/graph_queries.py +698 -0
- rememberstack/surfaces/http_api.py +377 -0
- rememberstack/surfaces/mcp.py +67 -0
- rememberstack/surfaces/query_engine.py +1591 -0
- rememberstack/surfaces/recipe_executor.py +185 -0
- rememberstack/surfaces/recipe_surface.py +219 -0
- rememberstack/surfaces/remote_mcp.py +133 -0
- rememberstack/surfaces/sdk.py +324 -0
- rememberstack/workers/__init__.py +155 -0
- rememberstack/workers/base.py +312 -0
- rememberstack/workers/e0.py +577 -0
- rememberstack/workers/e1.py +425 -0
- rememberstack/workers/e2.py +525 -0
- rememberstack/workers/e3.py +434 -0
- rememberstack/workers/forget.py +299 -0
- rememberstack/workers/knowledge_authored.py +146 -0
- rememberstack/workers/knowledge_driver.py +735 -0
- rememberstack/workers/knowledge_fact_sheet.py +123 -0
- rememberstack/workers/knowledge_planner.py +325 -0
- rememberstack/workers/knowledge_writer.py +393 -0
- rememberstack/workers/operations.py +42 -0
- rememberstack/workers/p1.py +234 -0
- rememberstack/workers/p2.py +513 -0
- rememberstack/workers/p2_analytics.py +276 -0
- rememberstack/workers/p3.py +673 -0
- rememberstack/workers/reconcile.py +485 -0
- rememberstack/workers/sync.py +168 -0
- rememberstack-0.1.0.dist-info/METADATA +213 -0
- rememberstack-0.1.0.dist-info/RECORD +186 -0
- rememberstack-0.1.0.dist-info/WHEEL +4 -0
- rememberstack-0.1.0.dist-info/entry_points.txt +2 -0
- rememberstack-0.1.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Typed, bounded operational inspection and dead-letter replay values."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
from pydantic import ConfigDict
|
|
8
|
+
from pydantic import Field
|
|
9
|
+
|
|
10
|
+
from rememberstack.model.processing import ProcessingStatus
|
|
11
|
+
from rememberstack.model.processing import ProcessingTarget
|
|
12
|
+
from rememberstack.model.queue import PipelineStage
|
|
13
|
+
from rememberstack.model.queue import ProcessingLane
|
|
14
|
+
from rememberstack.model.queue import QueueRoute
|
|
15
|
+
from rememberstack.model.queue import UTCDateTime
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PipelineRouteStatus(BaseModel):
|
|
19
|
+
"""One deployment route/status aggregate; the enum vocabulary bounds its size."""
|
|
20
|
+
|
|
21
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
22
|
+
|
|
23
|
+
stage: PipelineStage
|
|
24
|
+
lane: ProcessingLane | None
|
|
25
|
+
status: ProcessingStatus
|
|
26
|
+
count: int = Field(ge=0)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DeadLetterGroup(BaseModel):
|
|
30
|
+
"""One dead-letter aggregate used to spot a failing version or exception."""
|
|
31
|
+
|
|
32
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
33
|
+
|
|
34
|
+
stage: PipelineStage
|
|
35
|
+
error_class: str
|
|
36
|
+
component_version: str
|
|
37
|
+
count: int = Field(ge=1)
|
|
38
|
+
oldest_enqueued_at: UTCDateTime
|
|
39
|
+
latest_finished_at: UTCDateTime | None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class DeadLetterRecord(BaseModel):
|
|
43
|
+
"""One bounded DLQ sample retaining the complete diagnostic and replay input."""
|
|
44
|
+
|
|
45
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
46
|
+
|
|
47
|
+
processing_id: UUID
|
|
48
|
+
target_kind: ProcessingTarget
|
|
49
|
+
target_id: UUID
|
|
50
|
+
stage: PipelineStage
|
|
51
|
+
component_version: str
|
|
52
|
+
content_hash: str
|
|
53
|
+
lane: ProcessingLane | None
|
|
54
|
+
attempts: int = Field(ge=0)
|
|
55
|
+
max_attempts: int = Field(ge=1)
|
|
56
|
+
error_class: str
|
|
57
|
+
last_error: str | None
|
|
58
|
+
payload: dict[str, object] | None
|
|
59
|
+
enqueued_at: UTCDateTime
|
|
60
|
+
finished_at: UTCDateTime | None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class DeadLetterReport(BaseModel):
|
|
64
|
+
"""Deployment DLQ totals plus independently bounded aggregate/detail samples."""
|
|
65
|
+
|
|
66
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
67
|
+
|
|
68
|
+
total: int = Field(ge=0)
|
|
69
|
+
group_total: int = Field(ge=0)
|
|
70
|
+
groups: tuple[DeadLetterGroup, ...]
|
|
71
|
+
items: tuple[DeadLetterRecord, ...]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class PoisonTargetRecord(BaseModel):
|
|
75
|
+
"""A target dead-lettered by at least two component versions for one stage."""
|
|
76
|
+
|
|
77
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
78
|
+
|
|
79
|
+
target_kind: ProcessingTarget
|
|
80
|
+
target_id: UUID
|
|
81
|
+
stage: PipelineStage
|
|
82
|
+
component_version_total: int = Field(ge=2)
|
|
83
|
+
component_versions: tuple[str, ...]
|
|
84
|
+
dead_letters: int = Field(ge=2)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class PoisonTargetReport(BaseModel):
|
|
88
|
+
"""Total poison targets and a bounded sample."""
|
|
89
|
+
|
|
90
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
91
|
+
|
|
92
|
+
total: int = Field(ge=0)
|
|
93
|
+
items: tuple[PoisonTargetRecord, ...]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class ProjectionSnapshotState(BaseModel):
|
|
97
|
+
"""The current P2 or P3 snapshot pointer, if that plane has one."""
|
|
98
|
+
|
|
99
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
100
|
+
|
|
101
|
+
snapshot_id: UUID
|
|
102
|
+
plane: Literal["P2_graph", "P3_corpusfs"]
|
|
103
|
+
version: str
|
|
104
|
+
store_uri: str
|
|
105
|
+
row_counts: dict[str, object] | None
|
|
106
|
+
built_at: UTCDateTime
|
|
107
|
+
published_at: UTCDateTime | None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class CurrencyMismatch(BaseModel):
|
|
111
|
+
"""A claim whose cached currency differs from the append-only ledger truth."""
|
|
112
|
+
|
|
113
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
114
|
+
|
|
115
|
+
claim_id: UUID
|
|
116
|
+
cached_current: bool
|
|
117
|
+
ledger_current: bool
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class CurrencyLedgerAudit(BaseModel):
|
|
121
|
+
"""Deployment claim count and bounded currency-ledger mismatch evidence."""
|
|
122
|
+
|
|
123
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
124
|
+
|
|
125
|
+
claims: int = Field(ge=0)
|
|
126
|
+
mismatch_total: int = Field(ge=0)
|
|
127
|
+
mismatches: tuple[CurrencyMismatch, ...]
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class OperationalReport(BaseModel):
|
|
131
|
+
"""One coherent, deployment-scoped operational inspection snapshot."""
|
|
132
|
+
|
|
133
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
134
|
+
|
|
135
|
+
deployment_id: UUID
|
|
136
|
+
generated_at: UTCDateTime
|
|
137
|
+
routes: tuple[PipelineRouteStatus, ...]
|
|
138
|
+
dead_letters: DeadLetterReport
|
|
139
|
+
poison_targets: PoisonTargetReport
|
|
140
|
+
latest_projections: tuple[ProjectionSnapshotState, ...]
|
|
141
|
+
currency: CurrencyLedgerAudit
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class DeadLetterReplayResult(BaseModel):
|
|
145
|
+
"""Authoritative route and due time after reopening one dead-letter row."""
|
|
146
|
+
|
|
147
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
148
|
+
|
|
149
|
+
processing_id: UUID
|
|
150
|
+
route: QueueRoute
|
|
151
|
+
not_before: UTCDateTime
|
|
152
|
+
attempts: int = Field(ge=0)
|
|
153
|
+
max_attempts: int = Field(ge=1)
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""Typed records for the D67 work ledger: enqueue, claim, attempt, and cost rows."""
|
|
2
|
+
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
from enum import StrEnum
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from pydantic import ConfigDict
|
|
9
|
+
from pydantic import Field
|
|
10
|
+
|
|
11
|
+
from rememberstack.model.queue import PipelineStage
|
|
12
|
+
from rememberstack.model.queue import ProcessingLane
|
|
13
|
+
from rememberstack.model.queue import UTCDateTime
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ProcessingTarget(StrEnum):
|
|
17
|
+
"""Exact values of the binding Postgres ``processing_target`` enum."""
|
|
18
|
+
|
|
19
|
+
DOCUMENT = "document"
|
|
20
|
+
DOCUMENT_VERSION = "document_version"
|
|
21
|
+
DOCUMENT_SECTION = "document_section"
|
|
22
|
+
CHUNK = "chunk"
|
|
23
|
+
CLAIM = "claim"
|
|
24
|
+
RELATION = "relation"
|
|
25
|
+
OBSERVATION = "observation"
|
|
26
|
+
ENTITY = "entity"
|
|
27
|
+
SNAPSHOT = "snapshot"
|
|
28
|
+
KNOWLEDGE_ARTIFACT = "knowledge_artifact"
|
|
29
|
+
KNOWLEDGE_DISPATCH = "knowledge_dispatch"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ProcessingStatus(StrEnum):
|
|
33
|
+
"""Exact values of the binding Postgres ``processing_status`` enum."""
|
|
34
|
+
|
|
35
|
+
PENDING = "pending"
|
|
36
|
+
RUNNING = "running"
|
|
37
|
+
SUCCEEDED = "succeeded"
|
|
38
|
+
FAILED = "failed"
|
|
39
|
+
DEAD_LETTER = "dead_letter"
|
|
40
|
+
SKIPPED = "skipped"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class DeferReason(StrEnum):
|
|
44
|
+
"""Exact values of the binding Postgres ``processing_defer_reason`` enum (D67)."""
|
|
45
|
+
|
|
46
|
+
SCHEDULED = "scheduled"
|
|
47
|
+
RETRY_BACKOFF = "retry_backoff"
|
|
48
|
+
BUDGET = "budget"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class EnqueueWork(BaseModel):
|
|
52
|
+
"""One unit of work to insert into ``processing_state`` (D12 idempotency key)."""
|
|
53
|
+
|
|
54
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
55
|
+
|
|
56
|
+
deployment_id: UUID
|
|
57
|
+
target_kind: ProcessingTarget
|
|
58
|
+
target_id: UUID
|
|
59
|
+
stage: PipelineStage
|
|
60
|
+
component_version: str
|
|
61
|
+
content_hash: str
|
|
62
|
+
lane: ProcessingLane | None
|
|
63
|
+
payload: dict[str, object] | None = None
|
|
64
|
+
not_before: UTCDateTime | None = None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class EnqueueOutcome(BaseModel):
|
|
68
|
+
"""What an enqueue did: created a row, promoted its lane, or found it existing."""
|
|
69
|
+
|
|
70
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
71
|
+
|
|
72
|
+
processing_id: UUID
|
|
73
|
+
created: bool
|
|
74
|
+
promoted_to_steady: bool
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class BackfillSeedRequest(BaseModel):
|
|
78
|
+
"""One version-bump campaign to enumerate into the backfill lane."""
|
|
79
|
+
|
|
80
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
81
|
+
|
|
82
|
+
deployment_id: UUID
|
|
83
|
+
stage: PipelineStage
|
|
84
|
+
component_version: str = Field(min_length=1)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class BackfillSeedResult(BaseModel):
|
|
88
|
+
"""Outcome of one bounded, restartable seeder transaction."""
|
|
89
|
+
|
|
90
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
91
|
+
|
|
92
|
+
selected: int = Field(ge=0)
|
|
93
|
+
created: int = Field(ge=0)
|
|
94
|
+
already_present: int = Field(ge=0)
|
|
95
|
+
complete: bool
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class ClaimedWork(BaseModel):
|
|
99
|
+
"""A claimed ``processing_state`` row, running its ``attempt``-th handler execution."""
|
|
100
|
+
|
|
101
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
102
|
+
|
|
103
|
+
processing_id: UUID
|
|
104
|
+
deployment_id: UUID
|
|
105
|
+
target_kind: ProcessingTarget
|
|
106
|
+
target_id: UUID
|
|
107
|
+
stage: PipelineStage
|
|
108
|
+
component_version: str
|
|
109
|
+
content_hash: str
|
|
110
|
+
lane: ProcessingLane | None
|
|
111
|
+
attempt: int = Field(ge=1)
|
|
112
|
+
payload: dict[str, object] | None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class CostBudget(BaseModel):
|
|
116
|
+
"""One explicit spend ceiling for a deployment, stage, lane, and fixed window."""
|
|
117
|
+
|
|
118
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
119
|
+
|
|
120
|
+
deployment_id: UUID
|
|
121
|
+
stage: PipelineStage
|
|
122
|
+
lane: ProcessingLane | None
|
|
123
|
+
window_seconds: int = Field(gt=0)
|
|
124
|
+
ceiling_usd: Decimal = Field(gt=Decimal(0))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class BudgetParked(BaseModel):
|
|
128
|
+
"""A due work row parked before its next handler attempt because spend is exhausted."""
|
|
129
|
+
|
|
130
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
131
|
+
|
|
132
|
+
processing_id: UUID
|
|
133
|
+
resume_at: UTCDateTime
|
|
134
|
+
spent_usd: Decimal = Field(ge=Decimal(0))
|
|
135
|
+
ceiling_usd: Decimal = Field(gt=Decimal(0))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class CostTierSpend(BaseModel):
|
|
139
|
+
"""Current-window spend attributed to one recorded cascade tier."""
|
|
140
|
+
|
|
141
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
142
|
+
|
|
143
|
+
tier: str | None
|
|
144
|
+
cost_usd: Decimal = Field(ge=Decimal(0))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class CostBudgetStatus(BaseModel):
|
|
148
|
+
"""Admin-visible state derived from one configured ceiling and the durable ledgers."""
|
|
149
|
+
|
|
150
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
151
|
+
|
|
152
|
+
deployment_id: UUID
|
|
153
|
+
stage: PipelineStage
|
|
154
|
+
lane: ProcessingLane | None
|
|
155
|
+
window_seconds: int = Field(gt=0)
|
|
156
|
+
window_started_at: UTCDateTime
|
|
157
|
+
window_ends_at: UTCDateTime
|
|
158
|
+
ceiling_usd: Decimal = Field(gt=Decimal(0))
|
|
159
|
+
spent_usd: Decimal = Field(ge=Decimal(0))
|
|
160
|
+
remaining_usd: Decimal = Field(ge=Decimal(0))
|
|
161
|
+
exhausted: bool
|
|
162
|
+
parked_work: int = Field(ge=0)
|
|
163
|
+
tiers: tuple[CostTierSpend, ...]
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class RecordCall(BaseModel):
|
|
167
|
+
"""One billed model/provider call to attribute to the claimed row's attempt.
|
|
168
|
+
|
|
169
|
+
Attribution fields (stage, lane, attempt) are copied from the locked
|
|
170
|
+
``processing_state`` row by the spine and can never be supplied here (D67).
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
174
|
+
|
|
175
|
+
processing_id: UUID
|
|
176
|
+
call_key: str
|
|
177
|
+
model_name: str | None = None
|
|
178
|
+
tier: str | None = None
|
|
179
|
+
tokens_in: int | None = None
|
|
180
|
+
tokens_out: int | None = None
|
|
181
|
+
cost_usd: Decimal | None = None
|
|
182
|
+
latency_ms: int | None = None
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class RunResultOutcome(StrEnum):
|
|
186
|
+
"""How one worker pass ended for the row it claimed (or that none was due)."""
|
|
187
|
+
|
|
188
|
+
NO_WORK = "no_work"
|
|
189
|
+
BUDGET_PARKED = "budget_parked"
|
|
190
|
+
SUCCEEDED = "succeeded"
|
|
191
|
+
RETRY_SCHEDULED = "retry_scheduled"
|
|
192
|
+
DEAD_LETTERED = "dead_lettered"
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class WorkLedgerError(Exception):
|
|
196
|
+
"""Base error for work-ledger operations."""
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class BackfillNotDrainedError(WorkLedgerError):
|
|
200
|
+
"""Search-index maintenance was requested while backfill work was unresolved."""
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class LaneRouteError(WorkLedgerError):
|
|
204
|
+
"""A lane value that is illegal for the stage's route (D67 pairing rule)."""
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class WorkNotFoundError(WorkLedgerError):
|
|
208
|
+
"""A ``processing_id`` that does not exist in ``processing_state``."""
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class WorkNotRunningError(WorkLedgerError):
|
|
212
|
+
"""An operation that requires a running attempt hit a non-running row."""
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class WorkNotDeadLetterError(WorkLedgerError):
|
|
216
|
+
"""An operation that requires a dead-letter row hit another status."""
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class NonRetryableHandlerError(Exception):
|
|
220
|
+
"""A handler failure classified as permanent: the work dead-letters immediately."""
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class HandlerAlreadyRegisteredError(Exception):
|
|
224
|
+
"""A second handler registration for a stage that already has one."""
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class UnknownStageHandlerError(Exception):
|
|
228
|
+
"""A claimed stage with no registered handler."""
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""D67 queue-route snapshots and the binding Postgres stage/lane vocabulary."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from datetime import timedelta
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
from typing import TypeAlias
|
|
8
|
+
from uuid import UUID
|
|
9
|
+
|
|
10
|
+
from pydantic import AfterValidator
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
from pydantic import ConfigDict
|
|
13
|
+
from pydantic import Field
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PipelineStage(StrEnum):
|
|
17
|
+
"""Exact values of the binding Postgres ``pipeline_stage`` enum."""
|
|
18
|
+
|
|
19
|
+
INGEST = "ingest"
|
|
20
|
+
CONVERT = "convert"
|
|
21
|
+
STRUCTURE = "structure"
|
|
22
|
+
CROSSREF = "crossref"
|
|
23
|
+
CHUNK = "chunk"
|
|
24
|
+
EMBED_CHUNK = "embed_chunk"
|
|
25
|
+
EXTRACT_CLAIMS = "extract_claims"
|
|
26
|
+
EMBED_CLAIM = "embed_claim"
|
|
27
|
+
GROUND_CLAIMS = "ground_claims"
|
|
28
|
+
RESOLVE_ENTITIES = "resolve_entities"
|
|
29
|
+
NORMALIZE_RELATIONS = "normalize_relations"
|
|
30
|
+
ADJUDICATE_SUPERSESSION = "adjudicate_supersession"
|
|
31
|
+
ADJUDICATE_OBSERVATIONS = "adjudicate_observations"
|
|
32
|
+
EMBED_RELATION = "embed_relation"
|
|
33
|
+
LABEL_RELATION = "label_relation"
|
|
34
|
+
EMBED_OBSERVATION = "embed_observation"
|
|
35
|
+
LABEL_OBSERVATION = "label_observation"
|
|
36
|
+
REFRESH_PROFILE = "refresh_profile"
|
|
37
|
+
BUILD_SNAPSHOT = "build_snapshot"
|
|
38
|
+
DETECT_COMMUNITIES = "detect_communities"
|
|
39
|
+
COMPILE_KNOWLEDGE = "compile_knowledge"
|
|
40
|
+
REFLECT_KNOWLEDGE = "reflect_knowledge"
|
|
41
|
+
LINT_KNOWLEDGE = "lint_knowledge"
|
|
42
|
+
RECONCILE = "reconcile"
|
|
43
|
+
DISPATCH_KNOWLEDGE = "dispatch_knowledge" # appended by WP-6.6
|
|
44
|
+
HARD_FORGET = "hard_forget"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ProcessingLane(StrEnum):
|
|
48
|
+
"""The two and only two lane values used by Plane-E work."""
|
|
49
|
+
|
|
50
|
+
STEADY = "steady"
|
|
51
|
+
BACKFILL = "backfill"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _require_utc(value: datetime) -> datetime:
|
|
55
|
+
"""Require an aware datetime whose UTC offset is exactly zero."""
|
|
56
|
+
if value.tzinfo is None or value.utcoffset() != timedelta(0):
|
|
57
|
+
raise ValueError("datetime must be timezone-aware UTC")
|
|
58
|
+
return value
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
UTCDateTime: TypeAlias = Annotated[
|
|
62
|
+
datetime, Field(strict=True), AfterValidator(_require_utc)
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class QueueRoute(BaseModel):
|
|
67
|
+
"""Non-authoritative D67 physical-delivery route snapshot."""
|
|
68
|
+
|
|
69
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
70
|
+
|
|
71
|
+
deployment_id: UUID
|
|
72
|
+
stage: PipelineStage
|
|
73
|
+
lane: ProcessingLane | None
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Recipe registry values (D50): frozen query plans as data, not code.
|
|
2
|
+
|
|
3
|
+
A **recipe** is a named, versioned composition of the zero-LLM primitives
|
|
4
|
+
(retrieval §4) — `relation_hybrid_rrf`, `claims_as_of`, `entity_timeline`,
|
|
5
|
+
and the rest. It is a *registry row*, never code: the MCP tool list renders
|
|
6
|
+
from these rows, the eval harness measures recall@k per recipe version, and
|
|
7
|
+
adding a query pattern is inserting a row. The load-bearing property is that
|
|
8
|
+
a recipe adds **no capability** — anything it does, an agent can compose from
|
|
9
|
+
§3 — so a recipe is exactly its `chain`, and the eval harness proves it by
|
|
10
|
+
replaying the chain and diffing.
|
|
11
|
+
|
|
12
|
+
Two declared enums make the D41 grain bar ("claims never answer *is it true
|
|
13
|
+
now*") a mechanical constraint rather than a prose judgment: `output_grain`
|
|
14
|
+
(the D49 envelope grain the recipe returns) and `answer_intent` (what kind of
|
|
15
|
+
question it answers). The database CHECK enforces the headline rule
|
|
16
|
+
(`current_facts` ⇒ `fact` grain); the registration linter (`core`) validates
|
|
17
|
+
the chain itself against the same enums.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from enum import StrEnum
|
|
21
|
+
|
|
22
|
+
from pydantic import BaseModel
|
|
23
|
+
from pydantic import ConfigDict
|
|
24
|
+
from pydantic import Field
|
|
25
|
+
|
|
26
|
+
from rememberstack.model.envelope import Grain
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class RecipeAnswerIntent(StrEnum):
|
|
30
|
+
"""What kind of question a recipe answers (the D50 `answer_intent`).
|
|
31
|
+
|
|
32
|
+
The intent is what the grain linter reasons over: `current_facts` may
|
|
33
|
+
only ride validity-filtered fact primitives, `assertion_history` is the
|
|
34
|
+
evidence-grain "what did sources assert" read, `audit` is the decision
|
|
35
|
+
trail, `change_feed` is the delta, and `orientation` is a pre-paid
|
|
36
|
+
synthesis (K pages, briefs).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
CURRENT_FACTS = "current_facts"
|
|
40
|
+
ASSERTION_HISTORY = "assertion_history"
|
|
41
|
+
ORIENTATION = "orientation"
|
|
42
|
+
AUDIT = "audit"
|
|
43
|
+
CHANGE_FEED = "change_feed"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class RecipeStep(BaseModel):
|
|
47
|
+
"""One primitive invocation in a recipe chain (retrieval §3 op + settings).
|
|
48
|
+
|
|
49
|
+
`op` names a §3 primitive; `settings` are the FIXED arguments the recipe
|
|
50
|
+
freezes (channel sets, RRF constants, rerank weights); `bind` maps a
|
|
51
|
+
primitive keyword to the name of a recipe parameter the caller supplies;
|
|
52
|
+
and `inputs` names the prior steps (by index) whose outputs this op
|
|
53
|
+
consumes — how `fuse` references the two searches above it. A recipe with
|
|
54
|
+
one step is the common case (a recipe over a single primitive with frozen
|
|
55
|
+
settings); the chain generalizes to fusion pipelines.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
59
|
+
|
|
60
|
+
op: str
|
|
61
|
+
settings: dict[str, object] = Field(default_factory=dict)
|
|
62
|
+
bind: dict[str, str] = Field(default_factory=dict)
|
|
63
|
+
inputs: tuple[int, ...] = ()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Recipe(BaseModel):
|
|
67
|
+
"""One recipe registry row (D50): the frozen plan and its declared grain.
|
|
68
|
+
|
|
69
|
+
`parameters` is a JSON-Schema-shaped description of the arguments a
|
|
70
|
+
caller passes (rendered into the MCP tool signature). `chain` is the
|
|
71
|
+
ordered primitive composition — the recipe's entire behavior. The two
|
|
72
|
+
enums are the contract the linter and the DB CHECK enforce.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
76
|
+
|
|
77
|
+
name: str = Field(min_length=1)
|
|
78
|
+
description: str = Field(min_length=1)
|
|
79
|
+
parameters: dict[str, object] = Field(default_factory=dict)
|
|
80
|
+
chain: tuple[RecipeStep, ...] = Field(min_length=1)
|
|
81
|
+
output_grain: Grain
|
|
82
|
+
answer_intent: RecipeAnswerIntent
|
|
83
|
+
version: int = Field(default=1, ge=1)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""E3 normalization values: LLM candidates, resolution, and fact records (D2-D5, D17-D18, D43)."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
from pydantic import ConfigDict
|
|
8
|
+
from pydantic import Field
|
|
9
|
+
|
|
10
|
+
_NonEmpty = Annotated[str, Field(min_length=1)]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EntityRef(BaseModel):
|
|
14
|
+
"""One entity as the normalizer emitted it: canonical form + registry type."""
|
|
15
|
+
|
|
16
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
17
|
+
|
|
18
|
+
name: _NonEmpty
|
|
19
|
+
type: _NonEmpty
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class RelationCandidate(BaseModel):
|
|
23
|
+
"""One (subject, predicate, object) proposal from the normalizer call."""
|
|
24
|
+
|
|
25
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
26
|
+
|
|
27
|
+
subject: EntityRef
|
|
28
|
+
predicate: _NonEmpty
|
|
29
|
+
object: EntityRef
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ObservationCandidate(BaseModel):
|
|
33
|
+
"""One entity-anchored value/statement proposal (D43), incl. stances (D59)."""
|
|
34
|
+
|
|
35
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
36
|
+
|
|
37
|
+
subject: EntityRef
|
|
38
|
+
statement: _NonEmpty
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ObservationAssertion(BaseModel):
|
|
42
|
+
"""One resolved observation input in a document/entity adjudication batch."""
|
|
43
|
+
|
|
44
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
45
|
+
|
|
46
|
+
statement: _NonEmpty
|
|
47
|
+
claim_id: UUID
|
|
48
|
+
doc_id: UUID
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class NormalizationResponse(BaseModel):
|
|
52
|
+
"""The normalizer call's structured output for one claim (0..n of each)."""
|
|
53
|
+
|
|
54
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
55
|
+
|
|
56
|
+
relations: tuple[RelationCandidate, ...] = ()
|
|
57
|
+
observations: tuple[ObservationCandidate, ...] = ()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ClaimForNormalization(BaseModel):
|
|
61
|
+
"""One accepted claim as the normalize stage loads it."""
|
|
62
|
+
|
|
63
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
64
|
+
|
|
65
|
+
claim_id: UUID
|
|
66
|
+
doc_id: UUID
|
|
67
|
+
chunk_id: UUID
|
|
68
|
+
claim_text: str
|
|
69
|
+
is_attributed: bool
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ResolvedEntity(BaseModel):
|
|
73
|
+
"""A T0 resolution outcome: the canonical id and whether it was minted."""
|
|
74
|
+
|
|
75
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
76
|
+
|
|
77
|
+
entity_id: UUID
|
|
78
|
+
created: bool
|
|
79
|
+
entity_type: _NonEmpty
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""ER cascade values (D17): candidates, bands, verdicts, and the T4 response.
|
|
2
|
+
|
|
3
|
+
Block-loose / decide-tight: T1/T2 generate candidates and never decide; T0,
|
|
4
|
+
T3, and T4 decide. Thresholds are per-type, golden-set-measured starting
|
|
5
|
+
points versioned in `resolver_versions` — never committed constants.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Annotated
|
|
9
|
+
from uuid import UUID
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
from pydantic import ConfigDict
|
|
13
|
+
from pydantic import Field
|
|
14
|
+
|
|
15
|
+
_NonEmpty = Annotated[str, Field(min_length=1)]
|
|
16
|
+
_Unit = Annotated[float, Field(ge=-1.0, le=1.0)]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ResolutionCandidate(BaseModel):
|
|
20
|
+
"""One blocked candidate: which tier surfaced it and its scores."""
|
|
21
|
+
|
|
22
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
23
|
+
|
|
24
|
+
entity_id: UUID
|
|
25
|
+
canonical_name: _NonEmpty
|
|
26
|
+
type: _NonEmpty
|
|
27
|
+
blocking_tier: _NonEmpty # T0 | T1 | T2
|
|
28
|
+
trigram_score: float | None = None
|
|
29
|
+
embedding_score: _Unit | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TypeThresholds(BaseModel):
|
|
33
|
+
"""One entity type's decision bands (starting points to measure, D22).
|
|
34
|
+
|
|
35
|
+
T3 cosine >= accept: match. <= reject: not this candidate. Between the
|
|
36
|
+
bands: escalate to T4 — cheap tiers never auto-reject near-misses (the
|
|
37
|
+
blocking ceiling is a recall ceiling, not a verdict).
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
41
|
+
|
|
42
|
+
t3_accept: _Unit = 0.88
|
|
43
|
+
t3_reject: _Unit = 0.60
|
|
44
|
+
t4_small_confidence_floor: Annotated[float, Field(ge=0.0, le=1.0)] = 0.75
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ResolverConfig(BaseModel):
|
|
48
|
+
"""The versioned cascade configuration (`resolver_versions` row shape)."""
|
|
49
|
+
|
|
50
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
51
|
+
|
|
52
|
+
resolver_version: _NonEmpty
|
|
53
|
+
trigram_floor: Annotated[float, Field(ge=0.0, le=1.0)] = 0.3
|
|
54
|
+
blocking_limit: Annotated[int, Field(ge=1)] = 10
|
|
55
|
+
t4_max_candidates: Annotated[int, Field(ge=1)] = 3
|
|
56
|
+
default_thresholds: TypeThresholds = TypeThresholds()
|
|
57
|
+
thresholds_by_type: dict[str, TypeThresholds] = {}
|
|
58
|
+
|
|
59
|
+
def thresholds_for(self, *, entity_type: str) -> TypeThresholds:
|
|
60
|
+
"""The type's bands, falling back to the defaults."""
|
|
61
|
+
return self.thresholds_by_type.get(entity_type, self.default_thresholds)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class AdjudicationVerdict(BaseModel):
|
|
65
|
+
"""The T4 call's structured output: same entity or not, with confidence."""
|
|
66
|
+
|
|
67
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
68
|
+
|
|
69
|
+
match: bool
|
|
70
|
+
confidence: Annotated[float, Field(ge=0.0, le=1.0)]
|
|
71
|
+
rationale: str | None = None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class P1EntityRow(BaseModel):
|
|
75
|
+
"""One row of the P1 entities table: the T3 profile embedding home (D8)."""
|
|
76
|
+
|
|
77
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
78
|
+
|
|
79
|
+
entity_id: UUID
|
|
80
|
+
deployment_id: UUID
|
|
81
|
+
type: _NonEmpty
|
|
82
|
+
canonical_name: _NonEmpty
|
|
83
|
+
vector: Annotated[tuple[float, ...], Field(min_length=1)]
|