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,62 @@
|
|
|
1
|
+
"""Typed results for the WP-5.6 retrieval spike battery."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
from typing import get_args
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from pydantic import ConfigDict
|
|
9
|
+
from pydantic import Field
|
|
10
|
+
from pydantic import model_validator
|
|
11
|
+
|
|
12
|
+
RetrievalSpikeName = Literal[
|
|
13
|
+
"lance_filtered_search",
|
|
14
|
+
"hub_pagination",
|
|
15
|
+
"rerank_weights",
|
|
16
|
+
"envelope_overhead",
|
|
17
|
+
"hydration_batching",
|
|
18
|
+
"resolve_context",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
RETRIEVAL_SPIKE_NAMES = frozenset(get_args(RetrievalSpikeName))
|
|
22
|
+
"""The six WP-5.6 measurements; S58 and as-of graph cost closed earlier."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RetrievalSpikeMeasurement(BaseModel):
|
|
26
|
+
"""One measured question, its selected setting, and honest limitations."""
|
|
27
|
+
|
|
28
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
29
|
+
|
|
30
|
+
name: RetrievalSpikeName
|
|
31
|
+
scale: Annotated[int, Field(ge=1)]
|
|
32
|
+
metrics: dict[str, object]
|
|
33
|
+
selected: dict[str, object]
|
|
34
|
+
limitations: tuple[str, ...] = ()
|
|
35
|
+
passed: bool
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class RetrievalSpikeReport(BaseModel):
|
|
39
|
+
"""The complete six-spike WP-5.6 result written to ``eval_runs``."""
|
|
40
|
+
|
|
41
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
42
|
+
|
|
43
|
+
measurements: Annotated[
|
|
44
|
+
tuple[RetrievalSpikeMeasurement, ...], Field(min_length=6, max_length=6)
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
@model_validator(mode="after")
|
|
48
|
+
def complete_battery(self) -> "RetrievalSpikeReport":
|
|
49
|
+
"""Reject duplicate or missing measurements; absence is not compliance."""
|
|
50
|
+
names = {measurement.name for measurement in self.measurements}
|
|
51
|
+
if names != RETRIEVAL_SPIKE_NAMES:
|
|
52
|
+
missing = sorted(RETRIEVAL_SPIKE_NAMES - names)
|
|
53
|
+
extra = sorted(names - RETRIEVAL_SPIKE_NAMES)
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"retrieval spike names mismatch: missing={missing}, extra={extra}"
|
|
56
|
+
)
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def passed(self) -> bool:
|
|
61
|
+
"""The battery passes only when every measured invariant holds."""
|
|
62
|
+
return all(measurement.passed for measurement in self.measurements)
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""Section-structure values (D39/D57): the LLM's proposal and the snapped truth.
|
|
2
|
+
|
|
3
|
+
Two deliberately different trust levels share this module. `ProposedSection` /
|
|
4
|
+
`StructureResponse` are the structurer LLM's raw output — free-hand character
|
|
5
|
+
spans that may overlap, gap, nest wrongly, or point outside the document; they
|
|
6
|
+
are never persisted. `SnappedSection` is what the deterministic snap
|
|
7
|
+
(`core/section_snap.py`) makes of them: a well-formed partition on the block
|
|
8
|
+
grid, the only form that reaches `document_sections`.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from uuid import UUID
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel
|
|
16
|
+
from pydantic import ConfigDict
|
|
17
|
+
from pydantic import Field
|
|
18
|
+
from pydantic import model_validator
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ProposedSection(BaseModel):
|
|
22
|
+
"""One LLM-proposed section span (pre-snap): untrusted free-hand geometry."""
|
|
23
|
+
|
|
24
|
+
model_config = ConfigDict(frozen=True, extra="ignore")
|
|
25
|
+
|
|
26
|
+
title: str = ""
|
|
27
|
+
role: str = "body"
|
|
28
|
+
char_start: int = 0
|
|
29
|
+
char_end: int = 0
|
|
30
|
+
summary: str = ""
|
|
31
|
+
children: tuple[ProposedSection, ...] = ()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class StructureResponse(BaseModel):
|
|
35
|
+
"""The structurer's structured output: a proposed tree + placement hint."""
|
|
36
|
+
|
|
37
|
+
model_config = ConfigDict(frozen=True, extra="ignore")
|
|
38
|
+
|
|
39
|
+
sections: tuple[ProposedSection, ...] = ()
|
|
40
|
+
placement: str = ""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class SnappedSection(BaseModel):
|
|
44
|
+
"""One well-formed section after the deterministic snap (block coordinates).
|
|
45
|
+
|
|
46
|
+
``block_end`` is inclusive; the empty document's root carries the empty
|
|
47
|
+
range ``0..-1`` on the block grid (D57) with a zero-width char span.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
51
|
+
|
|
52
|
+
node_path: str # materialized path, e.g. '0.2.1'; the root is '0'
|
|
53
|
+
parent_path: str | None
|
|
54
|
+
title: str
|
|
55
|
+
role: str
|
|
56
|
+
block_start: int = Field(ge=0)
|
|
57
|
+
block_end: int = Field(ge=-1)
|
|
58
|
+
char_start: int = Field(ge=0)
|
|
59
|
+
char_end: int = Field(ge=0)
|
|
60
|
+
summary: str
|
|
61
|
+
ordinal: int = Field(ge=0)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class SectionTreeRecord(BaseModel):
|
|
65
|
+
"""The complete write input for one representation's section tree.
|
|
66
|
+
|
|
67
|
+
``sections`` is in depth-first document order with the root first — the
|
|
68
|
+
catalog resolves each row's parent id from the paths as it inserts, so
|
|
69
|
+
the record refuses any ordering or path structure that would silently
|
|
70
|
+
persist a disconnected tree (an orphan row would reach E1 as a second
|
|
71
|
+
root and double-chunk its range).
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
75
|
+
|
|
76
|
+
deployment_id: UUID
|
|
77
|
+
doc_id: UUID
|
|
78
|
+
version_id: UUID
|
|
79
|
+
representation_id: UUID
|
|
80
|
+
sections: tuple[SnappedSection, ...] = Field(min_length=1)
|
|
81
|
+
placement_path: str | None
|
|
82
|
+
structurer_name: str
|
|
83
|
+
structurer_version: str
|
|
84
|
+
|
|
85
|
+
@model_validator(mode="after")
|
|
86
|
+
def _tree_is_connected(self) -> SectionTreeRecord:
|
|
87
|
+
"""Root first; every node extends a parent that appeared before it."""
|
|
88
|
+
root = self.sections[0]
|
|
89
|
+
if root.node_path != "0" or root.parent_path is not None:
|
|
90
|
+
raise ValueError("the first section must be the root '0'")
|
|
91
|
+
seen = {root.node_path}
|
|
92
|
+
for section in self.sections[1:]:
|
|
93
|
+
if section.node_path in seen:
|
|
94
|
+
raise ValueError(f"duplicate section path {section.node_path!r}")
|
|
95
|
+
if section.parent_path not in seen:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
f"section {section.node_path!r} appears before its parent"
|
|
98
|
+
)
|
|
99
|
+
if section.node_path.rsplit(".", 1)[0] != section.parent_path:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f"section {section.node_path!r} does not extend its"
|
|
102
|
+
f" parent path {section.parent_path!r}"
|
|
103
|
+
)
|
|
104
|
+
seen.add(section.node_path)
|
|
105
|
+
return self
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class PersistedSectionTree(BaseModel):
|
|
109
|
+
"""What one representation's section-tree write actually landed.
|
|
110
|
+
|
|
111
|
+
On a retried attempt the FIRST write wins row by row, so the caller must
|
|
112
|
+
treat this — not its own input — as the truth (the sidecar is derived
|
|
113
|
+
from it, never from a fresher LLM proposal).
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
117
|
+
|
|
118
|
+
sections: tuple[SnappedSection, ...] = Field(min_length=1)
|
|
119
|
+
placement_path: str | None
|
|
120
|
+
structurer_version: str
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Structured telemetry values that remain independent of exporter SDKs."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
from pydantic import ConfigDict
|
|
7
|
+
from pydantic import Field
|
|
8
|
+
|
|
9
|
+
from rememberstack.model.queue import UTCDateTime
|
|
10
|
+
|
|
11
|
+
TelemetryScalar = str | int | float | bool | None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TelemetryAttribute(BaseModel):
|
|
15
|
+
"""One immutable structured attribute on a telemetry event."""
|
|
16
|
+
|
|
17
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
18
|
+
|
|
19
|
+
name: Annotated[str, Field(min_length=1)]
|
|
20
|
+
value: TelemetryScalar
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TelemetryEvent(BaseModel):
|
|
24
|
+
"""Provider-neutral structured event ready for export."""
|
|
25
|
+
|
|
26
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
27
|
+
|
|
28
|
+
name: Annotated[str, Field(min_length=1)]
|
|
29
|
+
occurred_at: UTCDateTime
|
|
30
|
+
attributes: tuple[TelemetryAttribute, ...]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Provider-neutral deployment substrate and store-capability protocols."""
|
|
2
|
+
|
|
3
|
+
from rememberstack.ports.auth import AuthPerimeterPort
|
|
4
|
+
from rememberstack.ports.forget import ForgetManifestPort
|
|
5
|
+
from rememberstack.ports.git import KGitRemotePort
|
|
6
|
+
from rememberstack.ports.model_provider import ModelProviderPort
|
|
7
|
+
from rememberstack.ports.mounts import MountPublisherPort
|
|
8
|
+
from rememberstack.ports.object_store import ObjectStorePort
|
|
9
|
+
from rememberstack.ports.purge import KGitPurgePort
|
|
10
|
+
from rememberstack.ports.purge import ObjectPurgePort
|
|
11
|
+
from rememberstack.ports.purge import P1PurgePort
|
|
12
|
+
from rememberstack.ports.purge import ProjectionPurgePort
|
|
13
|
+
from rememberstack.ports.queue import TaskQueuePort
|
|
14
|
+
from rememberstack.ports.telemetry import TelemetryPort
|
|
15
|
+
|
|
16
|
+
__all__ = (
|
|
17
|
+
"AuthPerimeterPort",
|
|
18
|
+
"ForgetManifestPort",
|
|
19
|
+
"KGitPurgePort",
|
|
20
|
+
"KGitRemotePort",
|
|
21
|
+
"ModelProviderPort",
|
|
22
|
+
"MountPublisherPort",
|
|
23
|
+
"ObjectStorePort",
|
|
24
|
+
"ObjectPurgePort",
|
|
25
|
+
"P1PurgePort",
|
|
26
|
+
"ProjectionPurgePort",
|
|
27
|
+
"TaskQueuePort",
|
|
28
|
+
"TelemetryPort",
|
|
29
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""D50/D60 auth-perimeter seam for a single-deployment trust domain."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
|
|
6
|
+
from rememberstack.model import AuthenticatedContext
|
|
7
|
+
from rememberstack.model import PerimeterCredential
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@runtime_checkable
|
|
11
|
+
class AuthPerimeterPort(Protocol):
|
|
12
|
+
"""Authenticate perimeter credentials without introducing internal tenancy."""
|
|
13
|
+
|
|
14
|
+
def authenticate(self, *, credential: PerimeterCredential) -> AuthenticatedContext:
|
|
15
|
+
"""Return the authenticated principal and its one deployment context."""
|
|
16
|
+
...
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""D61 seam for watched sources: poll observations, fetch bytes (lifecycle §2)."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
from typing import runtime_checkable
|
|
6
|
+
|
|
7
|
+
from rememberstack.model import SourceItem
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@runtime_checkable
|
|
11
|
+
class WatchedSourcePort(Protocol):
|
|
12
|
+
"""One watched source: enumerate current items and detect deletions."""
|
|
13
|
+
|
|
14
|
+
def poll(self, *, known: Mapping[str, str]) -> tuple[SourceItem, ...]:
|
|
15
|
+
"""Report every current item plus a deleted-marked item for each
|
|
16
|
+
known source_ref no longer present. `known` maps source_ref → the
|
|
17
|
+
last ingested revision, so unchanged items can skip fetch entirely.
|
|
18
|
+
"""
|
|
19
|
+
...
|
|
20
|
+
|
|
21
|
+
def fetch(self, *, source_ref: str) -> bytes:
|
|
22
|
+
"""The item's current bytes (called only for changed items)."""
|
|
23
|
+
...
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Provider-neutral sink for attributing one worker attempt's model calls."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
|
|
6
|
+
from rememberstack.model import ProviderCallUsage
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@runtime_checkable
|
|
10
|
+
class CostMeterPort(Protocol):
|
|
11
|
+
"""Record provider usage under a deterministic call key and cascade tier."""
|
|
12
|
+
|
|
13
|
+
def record(
|
|
14
|
+
self, *, call_key: str, tier: str | None, usage: ProviderCallUsage
|
|
15
|
+
) -> None:
|
|
16
|
+
"""Persist one successful provider call for the bound processing attempt."""
|
|
17
|
+
...
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""D74 durable intent boundary for portable hard-forget manifests."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from rememberstack.model import ForgetManifest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@runtime_checkable
|
|
11
|
+
class ForgetManifestPort(Protocol):
|
|
12
|
+
"""Append and enumerate immutable intent outside the protected restore set."""
|
|
13
|
+
|
|
14
|
+
def append(self, *, manifest: ForgetManifest) -> None:
|
|
15
|
+
"""Durably append one manifest; identical bytes are idempotent."""
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
def manifests(self, *, deployment_id: UUID) -> tuple[ForgetManifest, ...]:
|
|
19
|
+
"""Return every manifest for a deployment in deterministic order."""
|
|
20
|
+
...
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""D45/D61 remote interaction used by the single-writer Plane-K driver."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
from typing import runtime_checkable
|
|
6
|
+
|
|
7
|
+
from rememberstack.model import KRevision
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@runtime_checkable
|
|
11
|
+
class KGitRemotePort(Protocol):
|
|
12
|
+
"""Checkout and publish driver-owned Plane-K commits through one remote."""
|
|
13
|
+
|
|
14
|
+
def checkout(self, *, destination: Path) -> KRevision:
|
|
15
|
+
"""Create the driver's working checkout and return its current revision."""
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
def publish(self, *, worktree: Path) -> KRevision:
|
|
19
|
+
"""Publish the commit prepared by the K driver and return its revision."""
|
|
20
|
+
...
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""D52/D61 substrate seam for typed model and embedding provider calls."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
from typing import TypeVar
|
|
6
|
+
|
|
7
|
+
from rememberstack.model import EmbeddingRequest
|
|
8
|
+
from rememberstack.model import EmbeddingResponse
|
|
9
|
+
from rememberstack.model import GeneratedResponse
|
|
10
|
+
from rememberstack.model import ModelRequest
|
|
11
|
+
from rememberstack.model import StructuredResponseModel
|
|
12
|
+
|
|
13
|
+
ResponseT = TypeVar("ResponseT", bound=StructuredResponseModel)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class ModelProviderPort(Protocol):
|
|
18
|
+
"""Invoke configured models without owning prompts, cascades, or domain logic."""
|
|
19
|
+
|
|
20
|
+
def generate(
|
|
21
|
+
self, *, request: ModelRequest, response_type: type[ResponseT]
|
|
22
|
+
) -> GeneratedResponse[ResponseT]:
|
|
23
|
+
"""Return validated output plus the provider-reported usage for this call."""
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
def embed(self, *, request: EmbeddingRequest) -> EmbeddingResponse:
|
|
27
|
+
"""Return same-dimension embeddings for one caller-declared batch."""
|
|
28
|
+
...
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""D51/D61 portable publication boundary for four read-only mount views."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from rememberstack.model import PublishedMounts
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@runtime_checkable
|
|
11
|
+
class MountPublisherPort(Protocol):
|
|
12
|
+
"""Publish P3, artifact, raw, and Plane-K views without mount mechanics."""
|
|
13
|
+
|
|
14
|
+
def publish(self, *, deployment_id: UUID) -> PublishedMounts:
|
|
15
|
+
"""Publish and return the exact four read-only deployment views."""
|
|
16
|
+
...
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""D61 byte/object-key seam for immutable raw inputs, artifacts, and snapshots."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
|
|
6
|
+
from rememberstack.model import ObjectKey
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@runtime_checkable
|
|
10
|
+
class ObjectStorePort(Protocol):
|
|
11
|
+
"""Read and create immutable objects without exposing storage-provider types."""
|
|
12
|
+
|
|
13
|
+
def read_bytes(self, *, key: ObjectKey) -> bytes:
|
|
14
|
+
"""Read all bytes stored under an existing object key."""
|
|
15
|
+
...
|
|
16
|
+
|
|
17
|
+
def write_bytes(
|
|
18
|
+
self, *, key: ObjectKey, content: bytes, storage_class: str | None = None
|
|
19
|
+
) -> None:
|
|
20
|
+
"""Create immutable bytes, failing rather than replacing an occupied key.
|
|
21
|
+
|
|
22
|
+
`storage_class` is the D51 mime routing decision made by the caller
|
|
23
|
+
(hot for media a harness reads, cold for originals kept only for
|
|
24
|
+
audit). Providers that have storage classes apply it; providers
|
|
25
|
+
that do not record it, so the routing is observable either way.
|
|
26
|
+
"""
|
|
27
|
+
...
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""D61 seam for the P1 search indexes: chunks, claims, facts (D8)."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
|
|
6
|
+
from rememberstack.model import P1ChunkRow
|
|
7
|
+
from rememberstack.model import P1ClaimRow
|
|
8
|
+
from rememberstack.model import P1EntityRow
|
|
9
|
+
from rememberstack.model import P1FactRow
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@runtime_checkable
|
|
13
|
+
class ChunkIndexPort(Protocol):
|
|
14
|
+
"""Write the P1 chunk table without exposing vector-store types."""
|
|
15
|
+
|
|
16
|
+
def upsert_chunks(self, *, rows: tuple[P1ChunkRow, ...]) -> None:
|
|
17
|
+
"""Insert or replace rows by chunk_id; re-runs are idempotent."""
|
|
18
|
+
...
|
|
19
|
+
|
|
20
|
+
def chunk_vectors(
|
|
21
|
+
self, *, deployment_id: str, chunk_ids: tuple[str, ...]
|
|
22
|
+
) -> dict[str, tuple[float, ...]]:
|
|
23
|
+
"""Stored vectors for the requested ids (absent ids are omitted).
|
|
24
|
+
|
|
25
|
+
The D56 embedding-reuse read: an unchanged chunk in a new version
|
|
26
|
+
copies its predecessor's vector instead of re-embedding.
|
|
27
|
+
"""
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@runtime_checkable
|
|
32
|
+
class ClaimIndexPort(Protocol):
|
|
33
|
+
"""Write the P1 claims channel — the needle index (D58)."""
|
|
34
|
+
|
|
35
|
+
def upsert_claims(self, *, rows: tuple[P1ClaimRow, ...]) -> None:
|
|
36
|
+
"""Insert or replace rows by claim_id; re-runs are idempotent."""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@runtime_checkable
|
|
41
|
+
class FactIndexPort(Protocol):
|
|
42
|
+
"""Write the P1 facts channel — relation/observation labels (D8)."""
|
|
43
|
+
|
|
44
|
+
def upsert_facts(self, *, rows: tuple[P1FactRow, ...]) -> None:
|
|
45
|
+
"""Insert or replace rows by fact_id; re-runs are idempotent."""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@runtime_checkable
|
|
50
|
+
class P1SearchPort(Protocol):
|
|
51
|
+
"""Nominate candidates from the P1 indexes (D48: propose, never dispose)."""
|
|
52
|
+
|
|
53
|
+
def search_claims(
|
|
54
|
+
self,
|
|
55
|
+
*,
|
|
56
|
+
deployment_id: str,
|
|
57
|
+
vector: tuple[float, ...],
|
|
58
|
+
k: int,
|
|
59
|
+
current_only: bool,
|
|
60
|
+
) -> tuple[str, ...]:
|
|
61
|
+
"""Ranked claim-id nominations from the claims channel."""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
def search_facts(
|
|
65
|
+
self, *, deployment_id: str, vector: tuple[float, ...], k: int, kind: str | None
|
|
66
|
+
) -> tuple[str, ...]:
|
|
67
|
+
"""Ranked fact-id nominations from the facts channel."""
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@runtime_checkable
|
|
72
|
+
class EntityIndexPort(Protocol):
|
|
73
|
+
"""The T3 profile-embedding home: entity vectors in P1 (D8/D17)."""
|
|
74
|
+
|
|
75
|
+
def upsert_entities(self, *, rows: tuple[P1EntityRow, ...]) -> None:
|
|
76
|
+
"""Insert or replace entity profiles by entity_id; idempotent."""
|
|
77
|
+
...
|
|
78
|
+
|
|
79
|
+
def entity_vectors(
|
|
80
|
+
self, *, deployment_id: str, entity_ids: tuple[str, ...]
|
|
81
|
+
) -> dict[str, tuple[float, ...]]:
|
|
82
|
+
"""Profile vectors for the requested ids (absent ids are omitted)."""
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@runtime_checkable
|
|
87
|
+
class P1IndexMaintenancePort(Protocol):
|
|
88
|
+
"""Explicit post-bulk-load maintenance for the P1 search indexes."""
|
|
89
|
+
|
|
90
|
+
def build_search_indexes(self) -> None:
|
|
91
|
+
"""Build or refresh search indexes after a backfill has drained."""
|
|
92
|
+
...
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""D74 erasure capabilities of the already-selected serving stores."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from rememberstack.model import ObjectKey
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@runtime_checkable
|
|
11
|
+
class ObjectPurgePort(Protocol):
|
|
12
|
+
"""Idempotently erase manifest-nominated immutable objects."""
|
|
13
|
+
|
|
14
|
+
def purge_objects(
|
|
15
|
+
self, *, keys: tuple[ObjectKey, ...], prefixes: tuple[ObjectKey, ...]
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Delete exact keys and every object below exact prefixes; absence succeeds."""
|
|
18
|
+
...
|
|
19
|
+
|
|
20
|
+
def verify_objects_purged(
|
|
21
|
+
self, *, keys: tuple[ObjectKey, ...], prefixes: tuple[ObjectKey, ...]
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Raise unless every exact key and prefix is absent from the active store."""
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@runtime_checkable
|
|
28
|
+
class P1PurgePort(Protocol):
|
|
29
|
+
"""Idempotently erase manifest-nominated P1 rows by identity."""
|
|
30
|
+
|
|
31
|
+
def purge_rows(
|
|
32
|
+
self,
|
|
33
|
+
*,
|
|
34
|
+
deployment_id: UUID,
|
|
35
|
+
chunk_ids: tuple[UUID, ...],
|
|
36
|
+
claim_ids: tuple[UUID, ...],
|
|
37
|
+
fact_ids: tuple[UUID, ...],
|
|
38
|
+
entity_ids: tuple[UUID, ...],
|
|
39
|
+
) -> None:
|
|
40
|
+
"""Delete exact rows and compact affected P1 tables; absence succeeds."""
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
def verify_rows_purged(
|
|
44
|
+
self,
|
|
45
|
+
*,
|
|
46
|
+
deployment_id: UUID,
|
|
47
|
+
chunk_ids: tuple[UUID, ...],
|
|
48
|
+
claim_ids: tuple[UUID, ...],
|
|
49
|
+
fact_ids: tuple[UUID, ...],
|
|
50
|
+
entity_ids: tuple[UUID, ...],
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Raise unless every nominated row is absent from active P1 tables."""
|
|
53
|
+
...
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@runtime_checkable
|
|
57
|
+
class ProjectionPurgePort(Protocol):
|
|
58
|
+
"""Erase old P2/P3 durable prefixes and local serving copies."""
|
|
59
|
+
|
|
60
|
+
def purge_projections(
|
|
61
|
+
self, *, deployment_id: UUID, prefixes: tuple[ObjectKey, ...]
|
|
62
|
+
) -> None:
|
|
63
|
+
"""Delete every nominated projection copy; absence succeeds."""
|
|
64
|
+
...
|
|
65
|
+
|
|
66
|
+
def verify_projections_purged(
|
|
67
|
+
self, *, deployment_id: UUID, prefixes: tuple[ObjectKey, ...]
|
|
68
|
+
) -> None:
|
|
69
|
+
"""Raise unless durable old prefixes and local serving copies are absent."""
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@runtime_checkable
|
|
74
|
+
class KGitPurgePort(Protocol):
|
|
75
|
+
"""Erase affected Plane-K paths from all reachable Git history."""
|
|
76
|
+
|
|
77
|
+
def blocking_redaction_paths(
|
|
78
|
+
self, *, deployment_id: UUID, doc_id: UUID
|
|
79
|
+
) -> tuple[str, ...]:
|
|
80
|
+
"""Return sorted authored-body or curation paths that still cite a lineage."""
|
|
81
|
+
...
|
|
82
|
+
|
|
83
|
+
def purge_artifacts(
|
|
84
|
+
self, *, deployment_id: UUID, forget_id: UUID, artifact_ids: tuple[UUID, ...]
|
|
85
|
+
) -> None:
|
|
86
|
+
"""Erase affected history and retain only already-sanitized current files."""
|
|
87
|
+
...
|
|
88
|
+
|
|
89
|
+
def verify_artifacts_purged(
|
|
90
|
+
self, *, deployment_id: UUID, forget_id: UUID, artifact_ids: tuple[UUID, ...]
|
|
91
|
+
) -> None:
|
|
92
|
+
"""Raise unless the store-local receipt and affected-path history are clean."""
|
|
93
|
+
...
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""D67 delivery-only announcement seam over committed Postgres work truth."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from rememberstack.model import QueueRoute
|
|
8
|
+
from rememberstack.model import UTCDateTime
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@runtime_checkable
|
|
12
|
+
class TaskQueuePort(Protocol):
|
|
13
|
+
"""Announce an existing row using non-authoritative route and due snapshots."""
|
|
14
|
+
|
|
15
|
+
def announce(
|
|
16
|
+
self,
|
|
17
|
+
*,
|
|
18
|
+
processing_id: UUID,
|
|
19
|
+
route_snapshot: QueueRoute,
|
|
20
|
+
not_before_snapshot: UTCDateTime,
|
|
21
|
+
) -> None:
|
|
22
|
+
"""Schedule at-least-once delivery without creating or mutating work state."""
|
|
23
|
+
...
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""D61 telemetry seam preserving structured data and real exception objects."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
from typing import runtime_checkable
|
|
5
|
+
|
|
6
|
+
from rememberstack.model import TelemetryEvent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@runtime_checkable
|
|
10
|
+
class TelemetryPort(Protocol):
|
|
11
|
+
"""Export telemetry without importing a vendor SDK or hiding exporter failure."""
|
|
12
|
+
|
|
13
|
+
def export_event(self, *, event: TelemetryEvent) -> None:
|
|
14
|
+
"""Export one structured event and let exporter failures propagate."""
|
|
15
|
+
...
|
|
16
|
+
|
|
17
|
+
def export_exception(
|
|
18
|
+
self, *, event: TelemetryEvent, exception: BaseException
|
|
19
|
+
) -> None:
|
|
20
|
+
"""Export the event with the original exception object and cause chain."""
|
|
21
|
+
...
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Explicit composition root package."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from rememberstack.profiles.selfhost import SelfHostProfile
|
|
7
|
+
from rememberstack.profiles.selfhost import SelfHostSettings
|
|
8
|
+
|
|
9
|
+
__all__ = ("SelfHostProfile", "SelfHostSettings")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def __getattr__(name: str) -> object:
|
|
13
|
+
"""Load a profile only when its explicit composition root is requested."""
|
|
14
|
+
if name == "SelfHostProfile":
|
|
15
|
+
from rememberstack.profiles.selfhost import SelfHostProfile
|
|
16
|
+
|
|
17
|
+
return SelfHostProfile
|
|
18
|
+
if name == "SelfHostSettings":
|
|
19
|
+
from rememberstack.profiles.selfhost import SelfHostSettings
|
|
20
|
+
|
|
21
|
+
return SelfHostSettings
|
|
22
|
+
raise AttributeError(name)
|