textus 0.55.1 → 0.55.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/README.md +9 -9
- data/SPEC.md +14 -13
- data/docs/architecture/README.md +3 -3
- data/docs/reference/conventions.md +5 -2
- data/lib/textus/boot.rb +64 -85
- data/lib/textus/{gate → dispatch}/binder.rb +8 -10
- data/lib/textus/dispatch/contracts.rb +63 -0
- data/lib/textus/dispatch/handler_registry.rb +21 -0
- data/lib/textus/dispatch/middleware/audit_index.rb +51 -0
- data/lib/textus/dispatch/middleware/auth.rb +40 -0
- data/lib/textus/dispatch/middleware/base.rb +26 -0
- data/lib/textus/dispatch/middleware/binder.rb +20 -0
- data/lib/textus/dispatch/middleware/cascade.rb +53 -0
- data/lib/textus/dispatch/pipeline.rb +35 -0
- data/lib/textus/doctor/check/audit_log.rb +1 -1
- data/lib/textus/doctor/check/generator_drift.rb +2 -2
- data/lib/textus/doctor/check/orphaned_publish_targets.rb +1 -1
- data/lib/textus/doctor/check/schema_violations.rb +1 -1
- data/lib/textus/doctor/check/{notebook_sources.rb → scratchpad_sources.rb} +10 -5
- data/lib/textus/doctor/check/sentinels.rb +1 -1
- data/lib/textus/doctor/check.rb +8 -6
- data/lib/textus/doctor.rb +1 -1
- data/lib/textus/errors.rb +2 -0
- data/lib/textus/format/base.rb +36 -8
- data/lib/textus/format/json.rb +0 -21
- data/lib/textus/format/markdown.rb +0 -21
- data/lib/textus/format/yaml.rb +0 -21
- data/lib/textus/format.rb +16 -1
- data/lib/textus/handlers/maintenance/boot_store.rb +15 -0
- data/lib/textus/handlers/maintenance/doctor_store.rb +15 -0
- data/lib/textus/handlers/maintenance/drain_store.rb +21 -0
- data/lib/textus/handlers/maintenance/ingest_entry.rb +159 -0
- data/lib/textus/handlers/maintenance/jobs_action.rb +21 -0
- data/lib/textus/handlers/maintenance/published_entries.rb +17 -0
- data/lib/textus/handlers/maintenance/rule_explain.rb +77 -0
- data/lib/textus/handlers/maintenance/rule_lint.rb +54 -0
- data/lib/textus/handlers/maintenance/rule_list.rb +32 -0
- data/lib/textus/handlers/maintenance/schema_envelope.rb +19 -0
- data/lib/textus/handlers/read/audit_entries.rb +48 -0
- data/lib/textus/handlers/read/blame_entry.rb +71 -0
- data/lib/textus/handlers/read/deps_entry.rb +17 -0
- data/lib/textus/handlers/read/get_entry.rb +68 -0
- data/lib/textus/handlers/read/list_keys.rb +36 -0
- data/lib/textus/handlers/read/pulse_entries.rb +66 -0
- data/lib/textus/handlers/read/rdeps_entry.rb +21 -0
- data/lib/textus/handlers/read/uid_entry.rb +18 -0
- data/lib/textus/handlers/read/where_entry.rb +18 -0
- data/lib/textus/handlers/write/accept_proposal.rb +39 -0
- data/lib/textus/handlers/write/data_mv.rb +55 -0
- data/lib/textus/handlers/write/delete_key.rb +17 -0
- data/lib/textus/handlers/write/enqueue_job.rb +27 -0
- data/lib/textus/handlers/write/key_delete_prefix.rb +32 -0
- data/lib/textus/handlers/write/key_mv_prefix.rb +45 -0
- data/lib/textus/handlers/write/move_key.rb +80 -0
- data/lib/textus/handlers/write/propose_entry.rb +29 -0
- data/lib/textus/handlers/write/put_entry.rb +29 -0
- data/lib/textus/handlers/write/reject_proposal.rb +29 -0
- data/lib/textus/init.rb +5 -5
- data/lib/textus/manifest/capabilities.rb +1 -1
- data/lib/textus/manifest/entry/base.rb +3 -3
- data/lib/textus/manifest/entry/publish/to_paths.rb +1 -1
- data/lib/textus/manifest/policy/predicates/author_held.rb +22 -0
- data/lib/textus/manifest/policy/predicates/etag_match.rb +18 -0
- data/lib/textus/manifest/policy/predicates/fresh_within.rb +13 -0
- data/lib/textus/manifest/policy/predicates/lane_deletable_by.rb +31 -0
- data/lib/textus/manifest/policy/predicates/lane_writable_by.rb +23 -0
- data/lib/textus/manifest/policy/predicates/raw_lane_ingest_only.rb +25 -0
- data/lib/textus/manifest/policy/predicates/raw_write_once.rb +24 -0
- data/lib/textus/manifest/policy/predicates/schema_valid.rb +41 -0
- data/lib/textus/manifest/policy/predicates/target_is_canon.rb +20 -0
- data/lib/textus/manifest/policy/predicates.rb +54 -0
- data/lib/textus/manifest/policy/retention.rb +1 -1
- data/lib/textus/orchestration.rb +55 -0
- data/lib/textus/port/audit_log.rb +6 -6
- data/lib/textus/port/build_lock.rb +1 -1
- data/lib/textus/{core → port}/sentinel.rb +1 -6
- data/lib/textus/port/sentinel_store.rb +3 -3
- data/lib/textus/port/storage/file_store.rb +23 -0
- data/lib/textus/port/storage/interface.rb +17 -0
- data/lib/textus/port/store.rb +58 -2
- data/lib/textus/port/watcher_lock.rb +2 -2
- data/lib/textus/produce/engine.rb +1 -11
- data/lib/textus/produce/publisher.rb +21 -0
- data/lib/textus/schema/registry.rb +42 -0
- data/lib/textus/schema/tools.rb +3 -10
- data/lib/textus/store/container.rb +140 -10
- data/lib/textus/store/cursor.rb +1 -1
- data/lib/textus/store/{envelope → entry}/reader.rb +8 -4
- data/lib/textus/store/{envelope → entry}/writer.rb +53 -29
- data/lib/textus/store/envelope/meta.rb +61 -0
- data/lib/textus/store/freshness/drift_detector.rb +93 -0
- data/lib/textus/store/freshness/evaluator.rb +20 -0
- data/lib/textus/store/freshness/ttl_evaluator.rb +57 -0
- data/lib/textus/{core → store}/freshness/verdict.rb +1 -11
- data/lib/textus/store/freshness.rb +8 -0
- data/lib/textus/store/index/builder.rb +5 -3
- data/lib/textus/store/jobs/planner.rb +27 -7
- data/lib/textus/store/jobs/queue.rb +9 -1
- data/lib/textus/store/jobs/retention/base.rb +52 -0
- data/lib/textus/store/jobs/retention/sweep.rb +55 -0
- data/lib/textus/store/jobs/retention.rb +1 -43
- data/lib/textus/store/jobs/sweep.rb +2 -2
- data/lib/textus/store/{geometry.rb → layout.rb} +19 -3
- data/lib/textus/store.rb +53 -30
- data/lib/textus/surface/cli/runner.rb +8 -9
- data/lib/textus/surface/cli/verb/doctor.rb +3 -2
- data/lib/textus/surface/cli/verb/get.rb +5 -3
- data/lib/textus/surface/cli/verb/put.rb +5 -3
- data/lib/textus/surface/mcp/catalog.rb +26 -62
- data/lib/textus/surface/mcp/errors.rb +0 -10
- data/lib/textus/surface/mcp/projector.rb +20 -0
- data/lib/textus/surface/mcp/server.rb +20 -31
- data/lib/textus/{core → value}/duration.rb +1 -4
- data/lib/textus/value/envelope.rb +5 -4
- data/lib/textus/value/etag.rb +1 -1
- data/lib/textus/value/payload.rb +7 -0
- data/lib/textus/value/result.rb +36 -16
- data/lib/textus/verb_registry.rb +417 -0
- data/lib/textus/version.rb +1 -1
- data/lib/textus/workflow/loader.rb +1 -1
- data/lib/textus/workflow/runner.rb +10 -18
- data/lib/textus.rb +0 -64
- metadata +70 -70
- data/lib/textus/action/accept.rb +0 -46
- data/lib/textus/action/audit.rb +0 -94
- data/lib/textus/action/base.rb +0 -42
- data/lib/textus/action/blame.rb +0 -79
- data/lib/textus/action/boot.rb +0 -15
- data/lib/textus/action/data_mv.rb +0 -58
- data/lib/textus/action/deps.rb +0 -19
- data/lib/textus/action/doctor.rb +0 -17
- data/lib/textus/action/drain.rb +0 -31
- data/lib/textus/action/enqueue.rb +0 -37
- data/lib/textus/action/get.rb +0 -34
- data/lib/textus/action/ingest.rb +0 -199
- data/lib/textus/action/jobs.rb +0 -27
- data/lib/textus/action/key_delete.rb +0 -26
- data/lib/textus/action/key_delete_prefix.rb +0 -35
- data/lib/textus/action/key_mv.rb +0 -122
- data/lib/textus/action/key_mv_prefix.rb +0 -48
- data/lib/textus/action/list.rb +0 -28
- data/lib/textus/action/propose.rb +0 -42
- data/lib/textus/action/published.rb +0 -22
- data/lib/textus/action/pulse.rb +0 -49
- data/lib/textus/action/put.rb +0 -38
- data/lib/textus/action/rdeps.rb +0 -24
- data/lib/textus/action/reject.rb +0 -28
- data/lib/textus/action/rule_explain.rb +0 -81
- data/lib/textus/action/rule_lint.rb +0 -62
- data/lib/textus/action/rule_list.rb +0 -38
- data/lib/textus/action/schema_envelope.rb +0 -22
- data/lib/textus/action/uid.rb +0 -19
- data/lib/textus/action/where.rb +0 -21
- data/lib/textus/contract/arg.rb +0 -10
- data/lib/textus/contract/dsl.rb +0 -88
- data/lib/textus/contract/spec.rb +0 -25
- data/lib/textus/contract.rb +0 -12
- data/lib/textus/core/freshness/evaluator.rb +0 -150
- data/lib/textus/core/freshness.rb +0 -11
- data/lib/textus/core/retention/sweep.rb +0 -57
- data/lib/textus/core/retention.rb +0 -11
- data/lib/textus/format/shared.rb +0 -17
- data/lib/textus/gate/auth.rb +0 -212
- data/lib/textus/gate.rb +0 -92
- data/lib/textus/meta.rb +0 -54
- data/lib/textus/schemas.rb +0 -54
- data/lib/textus/store/compositor.rb +0 -34
- data/lib/textus/store/session.rb +0 -37
- data/lib/textus/surface/projector.rb +0 -27
- data/lib/textus/surface/role_scope.rb +0 -34
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: textus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.55.
|
|
4
|
+
version: 0.55.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrick
|
|
@@ -23,20 +23,6 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '3.0'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: dry-monads
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - "~>"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '1.6'
|
|
33
|
-
type: :runtime
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '1.6'
|
|
40
26
|
- !ruby/object:Gem::Dependency
|
|
41
27
|
name: dry-schema
|
|
42
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -180,55 +166,22 @@ files:
|
|
|
180
166
|
- docs/reference/conventions.md
|
|
181
167
|
- exe/textus
|
|
182
168
|
- lib/textus.rb
|
|
183
|
-
- lib/textus/action/accept.rb
|
|
184
|
-
- lib/textus/action/audit.rb
|
|
185
|
-
- lib/textus/action/base.rb
|
|
186
|
-
- lib/textus/action/blame.rb
|
|
187
|
-
- lib/textus/action/boot.rb
|
|
188
|
-
- lib/textus/action/data_mv.rb
|
|
189
|
-
- lib/textus/action/deps.rb
|
|
190
|
-
- lib/textus/action/doctor.rb
|
|
191
|
-
- lib/textus/action/drain.rb
|
|
192
|
-
- lib/textus/action/enqueue.rb
|
|
193
|
-
- lib/textus/action/get.rb
|
|
194
|
-
- lib/textus/action/ingest.rb
|
|
195
|
-
- lib/textus/action/jobs.rb
|
|
196
|
-
- lib/textus/action/key_delete.rb
|
|
197
|
-
- lib/textus/action/key_delete_prefix.rb
|
|
198
|
-
- lib/textus/action/key_mv.rb
|
|
199
|
-
- lib/textus/action/key_mv_prefix.rb
|
|
200
|
-
- lib/textus/action/list.rb
|
|
201
|
-
- lib/textus/action/propose.rb
|
|
202
|
-
- lib/textus/action/published.rb
|
|
203
|
-
- lib/textus/action/pulse.rb
|
|
204
|
-
- lib/textus/action/put.rb
|
|
205
|
-
- lib/textus/action/rdeps.rb
|
|
206
|
-
- lib/textus/action/reject.rb
|
|
207
|
-
- lib/textus/action/rule_explain.rb
|
|
208
|
-
- lib/textus/action/rule_lint.rb
|
|
209
|
-
- lib/textus/action/rule_list.rb
|
|
210
|
-
- lib/textus/action/schema_envelope.rb
|
|
211
|
-
- lib/textus/action/uid.rb
|
|
212
|
-
- lib/textus/action/where.rb
|
|
213
169
|
- lib/textus/boot.rb
|
|
214
|
-
- lib/textus/
|
|
215
|
-
- lib/textus/
|
|
216
|
-
- lib/textus/
|
|
217
|
-
- lib/textus/
|
|
218
|
-
- lib/textus/
|
|
219
|
-
- lib/textus/
|
|
220
|
-
- lib/textus/
|
|
221
|
-
- lib/textus/
|
|
222
|
-
- lib/textus/
|
|
223
|
-
- lib/textus/core/retention/sweep.rb
|
|
224
|
-
- lib/textus/core/sentinel.rb
|
|
170
|
+
- lib/textus/dispatch/binder.rb
|
|
171
|
+
- lib/textus/dispatch/contracts.rb
|
|
172
|
+
- lib/textus/dispatch/handler_registry.rb
|
|
173
|
+
- lib/textus/dispatch/middleware/audit_index.rb
|
|
174
|
+
- lib/textus/dispatch/middleware/auth.rb
|
|
175
|
+
- lib/textus/dispatch/middleware/base.rb
|
|
176
|
+
- lib/textus/dispatch/middleware/binder.rb
|
|
177
|
+
- lib/textus/dispatch/middleware/cascade.rb
|
|
178
|
+
- lib/textus/dispatch/pipeline.rb
|
|
225
179
|
- lib/textus/doctor.rb
|
|
226
180
|
- lib/textus/doctor/check.rb
|
|
227
181
|
- lib/textus/doctor/check/audit_log.rb
|
|
228
182
|
- lib/textus/doctor/check/generator_drift.rb
|
|
229
183
|
- lib/textus/doctor/check/illegal_keys.rb
|
|
230
184
|
- lib/textus/doctor/check/manifest_files.rb
|
|
231
|
-
- lib/textus/doctor/check/notebook_sources.rb
|
|
232
185
|
- lib/textus/doctor/check/orphaned_publish_targets.rb
|
|
233
186
|
- lib/textus/doctor/check/proposal_targets.rb
|
|
234
187
|
- lib/textus/doctor/check/protocol_version.rb
|
|
@@ -238,6 +191,7 @@ files:
|
|
|
238
191
|
- lib/textus/doctor/check/schema_parse_error.rb
|
|
239
192
|
- lib/textus/doctor/check/schema_violations.rb
|
|
240
193
|
- lib/textus/doctor/check/schemas.rb
|
|
194
|
+
- lib/textus/doctor/check/scratchpad_sources.rb
|
|
241
195
|
- lib/textus/doctor/check/sentinels.rb
|
|
242
196
|
- lib/textus/doctor/check/stale_reviewed_stamp.rb
|
|
243
197
|
- lib/textus/doctor/check/templates.rb
|
|
@@ -248,12 +202,37 @@ files:
|
|
|
248
202
|
- lib/textus/format/base.rb
|
|
249
203
|
- lib/textus/format/json.rb
|
|
250
204
|
- lib/textus/format/markdown.rb
|
|
251
|
-
- lib/textus/format/shared.rb
|
|
252
205
|
- lib/textus/format/text.rb
|
|
253
206
|
- lib/textus/format/yaml.rb
|
|
254
|
-
- lib/textus/
|
|
255
|
-
- lib/textus/
|
|
256
|
-
- lib/textus/
|
|
207
|
+
- lib/textus/handlers/maintenance/boot_store.rb
|
|
208
|
+
- lib/textus/handlers/maintenance/doctor_store.rb
|
|
209
|
+
- lib/textus/handlers/maintenance/drain_store.rb
|
|
210
|
+
- lib/textus/handlers/maintenance/ingest_entry.rb
|
|
211
|
+
- lib/textus/handlers/maintenance/jobs_action.rb
|
|
212
|
+
- lib/textus/handlers/maintenance/published_entries.rb
|
|
213
|
+
- lib/textus/handlers/maintenance/rule_explain.rb
|
|
214
|
+
- lib/textus/handlers/maintenance/rule_lint.rb
|
|
215
|
+
- lib/textus/handlers/maintenance/rule_list.rb
|
|
216
|
+
- lib/textus/handlers/maintenance/schema_envelope.rb
|
|
217
|
+
- lib/textus/handlers/read/audit_entries.rb
|
|
218
|
+
- lib/textus/handlers/read/blame_entry.rb
|
|
219
|
+
- lib/textus/handlers/read/deps_entry.rb
|
|
220
|
+
- lib/textus/handlers/read/get_entry.rb
|
|
221
|
+
- lib/textus/handlers/read/list_keys.rb
|
|
222
|
+
- lib/textus/handlers/read/pulse_entries.rb
|
|
223
|
+
- lib/textus/handlers/read/rdeps_entry.rb
|
|
224
|
+
- lib/textus/handlers/read/uid_entry.rb
|
|
225
|
+
- lib/textus/handlers/read/where_entry.rb
|
|
226
|
+
- lib/textus/handlers/write/accept_proposal.rb
|
|
227
|
+
- lib/textus/handlers/write/data_mv.rb
|
|
228
|
+
- lib/textus/handlers/write/delete_key.rb
|
|
229
|
+
- lib/textus/handlers/write/enqueue_job.rb
|
|
230
|
+
- lib/textus/handlers/write/key_delete_prefix.rb
|
|
231
|
+
- lib/textus/handlers/write/key_mv_prefix.rb
|
|
232
|
+
- lib/textus/handlers/write/move_key.rb
|
|
233
|
+
- lib/textus/handlers/write/propose_entry.rb
|
|
234
|
+
- lib/textus/handlers/write/put_entry.rb
|
|
235
|
+
- lib/textus/handlers/write/reject_proposal.rb
|
|
257
236
|
- lib/textus/init.rb
|
|
258
237
|
- lib/textus/jobs.rb
|
|
259
238
|
- lib/textus/key/distance.rb
|
|
@@ -283,6 +262,16 @@ files:
|
|
|
283
262
|
- lib/textus/manifest/entry/validators/publish.rb
|
|
284
263
|
- lib/textus/manifest/policy.rb
|
|
285
264
|
- lib/textus/manifest/policy/matcher.rb
|
|
265
|
+
- lib/textus/manifest/policy/predicates.rb
|
|
266
|
+
- lib/textus/manifest/policy/predicates/author_held.rb
|
|
267
|
+
- lib/textus/manifest/policy/predicates/etag_match.rb
|
|
268
|
+
- lib/textus/manifest/policy/predicates/fresh_within.rb
|
|
269
|
+
- lib/textus/manifest/policy/predicates/lane_deletable_by.rb
|
|
270
|
+
- lib/textus/manifest/policy/predicates/lane_writable_by.rb
|
|
271
|
+
- lib/textus/manifest/policy/predicates/raw_lane_ingest_only.rb
|
|
272
|
+
- lib/textus/manifest/policy/predicates/raw_write_once.rb
|
|
273
|
+
- lib/textus/manifest/policy/predicates/schema_valid.rb
|
|
274
|
+
- lib/textus/manifest/policy/predicates/target_is_canon.rb
|
|
286
275
|
- lib/textus/manifest/policy/publish_target.rb
|
|
287
276
|
- lib/textus/manifest/policy/react.rb
|
|
288
277
|
- lib/textus/manifest/policy/retention.rb
|
|
@@ -298,28 +287,35 @@ files:
|
|
|
298
287
|
- lib/textus/manifest/schema/semantics/migration.rb
|
|
299
288
|
- lib/textus/manifest/schema/validator.rb
|
|
300
289
|
- lib/textus/manifest/schema/vocabulary.rb
|
|
301
|
-
- lib/textus/
|
|
290
|
+
- lib/textus/orchestration.rb
|
|
302
291
|
- lib/textus/port/audit_log.rb
|
|
303
292
|
- lib/textus/port/build_lock.rb
|
|
304
293
|
- lib/textus/port/clock.rb
|
|
305
294
|
- lib/textus/port/publisher.rb
|
|
295
|
+
- lib/textus/port/sentinel.rb
|
|
306
296
|
- lib/textus/port/sentinel_store.rb
|
|
307
297
|
- lib/textus/port/storage/file_stat.rb
|
|
308
298
|
- lib/textus/port/storage/file_store.rb
|
|
299
|
+
- lib/textus/port/storage/interface.rb
|
|
309
300
|
- lib/textus/port/store.rb
|
|
310
301
|
- lib/textus/port/watcher_lock.rb
|
|
311
302
|
- lib/textus/produce/engine.rb
|
|
303
|
+
- lib/textus/produce/publisher.rb
|
|
312
304
|
- lib/textus/produce/render.rb
|
|
313
305
|
- lib/textus/schema.rb
|
|
306
|
+
- lib/textus/schema/registry.rb
|
|
314
307
|
- lib/textus/schema/tools.rb
|
|
315
|
-
- lib/textus/schemas.rb
|
|
316
308
|
- lib/textus/store.rb
|
|
317
|
-
- lib/textus/store/compositor.rb
|
|
318
309
|
- lib/textus/store/container.rb
|
|
319
310
|
- lib/textus/store/cursor.rb
|
|
320
|
-
- lib/textus/store/
|
|
321
|
-
- lib/textus/store/
|
|
322
|
-
- lib/textus/store/
|
|
311
|
+
- lib/textus/store/entry/reader.rb
|
|
312
|
+
- lib/textus/store/entry/writer.rb
|
|
313
|
+
- lib/textus/store/envelope/meta.rb
|
|
314
|
+
- lib/textus/store/freshness.rb
|
|
315
|
+
- lib/textus/store/freshness/drift_detector.rb
|
|
316
|
+
- lib/textus/store/freshness/evaluator.rb
|
|
317
|
+
- lib/textus/store/freshness/ttl_evaluator.rb
|
|
318
|
+
- lib/textus/store/freshness/verdict.rb
|
|
323
319
|
- lib/textus/store/index/builder.rb
|
|
324
320
|
- lib/textus/store/index/lookup.rb
|
|
325
321
|
- lib/textus/store/jobs/base.rb
|
|
@@ -330,9 +326,11 @@ files:
|
|
|
330
326
|
- lib/textus/store/jobs/queue.rb
|
|
331
327
|
- lib/textus/store/jobs/registry.rb
|
|
332
328
|
- lib/textus/store/jobs/retention.rb
|
|
329
|
+
- lib/textus/store/jobs/retention/base.rb
|
|
330
|
+
- lib/textus/store/jobs/retention/sweep.rb
|
|
333
331
|
- lib/textus/store/jobs/sweep.rb
|
|
334
332
|
- lib/textus/store/jobs/worker.rb
|
|
335
|
-
- lib/textus/store/
|
|
333
|
+
- lib/textus/store/layout.rb
|
|
336
334
|
- lib/textus/surface/cli.rb
|
|
337
335
|
- lib/textus/surface/cli/group.rb
|
|
338
336
|
- lib/textus/surface/cli/group/data.rb
|
|
@@ -355,18 +353,20 @@ files:
|
|
|
355
353
|
- lib/textus/surface/mcp.rb
|
|
356
354
|
- lib/textus/surface/mcp/catalog.rb
|
|
357
355
|
- lib/textus/surface/mcp/errors.rb
|
|
356
|
+
- lib/textus/surface/mcp/projector.rb
|
|
358
357
|
- lib/textus/surface/mcp/server.rb
|
|
359
|
-
- lib/textus/surface/projector.rb
|
|
360
|
-
- lib/textus/surface/role_scope.rb
|
|
361
358
|
- lib/textus/surface/watcher.rb
|
|
362
359
|
- lib/textus/value/call.rb
|
|
363
360
|
- lib/textus/value/command.rb
|
|
361
|
+
- lib/textus/value/duration.rb
|
|
364
362
|
- lib/textus/value/envelope.rb
|
|
365
363
|
- lib/textus/value/etag.rb
|
|
364
|
+
- lib/textus/value/payload.rb
|
|
366
365
|
- lib/textus/value/result.rb
|
|
367
366
|
- lib/textus/value/role.rb
|
|
368
367
|
- lib/textus/value/types.rb
|
|
369
368
|
- lib/textus/value/uid.rb
|
|
369
|
+
- lib/textus/verb_registry.rb
|
|
370
370
|
- lib/textus/version.rb
|
|
371
371
|
- lib/textus/workflow.rb
|
|
372
372
|
- lib/textus/workflow/collector.rb
|
data/lib/textus/action/accept.rb
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Textus
|
|
4
|
-
module Action
|
|
5
|
-
class Accept < Base
|
|
6
|
-
verb :accept
|
|
7
|
-
summary "apply a queued proposal to its target zone; requires the author capability"
|
|
8
|
-
surfaces :cli, :mcp
|
|
9
|
-
cli "accept"
|
|
10
|
-
arg :pending_key, String, required: true, positional: true, description: "the queued proposal's key"
|
|
11
|
-
|
|
12
|
-
def self.call(container:, call:, pending_key:)
|
|
13
|
-
env = container.compositor.read(pending_key)
|
|
14
|
-
parsed = proposal_from(env, key: pending_key)
|
|
15
|
-
return parsed if parsed.is_a?(Dry::Monads::Result::Failure)
|
|
16
|
-
|
|
17
|
-
target = parsed[:target_key]
|
|
18
|
-
action = parsed[:proposal]["action"] || "put"
|
|
19
|
-
|
|
20
|
-
case action
|
|
21
|
-
when "put"
|
|
22
|
-
mentry = container.manifest.resolver.resolve(target).entry
|
|
23
|
-
container.compositor.write(
|
|
24
|
-
target,
|
|
25
|
-
mentry: mentry,
|
|
26
|
-
payload: Textus::Store::Envelope::Writer::Payload.new(
|
|
27
|
-
meta: env.meta["_meta"] || {},
|
|
28
|
-
body: env.body,
|
|
29
|
-
content: nil,
|
|
30
|
-
),
|
|
31
|
-
call: call,
|
|
32
|
-
)
|
|
33
|
-
when "delete"
|
|
34
|
-
container.compositor.delete(target, call: call)
|
|
35
|
-
else
|
|
36
|
-
return Failure(code: :proposal_error, message: "unknown action: #{action}")
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
container.compositor.delete(pending_key, call: call)
|
|
40
|
-
|
|
41
|
-
Success("protocol" => Textus::PROTOCOL, "accepted" => pending_key, "target_key" => target, "action" => action,
|
|
42
|
-
"cascade_key" => target)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
data/lib/textus/action/audit.rb
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "json"
|
|
4
|
-
require "time"
|
|
5
|
-
|
|
6
|
-
module Textus
|
|
7
|
-
module Action
|
|
8
|
-
class Audit < Base
|
|
9
|
-
verb :audit
|
|
10
|
-
summary "Query the audit log with optional filters."
|
|
11
|
-
surfaces :cli
|
|
12
|
-
cli "audit"
|
|
13
|
-
arg :key, String, required: false, description: "filter to rows for this key"
|
|
14
|
-
arg :lane, String, required: false, description: "filter to keys in this lane"
|
|
15
|
-
arg :role, String, required: false, description: "filter to rows written under this role"
|
|
16
|
-
arg :verb, String, required: false, description: "filter to rows for this verb"
|
|
17
|
-
arg :since, String, required: false,
|
|
18
|
-
coerce: ->(s) { Textus::Action::Audit.parse_since(s, now: Time.now) },
|
|
19
|
-
description: "ISO-8601 timestamp or relative offset (e.g. 1h, 30m)"
|
|
20
|
-
arg :seq_since, Integer, required: false, description: "return rows with seq > this cursor value"
|
|
21
|
-
arg :correlation_id, String, required: false, description: "filter to rows with this correlation_id"
|
|
22
|
-
arg :limit, Integer, required: false, description: "maximum number of rows to return"
|
|
23
|
-
view(:cli) { |rows, _i| { "verb" => "audit", "rows" => rows } }
|
|
24
|
-
|
|
25
|
-
def self.call(container:, key: nil, lane: nil, role: nil, verb: nil, since: nil, seq_since: nil, correlation_id: nil, limit: nil, **) # rubocop:disable Metrics/ParameterLists
|
|
26
|
-
audit_log = container.audit_log
|
|
27
|
-
manifest = container.manifest
|
|
28
|
-
|
|
29
|
-
cursor_check = check_cursor_expiry(seq_since, audit_log)
|
|
30
|
-
return cursor_check if cursor_check.is_a?(Dry::Monads::Result::Failure)
|
|
31
|
-
|
|
32
|
-
Success(audit_log.scan(
|
|
33
|
-
seq_since: seq_since,
|
|
34
|
-
key: key,
|
|
35
|
-
role: role,
|
|
36
|
-
verb: verb,
|
|
37
|
-
correlation_id: correlation_id,
|
|
38
|
-
limit: limit,
|
|
39
|
-
).select do |row|
|
|
40
|
-
next false if lane && !key_in_lane?(row["key"], lane, manifest)
|
|
41
|
-
next false if since && (row["ts"].nil? || Time.parse(row["ts"]) < since)
|
|
42
|
-
|
|
43
|
-
true
|
|
44
|
-
end)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def self.parse_since(str, now: Time.now.utc)
|
|
48
|
-
return nil if str.nil? || str.empty?
|
|
49
|
-
return Time.parse(str) if str =~ /\A\d{4}-\d{2}-\d{2}/
|
|
50
|
-
|
|
51
|
-
match = str.match(/\A(\d+)([smhd])\z/) or return nil
|
|
52
|
-
mult = { "s" => 1, "m" => 60, "h" => 3600, "d" => 86_400 }[match[2]]
|
|
53
|
-
now - (match[1].to_i * mult)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
Query = Data.define(:key, :lane, :role, :verb, :since, :seq_since, :correlation_id, :limit) do
|
|
57
|
-
# rubocop:disable Metrics/ParameterLists
|
|
58
|
-
def self.build(key: nil, lane: nil, role: nil, verb: nil,
|
|
59
|
-
since: nil, seq_since: nil, correlation_id: nil, limit: nil)
|
|
60
|
-
new(key:, lane:, role:, verb:, since:, seq_since:, correlation_id:, limit:)
|
|
61
|
-
end
|
|
62
|
-
# rubocop:enable Metrics/ParameterLists
|
|
63
|
-
|
|
64
|
-
def matches?(row)
|
|
65
|
-
return false if key && row["key"] != key
|
|
66
|
-
return false if role && row["role"] != role
|
|
67
|
-
return false if verb && row["verb"] != verb
|
|
68
|
-
return false if since && (row["ts"].nil? || Time.parse(row["ts"]) < since)
|
|
69
|
-
return false if seq_since && (row["seq"].nil? || row["seq"] <= seq_since)
|
|
70
|
-
return false if correlation_id && row.dig("extras", "correlation_id") != correlation_id
|
|
71
|
-
|
|
72
|
-
true
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def self.check_cursor_expiry(seq_since, audit_log)
|
|
77
|
-
return unless seq_since
|
|
78
|
-
|
|
79
|
-
min = audit_log.min_available_seq
|
|
80
|
-
return unless min && seq_since < min - 1
|
|
81
|
-
|
|
82
|
-
Failure(code: :cursor_expired, message: "requested seq #{seq_since} is below minimum available #{min}",
|
|
83
|
-
details: { requested: seq_since, min_available: min })
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def self.key_in_lane?(key, lane, manifest)
|
|
87
|
-
mentry = manifest.resolver.resolve(key).entry
|
|
88
|
-
mentry && mentry.lane == lane
|
|
89
|
-
rescue Textus::Error
|
|
90
|
-
false
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
data/lib/textus/action/base.rb
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Textus
|
|
4
|
-
module Action
|
|
5
|
-
@registry = {}
|
|
6
|
-
|
|
7
|
-
def self.registry = @registry
|
|
8
|
-
|
|
9
|
-
def self.register(klass)
|
|
10
|
-
@registry[klass.name.gsub("::", "/").downcase] = klass
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def self.fetch(type)
|
|
14
|
-
return @registry[type] if @registry[type]
|
|
15
|
-
|
|
16
|
-
match = @registry.values.find { |k| k.const_defined?(:TYPE, false) && type == k::TYPE }
|
|
17
|
-
raise Textus::UsageError.new("unknown action type: #{type}") unless match
|
|
18
|
-
|
|
19
|
-
@registry[type] = match
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
class Base
|
|
23
|
-
extend Contract::DSL
|
|
24
|
-
extend Dry::Monads[:result]
|
|
25
|
-
|
|
26
|
-
def self.inherited(subclass)
|
|
27
|
-
super
|
|
28
|
-
Textus::Action.register(subclass) if subclass.name
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def self.call(**)
|
|
32
|
-
raise NotImplementedError.new("#{name}.call")
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def self.proposal_from(env, key:)
|
|
36
|
-
proposal = env.meta&.dig("proposal") or return Failure(code: :proposal_error, message: "entry has no proposal block: #{key}")
|
|
37
|
-
target = proposal["target_key"] or return Failure(code: :proposal_error, message: "proposal missing target_key")
|
|
38
|
-
{ proposal:, target_key: target }
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
data/lib/textus/action/blame.rb
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "open3"
|
|
4
|
-
|
|
5
|
-
module Textus
|
|
6
|
-
module Action
|
|
7
|
-
class Blame < Base
|
|
8
|
-
verb :blame
|
|
9
|
-
summary "Annotate audit rows for a key with the git commit that introduced each file state."
|
|
10
|
-
surfaces :cli
|
|
11
|
-
cli "blame"
|
|
12
|
-
arg :key, String, required: true, positional: true, description: "entry key to blame"
|
|
13
|
-
arg :limit, Integer, required: false, description: "maximum number of audit rows to return"
|
|
14
|
-
view(:cli) { |rows, inputs| { "verb" => "blame", "key" => inputs[:key], "rows" => rows } }
|
|
15
|
-
|
|
16
|
-
def self.call(container:, key:, limit: nil, **)
|
|
17
|
-
manifest = container.manifest
|
|
18
|
-
root = container.root
|
|
19
|
-
|
|
20
|
-
audit_result = Textus::Action::Audit.call(container: container, key: key, limit: limit)
|
|
21
|
-
audit_rows = Value::Result.unwrap(audit_result)
|
|
22
|
-
path = resolve_path(key, manifest: manifest)
|
|
23
|
-
return Success(audit_rows.map { |row| row.merge("git" => nil) }) unless git_tracked?(path, root: root)
|
|
24
|
-
|
|
25
|
-
Success(audit_rows.map { |row| row.merge("git" => git_commit_at(path, timestamp: row["ts"], root: root)) })
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def self.resolve_path(key, manifest:)
|
|
29
|
-
res = manifest.resolver.resolve(key)
|
|
30
|
-
mentry = res.entry
|
|
31
|
-
path = res.path
|
|
32
|
-
path || Textus::Key::Path.resolve(manifest.data, mentry)
|
|
33
|
-
rescue Textus::Error
|
|
34
|
-
nil
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def self.git_tracked?(path, root:)
|
|
38
|
-
return false if path.nil?
|
|
39
|
-
return false unless File.exist?(path)
|
|
40
|
-
return false unless git_repo?(root)
|
|
41
|
-
|
|
42
|
-
_out, _err, status = Open3.capture3(
|
|
43
|
-
"git", "ls-files", "--error-unmatch", path,
|
|
44
|
-
chdir: root
|
|
45
|
-
)
|
|
46
|
-
status.success?
|
|
47
|
-
rescue Errno::ENOENT
|
|
48
|
-
false
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def self.git_repo?(root)
|
|
52
|
-
dir = root
|
|
53
|
-
loop do
|
|
54
|
-
return true if File.directory?(File.join(dir, ".git"))
|
|
55
|
-
|
|
56
|
-
parent = File.dirname(dir)
|
|
57
|
-
return false if parent == dir
|
|
58
|
-
|
|
59
|
-
dir = parent
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def self.git_commit_at(path, timestamp:, root:)
|
|
64
|
-
args = ["git", "log", "-1"]
|
|
65
|
-
args << "--before=#{timestamp}" if timestamp
|
|
66
|
-
args += ["--format=%H%x09%an%x09%aI%x09%s", "--", path]
|
|
67
|
-
out, _err, status = Open3.capture3(*args, chdir: root)
|
|
68
|
-
return nil unless status.success?
|
|
69
|
-
|
|
70
|
-
sha, author, date, subject = out.strip.split("\t", 4)
|
|
71
|
-
return nil if sha.nil? || sha.empty?
|
|
72
|
-
|
|
73
|
-
{ "sha" => sha, "author" => author, "date" => date, "subject" => subject }
|
|
74
|
-
rescue Errno::ENOENT
|
|
75
|
-
nil
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
data/lib/textus/action/boot.rb
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Textus
|
|
4
|
-
module Action
|
|
5
|
-
class Boot < Base
|
|
6
|
-
verb :boot
|
|
7
|
-
summary "Return the orientation contract: lanes, agent_quickstart, agent_protocol, and pre-computed artifacts."
|
|
8
|
-
surfaces :cli, :mcp
|
|
9
|
-
|
|
10
|
-
def self.call(container:, **)
|
|
11
|
-
Success(Textus::Boot.build(container: container))
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "yaml"
|
|
4
|
-
|
|
5
|
-
module Textus
|
|
6
|
-
module Action
|
|
7
|
-
class DataMv < Base
|
|
8
|
-
verb :data_mv
|
|
9
|
-
summary "Rename a data lane — manifest + files. Refuses if destination exists."
|
|
10
|
-
surfaces :cli, :mcp
|
|
11
|
-
cli "data mv"
|
|
12
|
-
arg :from, String, required: true, positional: true, description: "current data lane name"
|
|
13
|
-
arg :to, String, required: true, positional: true,
|
|
14
|
-
description: "new data lane name; refused if a lane by this name already exists"
|
|
15
|
-
arg :dry_run, :boolean, default: false,
|
|
16
|
-
description: "when true, returns the planned zone move without applying it; " \
|
|
17
|
-
"defaults to false, so omitting it applies the move immediately"
|
|
18
|
-
view { |v, _i| v.to_h }
|
|
19
|
-
|
|
20
|
-
def self.call(container:, call:, from:, to:, dry_run: false, **) # rubocop:disable Lint/UnusedMethodArgument
|
|
21
|
-
manifest = container.manifest
|
|
22
|
-
geom = container.geometry
|
|
23
|
-
|
|
24
|
-
return Failure(code: :usage_error, message: "from and to required") if from.nil? || to.nil? || from.empty? || to.empty?
|
|
25
|
-
return Failure(code: :usage_error, message: "data lane '#{from}' not declared") unless manifest.data.declared_lane_kinds.key?(from)
|
|
26
|
-
|
|
27
|
-
dest_dir = geom.lane_path(to)
|
|
28
|
-
return Failure(code: :usage_error, message: "destination 'data/#{to}' already exists") if File.exist?(dest_dir)
|
|
29
|
-
|
|
30
|
-
affected_keys = manifest.data.entries.select { |entry| entry.lane == from }.map(&:key)
|
|
31
|
-
|
|
32
|
-
steps = [{ "op" => "rename_zone", "from" => from, "to" => to }]
|
|
33
|
-
steps += affected_keys.map do |key|
|
|
34
|
-
{ "op" => "mv", "from" => key, "to" => "#{to}#{key[from.length..]}" }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
plan = Textus::Store::Jobs::Plan.new(steps: steps, warnings: [])
|
|
38
|
-
return Success(plan) if dry_run
|
|
39
|
-
|
|
40
|
-
rewrite_manifest!(geom, from:, to:)
|
|
41
|
-
FileUtils.mv(geom.lane_path(from), dest_dir)
|
|
42
|
-
Success(plan)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def self.rewrite_manifest!(geom, from:, to:)
|
|
46
|
-
path = geom.manifest_path
|
|
47
|
-
raw = YAML.safe_load_file(path, permitted_classes: [Symbol], aliases: false)
|
|
48
|
-
raw["lanes"].each { |lane| lane["name"] = to if lane["name"] == from }
|
|
49
|
-
raw["entries"].each do |entry|
|
|
50
|
-
entry["lane"] = to if entry["lane"] == from
|
|
51
|
-
entry["key"] = entry["key"].sub(/\A#{Regexp.escape(from)}(\.|\z)/, "#{to}\\1")
|
|
52
|
-
entry["path"] = entry["path"].sub(%r{\A(data/)?#{Regexp.escape(from)}(/|\z)}, "\\1#{to}\\2")
|
|
53
|
-
end
|
|
54
|
-
File.write(path, YAML.dump(raw))
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
data/lib/textus/action/deps.rb
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Textus
|
|
4
|
-
module Action
|
|
5
|
-
class Deps < Base
|
|
6
|
-
verb :deps
|
|
7
|
-
summary "List the keys a derived entry depends on (its projection/external sources)."
|
|
8
|
-
surfaces :cli, :mcp
|
|
9
|
-
arg :key, String, required: true, positional: true,
|
|
10
|
-
description: "dotted key of the derived entry whose source keys you want"
|
|
11
|
-
|
|
12
|
-
def self.call(container:, key:, **)
|
|
13
|
-
entry = container.manifest.data.entries.find { |e| e.key == key }
|
|
14
|
-
deps = entry&.external? ? Array(entry.source&.sources).compact : []
|
|
15
|
-
Success({ "key" => key, "deps" => deps.uniq })
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
data/lib/textus/action/doctor.rb
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Textus
|
|
4
|
-
module Action
|
|
5
|
-
class Doctor < Base
|
|
6
|
-
verb :doctor
|
|
7
|
-
summary "Run health checks on the textus store and report any issues."
|
|
8
|
-
surfaces :cli
|
|
9
|
-
cli "doctor"
|
|
10
|
-
arg :checks, Array, required: false, description: "subset of check names to run (default: all)"
|
|
11
|
-
|
|
12
|
-
def self.call(container:, call:, checks: nil, **)
|
|
13
|
-
Success(Textus::Doctor.build(container: container, checks: checks, role: call.role))
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
data/lib/textus/action/drain.rb
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Textus
|
|
4
|
-
module Action
|
|
5
|
-
class Drain < Base
|
|
6
|
-
verb :drain
|
|
7
|
-
summary "Seed materialize + sweep jobs then drain the queue to empty. " \
|
|
8
|
-
"Identical to one Watcher tick. Use when no watcher is running."
|
|
9
|
-
surfaces :cli, :mcp
|
|
10
|
-
arg :prefix, String, description: "restrict to keys under this dotted prefix"
|
|
11
|
-
arg :lane, String, description: "restrict to entries in this lane"
|
|
12
|
-
|
|
13
|
-
def self.call(container:, call:, prefix: nil, lane: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
14
|
-
queue = Textus::Store::Jobs::Queue.new(store: container.job_store)
|
|
15
|
-
Textus::Store::Jobs::Planner.seed(
|
|
16
|
-
container: container,
|
|
17
|
-
queue: queue,
|
|
18
|
-
role: call.role,
|
|
19
|
-
)
|
|
20
|
-
queue.reclaim(now: Textus::Port::Clock.new.now)
|
|
21
|
-
summary = Textus::Store::Jobs::Worker.for(container:, queue:).drain
|
|
22
|
-
Success({
|
|
23
|
-
"protocol" => Textus::PROTOCOL,
|
|
24
|
-
"ok" => summary.failed.zero?,
|
|
25
|
-
"completed" => summary.completed,
|
|
26
|
-
"failed" => summary.failed,
|
|
27
|
-
})
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|