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,276 @@
|
|
|
1
|
+
"""The recipe registry (D50): frozen query plans as rows the surfaces render.
|
|
2
|
+
|
|
3
|
+
`RecipeRegistry` is the write and read side of `retrieval_recipes`. Every
|
|
4
|
+
registration passes the `core` linter first, so a row that would let a recipe
|
|
5
|
+
misreport its grain never lands — the linter is the chain-level half of the
|
|
6
|
+
D41 bar, the DB CHECK the enum half. Reads return only `status='active'`
|
|
7
|
+
rows: those are what the MCP tool list, the CLI, and the API render from.
|
|
8
|
+
|
|
9
|
+
Adding a query pattern is inserting a row here — never new code — which is
|
|
10
|
+
exactly why a recipe can add no capability: the executor (surfaces) replays
|
|
11
|
+
whatever chain the row carries, and nothing else.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
from uuid import UUID
|
|
16
|
+
from uuid import uuid4
|
|
17
|
+
|
|
18
|
+
from sqlalchemy import bindparam
|
|
19
|
+
from sqlalchemy import JSON
|
|
20
|
+
from sqlalchemy import RowMapping
|
|
21
|
+
from sqlalchemy import text
|
|
22
|
+
from sqlalchemy.engine import Engine
|
|
23
|
+
|
|
24
|
+
from rememberstack.core import lint_recipe
|
|
25
|
+
from rememberstack.model import Grain
|
|
26
|
+
from rememberstack.model import Recipe
|
|
27
|
+
from rememberstack.model import RecipeAnswerIntent
|
|
28
|
+
from rememberstack.model import RecipeStep
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class RecipeRegistry:
|
|
32
|
+
"""Register and read the deployment's retrieval recipes (D50)."""
|
|
33
|
+
|
|
34
|
+
def __init__(self, *, engine: Engine) -> None:
|
|
35
|
+
"""Bind the registry to the deployment's spine."""
|
|
36
|
+
self._engine = engine
|
|
37
|
+
|
|
38
|
+
def register(self, *, deployment_id: UUID, recipe: Recipe) -> None:
|
|
39
|
+
"""Lint, then insert one recipe version (idempotent per name+version).
|
|
40
|
+
|
|
41
|
+
The linter runs BEFORE the write (`RecipeLintError` on a bad chain),
|
|
42
|
+
so an invalid recipe never becomes a row. Re-registering the same
|
|
43
|
+
`(name, version)` is a no-op, which makes seeding safe to repeat.
|
|
44
|
+
"""
|
|
45
|
+
lint_recipe(recipe)
|
|
46
|
+
with self._engine.begin() as connection:
|
|
47
|
+
connection.execute(
|
|
48
|
+
_INSERT_RECIPE,
|
|
49
|
+
{
|
|
50
|
+
"recipe_id": uuid4(),
|
|
51
|
+
"deployment_id": deployment_id,
|
|
52
|
+
"name": recipe.name,
|
|
53
|
+
"description": recipe.description,
|
|
54
|
+
"parameters": recipe.parameters,
|
|
55
|
+
"chain": [step.model_dump(mode="json") for step in recipe.chain],
|
|
56
|
+
"output_grain": recipe.output_grain.value,
|
|
57
|
+
"answer_intent": recipe.answer_intent.value,
|
|
58
|
+
"version": recipe.version,
|
|
59
|
+
},
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def active(self, *, deployment_id: UUID) -> tuple[Recipe, ...]:
|
|
63
|
+
"""Every active recipe, name-ordered — the surface's tool list."""
|
|
64
|
+
with self._engine.connect() as connection:
|
|
65
|
+
rows = (
|
|
66
|
+
connection.execute(_ACTIVE_RECIPES, {"deployment_id": deployment_id})
|
|
67
|
+
.mappings()
|
|
68
|
+
.all()
|
|
69
|
+
)
|
|
70
|
+
return tuple(_recipe_from_row(row) for row in rows)
|
|
71
|
+
|
|
72
|
+
def by_name(self, *, deployment_id: UUID, name: str) -> Recipe | None:
|
|
73
|
+
"""The latest active version of one recipe, or None if none exists."""
|
|
74
|
+
with self._engine.connect() as connection:
|
|
75
|
+
row = (
|
|
76
|
+
connection.execute(
|
|
77
|
+
_RECIPE_BY_NAME, {"deployment_id": deployment_id, "name": name}
|
|
78
|
+
)
|
|
79
|
+
.mappings()
|
|
80
|
+
.one_or_none()
|
|
81
|
+
)
|
|
82
|
+
return None if row is None else _recipe_from_row(row)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _recipe_from_row(row: RowMapping) -> Recipe:
|
|
86
|
+
"""Rebuild a Recipe (typed chain and all) from one registry row."""
|
|
87
|
+
raw_chain = row["chain"]
|
|
88
|
+
chain_items = (
|
|
89
|
+
raw_chain if isinstance(raw_chain, list) else json.loads(str(raw_chain))
|
|
90
|
+
)
|
|
91
|
+
raw_parameters = row["parameters"]
|
|
92
|
+
parameters = (
|
|
93
|
+
raw_parameters
|
|
94
|
+
if isinstance(raw_parameters, dict)
|
|
95
|
+
else json.loads(str(raw_parameters))
|
|
96
|
+
)
|
|
97
|
+
return Recipe(
|
|
98
|
+
name=str(row["name"]),
|
|
99
|
+
description=str(row["description"]),
|
|
100
|
+
parameters=parameters,
|
|
101
|
+
chain=tuple(RecipeStep.model_validate(item) for item in chain_items),
|
|
102
|
+
output_grain=Grain(row["output_grain"]),
|
|
103
|
+
answer_intent=RecipeAnswerIntent(row["answer_intent"]),
|
|
104
|
+
version=int(str(row["version"])),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
_INSERT_RECIPE = text(
|
|
109
|
+
"""
|
|
110
|
+
INSERT INTO retrieval_recipes (recipe_id, deployment_id, name, description,
|
|
111
|
+
parameters, chain, output_grain, answer_intent, version)
|
|
112
|
+
VALUES (:recipe_id, :deployment_id, :name, :description, :parameters,
|
|
113
|
+
:chain, CAST(:output_grain AS recipe_output_grain),
|
|
114
|
+
CAST(:answer_intent AS recipe_answer_intent), :version)
|
|
115
|
+
ON CONFLICT (deployment_id, name, version) DO NOTHING
|
|
116
|
+
"""
|
|
117
|
+
).bindparams(bindparam("parameters", type_=JSON), bindparam("chain", type_=JSON))
|
|
118
|
+
|
|
119
|
+
_RECIPE_COLUMNS = (
|
|
120
|
+
"name, description, parameters, chain, output_grain::text AS output_grain,"
|
|
121
|
+
" answer_intent::text AS answer_intent, version"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
_ACTIVE_RECIPES = text(
|
|
125
|
+
f"""
|
|
126
|
+
SELECT {_RECIPE_COLUMNS}
|
|
127
|
+
FROM retrieval_recipes
|
|
128
|
+
WHERE deployment_id = :deployment_id AND status = 'active'
|
|
129
|
+
ORDER BY name, version DESC
|
|
130
|
+
""" # noqa: S608 — _RECIPE_COLUMNS is a module constant, not user input
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
_RECIPE_BY_NAME = text(
|
|
134
|
+
f"""
|
|
135
|
+
SELECT {_RECIPE_COLUMNS}
|
|
136
|
+
FROM retrieval_recipes
|
|
137
|
+
WHERE deployment_id = :deployment_id AND name = :name AND status = 'active'
|
|
138
|
+
ORDER BY version DESC
|
|
139
|
+
LIMIT 1
|
|
140
|
+
""" # noqa: S608 — _RECIPE_COLUMNS is a module constant, not user input
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
145
|
+
# The canonical recipe set (retrieval §4), each a frozen composition of the
|
|
146
|
+
# zero-LLM primitives. These are seeded into every deployment; the surfaces
|
|
147
|
+
# render their tool list from the rows, and the eval harness proves each is
|
|
148
|
+
# exactly its chain. Adding a query pattern is adding an entry here.
|
|
149
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
150
|
+
CANONICAL_RECIPES: tuple[Recipe, ...] = (
|
|
151
|
+
Recipe(
|
|
152
|
+
name="relation_current",
|
|
153
|
+
description="Current relations matching a subject and optional predicate"
|
|
154
|
+
" — 'who does X work for now?' (S1). Validity-filtered, fact grain.",
|
|
155
|
+
parameters={
|
|
156
|
+
"subject_entity_id": {"type": "uuid", "required": True},
|
|
157
|
+
"predicate": {"type": "string", "required": False},
|
|
158
|
+
},
|
|
159
|
+
chain=(
|
|
160
|
+
RecipeStep(
|
|
161
|
+
op="lookup_relations",
|
|
162
|
+
bind={
|
|
163
|
+
"subject_entity_id": "subject_entity_id",
|
|
164
|
+
"predicate": "predicate",
|
|
165
|
+
},
|
|
166
|
+
),
|
|
167
|
+
),
|
|
168
|
+
output_grain=Grain.FACT,
|
|
169
|
+
answer_intent=RecipeAnswerIntent.CURRENT_FACTS,
|
|
170
|
+
),
|
|
171
|
+
Recipe(
|
|
172
|
+
name="observation_current",
|
|
173
|
+
description="Current observations on an entity — 'what do we know about"
|
|
174
|
+
" X now?' (S2). Validity-filtered, fact grain.",
|
|
175
|
+
parameters={"entity_id": {"type": "uuid", "required": True}},
|
|
176
|
+
chain=(RecipeStep(op="lookup_observations", bind={"entity_id": "entity_id"}),),
|
|
177
|
+
output_grain=Grain.FACT,
|
|
178
|
+
answer_intent=RecipeAnswerIntent.CURRENT_FACTS,
|
|
179
|
+
),
|
|
180
|
+
Recipe(
|
|
181
|
+
name="entity_timeline",
|
|
182
|
+
description="An entity's facts by year — its evolution over time (S30)."
|
|
183
|
+
" A bounded fact aggregate, an orientation over history.",
|
|
184
|
+
parameters={"entity_id": {"type": "uuid", "required": True}},
|
|
185
|
+
chain=(
|
|
186
|
+
RecipeStep(
|
|
187
|
+
op="aggregate",
|
|
188
|
+
settings={"form": "timeline"},
|
|
189
|
+
bind={"subject_entity_id": "entity_id"},
|
|
190
|
+
),
|
|
191
|
+
),
|
|
192
|
+
output_grain=Grain.FACT,
|
|
193
|
+
answer_intent=RecipeAnswerIntent.ORIENTATION,
|
|
194
|
+
),
|
|
195
|
+
Recipe(
|
|
196
|
+
name="claims_verbatim",
|
|
197
|
+
description="What sources actually asserted, verbatim, for a query"
|
|
198
|
+
" (S6). Evidence grain — never a current-fact answer (the D41 bar).",
|
|
199
|
+
parameters={
|
|
200
|
+
"query": {"type": "string", "required": True},
|
|
201
|
+
"k": {"type": "integer", "required": False, "default": 10},
|
|
202
|
+
},
|
|
203
|
+
chain=(RecipeStep(op="search_claims", bind={"query": "query", "k": "k"}),),
|
|
204
|
+
output_grain=Grain.EVIDENCE,
|
|
205
|
+
answer_intent=RecipeAnswerIntent.ASSERTION_HISTORY,
|
|
206
|
+
),
|
|
207
|
+
Recipe(
|
|
208
|
+
name="claims_hybrid_rrf",
|
|
209
|
+
description="Verbatim claims for a query, fused across parallel channel"
|
|
210
|
+
" orderings by reciprocal-rank fusion (S46). Evidence grain.",
|
|
211
|
+
parameters={
|
|
212
|
+
"query": {"type": "string", "required": True},
|
|
213
|
+
"k": {"type": "integer", "required": False, "default": 10},
|
|
214
|
+
},
|
|
215
|
+
chain=(
|
|
216
|
+
RecipeStep(op="search_claims", bind={"query": "query", "k": "k"}),
|
|
217
|
+
RecipeStep(op="search_claims", bind={"query": "query", "k": "k"}),
|
|
218
|
+
RecipeStep(op="fuse", settings={"k": 60}, inputs=(0, 1)),
|
|
219
|
+
),
|
|
220
|
+
output_grain=Grain.EVIDENCE,
|
|
221
|
+
answer_intent=RecipeAnswerIntent.ASSERTION_HISTORY,
|
|
222
|
+
),
|
|
223
|
+
Recipe(
|
|
224
|
+
name="explain",
|
|
225
|
+
description="Why do we believe a relation — the fact with its evidence"
|
|
226
|
+
" and source handles (S5). Composite grain, the audit deepening hop.",
|
|
227
|
+
parameters={"relation_id": {"type": "uuid", "required": True}},
|
|
228
|
+
chain=(RecipeStep(op="hydrate_relation", bind={"relation_id": "relation_id"}),),
|
|
229
|
+
output_grain=Grain.COMPOSITE,
|
|
230
|
+
answer_intent=RecipeAnswerIntent.AUDIT,
|
|
231
|
+
),
|
|
232
|
+
Recipe(
|
|
233
|
+
name="identity_as_of",
|
|
234
|
+
description="An entity's identity history — how its mentions resolved"
|
|
235
|
+
" and every merge it took part in (S61). Composite grain, audit.",
|
|
236
|
+
parameters={"entity_id": {"type": "uuid", "required": True}},
|
|
237
|
+
chain=(
|
|
238
|
+
RecipeStep(
|
|
239
|
+
op="transcript",
|
|
240
|
+
settings={"subject_kind": "entity"},
|
|
241
|
+
bind={"subject_id": "entity_id"},
|
|
242
|
+
),
|
|
243
|
+
),
|
|
244
|
+
output_grain=Grain.COMPOSITE,
|
|
245
|
+
answer_intent=RecipeAnswerIntent.AUDIT,
|
|
246
|
+
),
|
|
247
|
+
Recipe(
|
|
248
|
+
name="changed_since",
|
|
249
|
+
description="What changed since an instant — the delta feed (S13/S14)."
|
|
250
|
+
" Composite grain, the change-feed intent.",
|
|
251
|
+
parameters={"since": {"type": "timestamp", "required": True}},
|
|
252
|
+
chain=(RecipeStep(op="delta", bind={"since": "since"}),),
|
|
253
|
+
output_grain=Grain.COMPOSITE,
|
|
254
|
+
answer_intent=RecipeAnswerIntent.CHANGE_FEED,
|
|
255
|
+
),
|
|
256
|
+
Recipe(
|
|
257
|
+
name="pages_about",
|
|
258
|
+
description="Which compiled K pages exist about an entity (S31/S45) —"
|
|
259
|
+
" the routing index read backwards. Compiled grain, orientation.",
|
|
260
|
+
parameters={"entity_id": {"type": "uuid", "required": True}},
|
|
261
|
+
chain=(RecipeStep(op="pages_about", bind={"entity_id": "entity_id"}),),
|
|
262
|
+
output_grain=Grain.COMPILED,
|
|
263
|
+
answer_intent=RecipeAnswerIntent.ORIENTATION,
|
|
264
|
+
),
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def seed_canonical_recipes(*, registry: RecipeRegistry, deployment_id: UUID) -> int:
|
|
269
|
+
"""Register the canonical recipe set into a deployment (idempotent).
|
|
270
|
+
|
|
271
|
+
Each recipe is linted then inserted; re-seeding is a no-op per version.
|
|
272
|
+
Returns how many recipes were seeded (the full canonical count).
|
|
273
|
+
"""
|
|
274
|
+
for recipe in CANONICAL_RECIPES:
|
|
275
|
+
registry.register(deployment_id=deployment_id, recipe=recipe)
|
|
276
|
+
return len(CANONICAL_RECIPES)
|