alma-memory 0.5.0__py3-none-any.whl → 0.7.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.
- alma/__init__.py +296 -194
- alma/compression/__init__.py +33 -0
- alma/compression/pipeline.py +980 -0
- alma/confidence/__init__.py +47 -47
- alma/confidence/engine.py +540 -540
- alma/confidence/types.py +351 -351
- alma/config/loader.py +157 -157
- alma/consolidation/__init__.py +23 -23
- alma/consolidation/engine.py +678 -678
- alma/consolidation/prompts.py +84 -84
- alma/core.py +1189 -322
- alma/domains/__init__.py +30 -30
- alma/domains/factory.py +359 -359
- alma/domains/schemas.py +448 -448
- alma/domains/types.py +272 -272
- alma/events/__init__.py +75 -75
- alma/events/emitter.py +285 -284
- alma/events/storage_mixin.py +246 -246
- alma/events/types.py +126 -126
- alma/events/webhook.py +425 -425
- alma/exceptions.py +49 -49
- alma/extraction/__init__.py +31 -31
- alma/extraction/auto_learner.py +265 -264
- alma/extraction/extractor.py +420 -420
- alma/graph/__init__.py +106 -81
- alma/graph/backends/__init__.py +32 -18
- alma/graph/backends/kuzu.py +624 -0
- alma/graph/backends/memgraph.py +432 -0
- alma/graph/backends/memory.py +236 -236
- alma/graph/backends/neo4j.py +417 -417
- alma/graph/base.py +159 -159
- alma/graph/extraction.py +198 -198
- alma/graph/store.py +860 -860
- alma/harness/__init__.py +35 -35
- alma/harness/base.py +386 -386
- alma/harness/domains.py +705 -705
- alma/initializer/__init__.py +37 -37
- alma/initializer/initializer.py +418 -418
- alma/initializer/types.py +250 -250
- alma/integration/__init__.py +62 -62
- alma/integration/claude_agents.py +444 -432
- alma/integration/helena.py +423 -423
- alma/integration/victor.py +471 -471
- alma/learning/__init__.py +101 -86
- alma/learning/decay.py +878 -0
- alma/learning/forgetting.py +1446 -1446
- alma/learning/heuristic_extractor.py +390 -390
- alma/learning/protocols.py +374 -374
- alma/learning/validation.py +346 -346
- alma/mcp/__init__.py +123 -45
- alma/mcp/__main__.py +156 -156
- alma/mcp/resources.py +122 -122
- alma/mcp/server.py +955 -591
- alma/mcp/tools.py +3254 -511
- alma/observability/__init__.py +91 -0
- alma/observability/config.py +302 -0
- alma/observability/guidelines.py +170 -0
- alma/observability/logging.py +424 -0
- alma/observability/metrics.py +583 -0
- alma/observability/tracing.py +440 -0
- alma/progress/__init__.py +21 -21
- alma/progress/tracker.py +607 -607
- alma/progress/types.py +250 -250
- alma/retrieval/__init__.py +134 -53
- alma/retrieval/budget.py +525 -0
- alma/retrieval/cache.py +1304 -1061
- alma/retrieval/embeddings.py +202 -202
- alma/retrieval/engine.py +850 -366
- alma/retrieval/modes.py +365 -0
- alma/retrieval/progressive.py +560 -0
- alma/retrieval/scoring.py +344 -344
- alma/retrieval/trust_scoring.py +637 -0
- alma/retrieval/verification.py +797 -0
- alma/session/__init__.py +19 -19
- alma/session/manager.py +442 -399
- alma/session/types.py +288 -288
- alma/storage/__init__.py +101 -61
- alma/storage/archive.py +233 -0
- alma/storage/azure_cosmos.py +1259 -1048
- alma/storage/base.py +1083 -525
- alma/storage/chroma.py +1443 -1443
- alma/storage/constants.py +103 -0
- alma/storage/file_based.py +614 -619
- alma/storage/migrations/__init__.py +21 -0
- alma/storage/migrations/base.py +321 -0
- alma/storage/migrations/runner.py +323 -0
- alma/storage/migrations/version_stores.py +337 -0
- alma/storage/migrations/versions/__init__.py +11 -0
- alma/storage/migrations/versions/v1_0_0.py +373 -0
- alma/storage/migrations/versions/v1_1_0_workflow_context.py +551 -0
- alma/storage/pinecone.py +1080 -1080
- alma/storage/postgresql.py +1948 -1452
- alma/storage/qdrant.py +1306 -1306
- alma/storage/sqlite_local.py +3041 -1358
- alma/testing/__init__.py +46 -0
- alma/testing/factories.py +301 -0
- alma/testing/mocks.py +389 -0
- alma/types.py +292 -264
- alma/utils/__init__.py +19 -0
- alma/utils/tokenizer.py +521 -0
- alma/workflow/__init__.py +83 -0
- alma/workflow/artifacts.py +170 -0
- alma/workflow/checkpoint.py +311 -0
- alma/workflow/context.py +228 -0
- alma/workflow/outcomes.py +189 -0
- alma/workflow/reducers.py +393 -0
- {alma_memory-0.5.0.dist-info → alma_memory-0.7.0.dist-info}/METADATA +244 -72
- alma_memory-0.7.0.dist-info/RECORD +112 -0
- alma_memory-0.5.0.dist-info/RECORD +0 -76
- {alma_memory-0.5.0.dist-info → alma_memory-0.7.0.dist-info}/WHEEL +0 -0
- {alma_memory-0.5.0.dist-info → alma_memory-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ALMA Schema Migration v1.0.0 - Initial Schema.
|
|
3
|
+
|
|
4
|
+
This migration establishes the baseline schema for existing databases.
|
|
5
|
+
For fresh installations, this creates the initial tables.
|
|
6
|
+
For existing databases, this records the current state.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from alma.storage.migrations.base import Migration, register_migration
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@register_migration(backend="sqlite")
|
|
15
|
+
class SQLiteInitialSchema(Migration):
|
|
16
|
+
"""
|
|
17
|
+
SQLite initial schema migration.
|
|
18
|
+
|
|
19
|
+
This represents the baseline schema as of ALMA v0.5.x.
|
|
20
|
+
For existing databases, this is a no-op that records the baseline.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
version = "1.0.0"
|
|
24
|
+
description = "Initial ALMA schema with core tables"
|
|
25
|
+
|
|
26
|
+
def upgrade(self, connection: Any) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Create or verify initial schema.
|
|
29
|
+
|
|
30
|
+
For SQLite, this creates all core tables if they don't exist.
|
|
31
|
+
"""
|
|
32
|
+
cursor = connection.cursor()
|
|
33
|
+
|
|
34
|
+
# Heuristics table
|
|
35
|
+
cursor.execute("""
|
|
36
|
+
CREATE TABLE IF NOT EXISTS heuristics (
|
|
37
|
+
id TEXT PRIMARY KEY,
|
|
38
|
+
agent TEXT NOT NULL,
|
|
39
|
+
project_id TEXT NOT NULL,
|
|
40
|
+
condition TEXT NOT NULL,
|
|
41
|
+
strategy TEXT NOT NULL,
|
|
42
|
+
confidence REAL DEFAULT 0.0,
|
|
43
|
+
occurrence_count INTEGER DEFAULT 0,
|
|
44
|
+
success_count INTEGER DEFAULT 0,
|
|
45
|
+
last_validated TEXT,
|
|
46
|
+
created_at TEXT,
|
|
47
|
+
metadata TEXT
|
|
48
|
+
)
|
|
49
|
+
""")
|
|
50
|
+
cursor.execute(
|
|
51
|
+
"CREATE INDEX IF NOT EXISTS idx_heuristics_project_agent "
|
|
52
|
+
"ON heuristics(project_id, agent)"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Outcomes table
|
|
56
|
+
cursor.execute("""
|
|
57
|
+
CREATE TABLE IF NOT EXISTS outcomes (
|
|
58
|
+
id TEXT PRIMARY KEY,
|
|
59
|
+
agent TEXT NOT NULL,
|
|
60
|
+
project_id TEXT NOT NULL,
|
|
61
|
+
task_type TEXT,
|
|
62
|
+
task_description TEXT NOT NULL,
|
|
63
|
+
success INTEGER DEFAULT 0,
|
|
64
|
+
strategy_used TEXT,
|
|
65
|
+
duration_ms INTEGER,
|
|
66
|
+
error_message TEXT,
|
|
67
|
+
user_feedback TEXT,
|
|
68
|
+
timestamp TEXT,
|
|
69
|
+
metadata TEXT
|
|
70
|
+
)
|
|
71
|
+
""")
|
|
72
|
+
cursor.execute(
|
|
73
|
+
"CREATE INDEX IF NOT EXISTS idx_outcomes_project_agent "
|
|
74
|
+
"ON outcomes(project_id, agent)"
|
|
75
|
+
)
|
|
76
|
+
cursor.execute(
|
|
77
|
+
"CREATE INDEX IF NOT EXISTS idx_outcomes_task_type "
|
|
78
|
+
"ON outcomes(project_id, agent, task_type)"
|
|
79
|
+
)
|
|
80
|
+
cursor.execute(
|
|
81
|
+
"CREATE INDEX IF NOT EXISTS idx_outcomes_timestamp "
|
|
82
|
+
"ON outcomes(project_id, timestamp)"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# User preferences table
|
|
86
|
+
cursor.execute("""
|
|
87
|
+
CREATE TABLE IF NOT EXISTS preferences (
|
|
88
|
+
id TEXT PRIMARY KEY,
|
|
89
|
+
user_id TEXT NOT NULL,
|
|
90
|
+
category TEXT,
|
|
91
|
+
preference TEXT NOT NULL,
|
|
92
|
+
source TEXT,
|
|
93
|
+
confidence REAL DEFAULT 1.0,
|
|
94
|
+
timestamp TEXT,
|
|
95
|
+
metadata TEXT
|
|
96
|
+
)
|
|
97
|
+
""")
|
|
98
|
+
cursor.execute(
|
|
99
|
+
"CREATE INDEX IF NOT EXISTS idx_preferences_user ON preferences(user_id)"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Domain knowledge table
|
|
103
|
+
cursor.execute("""
|
|
104
|
+
CREATE TABLE IF NOT EXISTS domain_knowledge (
|
|
105
|
+
id TEXT PRIMARY KEY,
|
|
106
|
+
agent TEXT NOT NULL,
|
|
107
|
+
project_id TEXT NOT NULL,
|
|
108
|
+
domain TEXT,
|
|
109
|
+
fact TEXT NOT NULL,
|
|
110
|
+
source TEXT,
|
|
111
|
+
confidence REAL DEFAULT 1.0,
|
|
112
|
+
last_verified TEXT,
|
|
113
|
+
metadata TEXT
|
|
114
|
+
)
|
|
115
|
+
""")
|
|
116
|
+
cursor.execute(
|
|
117
|
+
"CREATE INDEX IF NOT EXISTS idx_domain_knowledge_project_agent "
|
|
118
|
+
"ON domain_knowledge(project_id, agent)"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Anti-patterns table
|
|
122
|
+
cursor.execute("""
|
|
123
|
+
CREATE TABLE IF NOT EXISTS anti_patterns (
|
|
124
|
+
id TEXT PRIMARY KEY,
|
|
125
|
+
agent TEXT NOT NULL,
|
|
126
|
+
project_id TEXT NOT NULL,
|
|
127
|
+
pattern TEXT NOT NULL,
|
|
128
|
+
why_bad TEXT,
|
|
129
|
+
better_alternative TEXT,
|
|
130
|
+
occurrence_count INTEGER DEFAULT 1,
|
|
131
|
+
last_seen TEXT,
|
|
132
|
+
created_at TEXT,
|
|
133
|
+
metadata TEXT
|
|
134
|
+
)
|
|
135
|
+
""")
|
|
136
|
+
cursor.execute(
|
|
137
|
+
"CREATE INDEX IF NOT EXISTS idx_anti_patterns_project_agent "
|
|
138
|
+
"ON anti_patterns(project_id, agent)"
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Embeddings table
|
|
142
|
+
cursor.execute("""
|
|
143
|
+
CREATE TABLE IF NOT EXISTS embeddings (
|
|
144
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
145
|
+
memory_type TEXT NOT NULL,
|
|
146
|
+
memory_id TEXT NOT NULL,
|
|
147
|
+
embedding BLOB NOT NULL,
|
|
148
|
+
UNIQUE(memory_type, memory_id)
|
|
149
|
+
)
|
|
150
|
+
""")
|
|
151
|
+
cursor.execute(
|
|
152
|
+
"CREATE INDEX IF NOT EXISTS idx_embeddings_type ON embeddings(memory_type)"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
connection.commit()
|
|
156
|
+
|
|
157
|
+
def downgrade(self, connection: Any) -> None:
|
|
158
|
+
"""
|
|
159
|
+
Downgrade is not supported for initial schema.
|
|
160
|
+
|
|
161
|
+
Rolling back the initial schema would destroy all data.
|
|
162
|
+
"""
|
|
163
|
+
raise NotImplementedError(
|
|
164
|
+
"Cannot roll back initial schema - this would destroy all data"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def pre_check(self, connection: Any) -> bool:
|
|
168
|
+
"""Verify we can connect to the database."""
|
|
169
|
+
try:
|
|
170
|
+
cursor = connection.cursor()
|
|
171
|
+
cursor.execute("SELECT 1")
|
|
172
|
+
return True
|
|
173
|
+
except Exception:
|
|
174
|
+
return False
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@register_migration(backend="postgresql")
|
|
178
|
+
class PostgreSQLInitialSchema(Migration):
|
|
179
|
+
"""
|
|
180
|
+
PostgreSQL initial schema migration.
|
|
181
|
+
|
|
182
|
+
This represents the baseline schema as of ALMA v0.5.x.
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
version = "1.0.0"
|
|
186
|
+
description = "Initial ALMA schema with core tables and pgvector support"
|
|
187
|
+
|
|
188
|
+
def __init__(self, schema: str = "public", embedding_dim: int = 384):
|
|
189
|
+
self._schema = schema
|
|
190
|
+
self._embedding_dim = embedding_dim
|
|
191
|
+
|
|
192
|
+
def upgrade(self, connection: Any) -> None:
|
|
193
|
+
"""Create or verify initial PostgreSQL schema."""
|
|
194
|
+
schema = self._schema
|
|
195
|
+
embedding_dim = self._embedding_dim
|
|
196
|
+
|
|
197
|
+
# Try to enable pgvector
|
|
198
|
+
pgvector_available = False
|
|
199
|
+
try:
|
|
200
|
+
connection.execute("CREATE EXTENSION IF NOT EXISTS vector")
|
|
201
|
+
connection.commit()
|
|
202
|
+
pgvector_available = True
|
|
203
|
+
except Exception:
|
|
204
|
+
connection.rollback()
|
|
205
|
+
|
|
206
|
+
vector_type = f"VECTOR({embedding_dim})" if pgvector_available else "BYTEA"
|
|
207
|
+
|
|
208
|
+
# Heuristics table
|
|
209
|
+
connection.execute(f"""
|
|
210
|
+
CREATE TABLE IF NOT EXISTS {schema}.alma_heuristics (
|
|
211
|
+
id TEXT PRIMARY KEY,
|
|
212
|
+
agent TEXT NOT NULL,
|
|
213
|
+
project_id TEXT NOT NULL,
|
|
214
|
+
condition TEXT NOT NULL,
|
|
215
|
+
strategy TEXT NOT NULL,
|
|
216
|
+
confidence REAL DEFAULT 0.0,
|
|
217
|
+
occurrence_count INTEGER DEFAULT 0,
|
|
218
|
+
success_count INTEGER DEFAULT 0,
|
|
219
|
+
last_validated TIMESTAMPTZ,
|
|
220
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
221
|
+
metadata JSONB,
|
|
222
|
+
embedding {vector_type}
|
|
223
|
+
)
|
|
224
|
+
""")
|
|
225
|
+
connection.execute(f"""
|
|
226
|
+
CREATE INDEX IF NOT EXISTS idx_heuristics_project_agent
|
|
227
|
+
ON {schema}.alma_heuristics(project_id, agent)
|
|
228
|
+
""")
|
|
229
|
+
connection.execute(f"""
|
|
230
|
+
CREATE INDEX IF NOT EXISTS idx_heuristics_confidence
|
|
231
|
+
ON {schema}.alma_heuristics(project_id, confidence DESC)
|
|
232
|
+
""")
|
|
233
|
+
|
|
234
|
+
# Outcomes table
|
|
235
|
+
connection.execute(f"""
|
|
236
|
+
CREATE TABLE IF NOT EXISTS {schema}.alma_outcomes (
|
|
237
|
+
id TEXT PRIMARY KEY,
|
|
238
|
+
agent TEXT NOT NULL,
|
|
239
|
+
project_id TEXT NOT NULL,
|
|
240
|
+
task_type TEXT,
|
|
241
|
+
task_description TEXT NOT NULL,
|
|
242
|
+
success BOOLEAN DEFAULT FALSE,
|
|
243
|
+
strategy_used TEXT,
|
|
244
|
+
duration_ms INTEGER,
|
|
245
|
+
error_message TEXT,
|
|
246
|
+
user_feedback TEXT,
|
|
247
|
+
timestamp TIMESTAMPTZ DEFAULT NOW(),
|
|
248
|
+
metadata JSONB,
|
|
249
|
+
embedding {vector_type}
|
|
250
|
+
)
|
|
251
|
+
""")
|
|
252
|
+
connection.execute(f"""
|
|
253
|
+
CREATE INDEX IF NOT EXISTS idx_outcomes_project_agent
|
|
254
|
+
ON {schema}.alma_outcomes(project_id, agent)
|
|
255
|
+
""")
|
|
256
|
+
connection.execute(f"""
|
|
257
|
+
CREATE INDEX IF NOT EXISTS idx_outcomes_task_type
|
|
258
|
+
ON {schema}.alma_outcomes(project_id, agent, task_type)
|
|
259
|
+
""")
|
|
260
|
+
connection.execute(f"""
|
|
261
|
+
CREATE INDEX IF NOT EXISTS idx_outcomes_timestamp
|
|
262
|
+
ON {schema}.alma_outcomes(project_id, timestamp DESC)
|
|
263
|
+
""")
|
|
264
|
+
|
|
265
|
+
# User preferences table
|
|
266
|
+
connection.execute(f"""
|
|
267
|
+
CREATE TABLE IF NOT EXISTS {schema}.alma_preferences (
|
|
268
|
+
id TEXT PRIMARY KEY,
|
|
269
|
+
user_id TEXT NOT NULL,
|
|
270
|
+
category TEXT,
|
|
271
|
+
preference TEXT NOT NULL,
|
|
272
|
+
source TEXT,
|
|
273
|
+
confidence REAL DEFAULT 1.0,
|
|
274
|
+
timestamp TIMESTAMPTZ DEFAULT NOW(),
|
|
275
|
+
metadata JSONB
|
|
276
|
+
)
|
|
277
|
+
""")
|
|
278
|
+
connection.execute(f"""
|
|
279
|
+
CREATE INDEX IF NOT EXISTS idx_preferences_user
|
|
280
|
+
ON {schema}.alma_preferences(user_id)
|
|
281
|
+
""")
|
|
282
|
+
|
|
283
|
+
# Domain knowledge table
|
|
284
|
+
connection.execute(f"""
|
|
285
|
+
CREATE TABLE IF NOT EXISTS {schema}.alma_domain_knowledge (
|
|
286
|
+
id TEXT PRIMARY KEY,
|
|
287
|
+
agent TEXT NOT NULL,
|
|
288
|
+
project_id TEXT NOT NULL,
|
|
289
|
+
domain TEXT,
|
|
290
|
+
fact TEXT NOT NULL,
|
|
291
|
+
source TEXT,
|
|
292
|
+
confidence REAL DEFAULT 1.0,
|
|
293
|
+
last_verified TIMESTAMPTZ DEFAULT NOW(),
|
|
294
|
+
metadata JSONB,
|
|
295
|
+
embedding {vector_type}
|
|
296
|
+
)
|
|
297
|
+
""")
|
|
298
|
+
connection.execute(f"""
|
|
299
|
+
CREATE INDEX IF NOT EXISTS idx_domain_knowledge_project_agent
|
|
300
|
+
ON {schema}.alma_domain_knowledge(project_id, agent)
|
|
301
|
+
""")
|
|
302
|
+
connection.execute(f"""
|
|
303
|
+
CREATE INDEX IF NOT EXISTS idx_domain_knowledge_confidence
|
|
304
|
+
ON {schema}.alma_domain_knowledge(project_id, confidence DESC)
|
|
305
|
+
""")
|
|
306
|
+
|
|
307
|
+
# Anti-patterns table
|
|
308
|
+
connection.execute(f"""
|
|
309
|
+
CREATE TABLE IF NOT EXISTS {schema}.alma_anti_patterns (
|
|
310
|
+
id TEXT PRIMARY KEY,
|
|
311
|
+
agent TEXT NOT NULL,
|
|
312
|
+
project_id TEXT NOT NULL,
|
|
313
|
+
pattern TEXT NOT NULL,
|
|
314
|
+
why_bad TEXT,
|
|
315
|
+
better_alternative TEXT,
|
|
316
|
+
occurrence_count INTEGER DEFAULT 1,
|
|
317
|
+
last_seen TIMESTAMPTZ DEFAULT NOW(),
|
|
318
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
319
|
+
metadata JSONB,
|
|
320
|
+
embedding {vector_type}
|
|
321
|
+
)
|
|
322
|
+
""")
|
|
323
|
+
connection.execute(f"""
|
|
324
|
+
CREATE INDEX IF NOT EXISTS idx_anti_patterns_project_agent
|
|
325
|
+
ON {schema}.alma_anti_patterns(project_id, agent)
|
|
326
|
+
""")
|
|
327
|
+
|
|
328
|
+
# Create vector indexes if pgvector available
|
|
329
|
+
if pgvector_available:
|
|
330
|
+
for table in [
|
|
331
|
+
"alma_heuristics",
|
|
332
|
+
"alma_outcomes",
|
|
333
|
+
"alma_domain_knowledge",
|
|
334
|
+
"alma_anti_patterns",
|
|
335
|
+
]:
|
|
336
|
+
try:
|
|
337
|
+
connection.execute(f"""
|
|
338
|
+
CREATE INDEX IF NOT EXISTS idx_{table}_embedding
|
|
339
|
+
ON {schema}.{table}
|
|
340
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
341
|
+
WITH (m = 16, ef_construction = 64)
|
|
342
|
+
""")
|
|
343
|
+
except Exception:
|
|
344
|
+
pass # Index may already exist or not be possible
|
|
345
|
+
|
|
346
|
+
connection.commit()
|
|
347
|
+
|
|
348
|
+
def downgrade(self, connection: Any) -> None:
|
|
349
|
+
"""Cannot roll back initial schema."""
|
|
350
|
+
raise NotImplementedError(
|
|
351
|
+
"Cannot roll back initial schema - this would destroy all data"
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
@register_migration()
|
|
356
|
+
class FileBasedInitialSchema(Migration):
|
|
357
|
+
"""
|
|
358
|
+
File-based storage initial schema migration.
|
|
359
|
+
|
|
360
|
+
This is mostly a no-op since file-based storage creates files on demand.
|
|
361
|
+
"""
|
|
362
|
+
|
|
363
|
+
version = "1.0.0"
|
|
364
|
+
description = "Initial ALMA file-based storage schema"
|
|
365
|
+
|
|
366
|
+
def upgrade(self, storage: Any) -> None:
|
|
367
|
+
"""Verify file-based storage is properly initialized."""
|
|
368
|
+
# File-based storage creates files on demand, so this is a no-op
|
|
369
|
+
pass
|
|
370
|
+
|
|
371
|
+
def downgrade(self, storage: Any) -> None:
|
|
372
|
+
"""Cannot roll back initial schema."""
|
|
373
|
+
raise NotImplementedError("Cannot roll back initial schema")
|