@latysh-development/monolith 0.0.0-stage → 0.1.0-alpha.0
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.
- package/LICENSE +21 -0
- package/README.md +132 -2
- package/dist/brief/cli.d.ts +30 -0
- package/dist/brief/cli.d.ts.map +1 -0
- package/dist/brief/cli.js +85 -0
- package/dist/brief/collect.d.ts +17 -0
- package/dist/brief/collect.d.ts.map +1 -0
- package/dist/brief/collect.js +302 -0
- package/dist/brief/config.d.ts +40 -0
- package/dist/brief/config.d.ts.map +1 -0
- package/dist/brief/config.js +85 -0
- package/dist/brief/constants.d.ts +10 -0
- package/dist/brief/constants.d.ts.map +1 -0
- package/dist/brief/constants.js +9 -0
- package/dist/brief/docs.d.ts +53 -0
- package/dist/brief/docs.d.ts.map +1 -0
- package/dist/brief/docs.js +229 -0
- package/dist/brief/freshness.d.ts +104 -0
- package/dist/brief/freshness.d.ts.map +1 -0
- package/dist/brief/freshness.js +263 -0
- package/dist/brief/git-signals.d.ts +17 -0
- package/dist/brief/git-signals.d.ts.map +1 -0
- package/dist/brief/git-signals.js +101 -0
- package/dist/brief/index.d.ts +11 -0
- package/dist/brief/index.d.ts.map +1 -0
- package/dist/brief/index.js +5 -0
- package/dist/brief/reconcile.d.ts +75 -0
- package/dist/brief/reconcile.d.ts.map +1 -0
- package/dist/brief/reconcile.js +259 -0
- package/dist/brief/render.d.ts +60 -0
- package/dist/brief/render.d.ts.map +1 -0
- package/dist/brief/render.js +407 -0
- package/dist/brief/sanitize.d.ts +38 -0
- package/dist/brief/sanitize.d.ts.map +1 -0
- package/dist/brief/sanitize.js +48 -0
- package/dist/brief/selectors.d.ts +36 -0
- package/dist/brief/selectors.d.ts.map +1 -0
- package/dist/brief/selectors.js +75 -0
- package/dist/brief/story.d.ts +18 -0
- package/dist/brief/story.d.ts.map +1 -0
- package/dist/brief/story.js +59 -0
- package/dist/brief/types.d.ts +110 -0
- package/dist/brief/types.d.ts.map +1 -0
- package/dist/brief/types.js +11 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +166 -0
- package/dist/cli/init-args.d.ts +16 -0
- package/dist/cli/init-args.d.ts.map +1 -0
- package/dist/cli/init-args.js +24 -0
- package/dist/cli/ui-args.d.ts +23 -0
- package/dist/cli/ui-args.d.ts.map +1 -0
- package/dist/cli/ui-args.js +66 -0
- package/dist/cli/ui.d.ts +40 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +180 -0
- package/dist/coordinatorium/checkpoint.d.ts +44 -0
- package/dist/coordinatorium/checkpoint.d.ts.map +1 -0
- package/dist/coordinatorium/checkpoint.js +124 -0
- package/dist/coordinatorium/cli.d.ts +39 -0
- package/dist/coordinatorium/cli.d.ts.map +1 -0
- package/dist/coordinatorium/cli.js +203 -0
- package/dist/coordinatorium/errors.d.ts +112 -0
- package/dist/coordinatorium/errors.d.ts.map +1 -0
- package/dist/coordinatorium/errors.js +145 -0
- package/dist/coordinatorium/index.d.ts +11 -0
- package/dist/coordinatorium/index.d.ts.map +1 -0
- package/dist/coordinatorium/index.js +5 -0
- package/dist/coordinatorium/lock.d.ts +187 -0
- package/dist/coordinatorium/lock.d.ts.map +1 -0
- package/dist/coordinatorium/lock.js +659 -0
- package/dist/coordinatorium/mission.d.ts +32 -0
- package/dist/coordinatorium/mission.d.ts.map +1 -0
- package/dist/coordinatorium/mission.js +87 -0
- package/dist/coordinatorium/state-keeper.d.ts +115 -0
- package/dist/coordinatorium/state-keeper.d.ts.map +1 -0
- package/dist/coordinatorium/state-keeper.js +396 -0
- package/dist/coordinatorium/types.d.ts +69 -0
- package/dist/coordinatorium/types.d.ts.map +1 -0
- package/dist/coordinatorium/types.js +27 -0
- package/dist/durable/assess.d.ts +105 -0
- package/dist/durable/assess.d.ts.map +1 -0
- package/dist/durable/assess.js +239 -0
- package/dist/durable/canonical.d.ts +25 -0
- package/dist/durable/canonical.d.ts.map +1 -0
- package/dist/durable/canonical.js +78 -0
- package/dist/durable/cli.d.ts +37 -0
- package/dist/durable/cli.d.ts.map +1 -0
- package/dist/durable/cli.js +141 -0
- package/dist/durable/errors.d.ts +188 -0
- package/dist/durable/errors.d.ts.map +1 -0
- package/dist/durable/errors.js +317 -0
- package/dist/durable/fs-store.d.ts +233 -0
- package/dist/durable/fs-store.d.ts.map +1 -0
- package/dist/durable/fs-store.js +1393 -0
- package/dist/durable/index.d.ts +20 -0
- package/dist/durable/index.d.ts.map +1 -0
- package/dist/durable/index.js +13 -0
- package/dist/durable/log.d.ts +33 -0
- package/dist/durable/log.d.ts.map +1 -0
- package/dist/durable/log.js +157 -0
- package/dist/durable/memory-store.d.ts +51 -0
- package/dist/durable/memory-store.d.ts.map +1 -0
- package/dist/durable/memory-store.js +302 -0
- package/dist/durable/projection.d.ts +35 -0
- package/dist/durable/projection.d.ts.map +1 -0
- package/dist/durable/projection.js +328 -0
- package/dist/durable/prune-check.d.ts +17 -0
- package/dist/durable/prune-check.d.ts.map +1 -0
- package/dist/durable/prune-check.js +45 -0
- package/dist/durable/register.d.ts +100 -0
- package/dist/durable/register.d.ts.map +1 -0
- package/dist/durable/register.js +532 -0
- package/dist/durable/retention.d.ts +49 -0
- package/dist/durable/retention.d.ts.map +1 -0
- package/dist/durable/retention.js +59 -0
- package/dist/durable/runtime.d.ts +497 -0
- package/dist/durable/runtime.d.ts.map +1 -0
- package/dist/durable/runtime.js +1271 -0
- package/dist/durable/seams.d.ts +40 -0
- package/dist/durable/seams.d.ts.map +1 -0
- package/dist/durable/seams.js +21 -0
- package/dist/durable/testing.d.ts +11 -0
- package/dist/durable/testing.d.ts.map +1 -0
- package/dist/durable/testing.js +25 -0
- package/dist/durable/types.d.ts +442 -0
- package/dist/durable/types.d.ts.map +1 -0
- package/dist/durable/types.js +75 -0
- package/dist/graph/builder.d.ts +11 -0
- package/dist/graph/builder.d.ts.map +1 -0
- package/dist/graph/builder.js +153 -0
- package/dist/graph/identity.d.ts +37 -0
- package/dist/graph/identity.d.ts.map +1 -0
- package/dist/graph/identity.js +46 -0
- package/dist/graph/index.d.ts +7 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +3 -0
- package/dist/graph/resolver.d.ts +41 -0
- package/dist/graph/resolver.d.ts.map +1 -0
- package/dist/graph/resolver.js +36 -0
- package/dist/graph/types.d.ts +42 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +1 -0
- package/dist/http/index.d.ts +5 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +2 -0
- package/dist/http/server.d.ts +76 -0
- package/dist/http/server.d.ts.map +1 -0
- package/dist/http/server.js +195 -0
- package/dist/http/ui-assets.d.ts +22 -0
- package/dist/http/ui-assets.d.ts.map +1 -0
- package/dist/http/ui-assets.js +100 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/init/index.d.ts +12 -0
- package/dist/init/index.d.ts.map +1 -0
- package/dist/init/index.js +90 -0
- package/dist/init/prompts.d.ts +3 -0
- package/dist/init/prompts.d.ts.map +1 -0
- package/dist/init/prompts.js +47 -0
- package/dist/init/scaffold.d.ts +25 -0
- package/dist/init/scaffold.d.ts.map +1 -0
- package/dist/init/scaffold.js +204 -0
- package/dist/init/types.d.ts +14 -0
- package/dist/init/types.d.ts.map +1 -0
- package/dist/init/types.js +1 -0
- package/dist/readmodel/dashboard.d.ts +40 -0
- package/dist/readmodel/dashboard.d.ts.map +1 -0
- package/dist/readmodel/dashboard.js +236 -0
- package/dist/readmodel/index.d.ts +3 -0
- package/dist/readmodel/index.d.ts.map +1 -0
- package/dist/readmodel/index.js +1 -0
- package/dist/readmodel/types.d.ts +104 -0
- package/dist/readmodel/types.d.ts.map +1 -0
- package/dist/readmodel/types.js +15 -0
- package/dist/root/index.d.ts +179 -0
- package/dist/root/index.d.ts.map +1 -0
- package/dist/root/index.js +418 -0
- package/dist/root/safe-write.d.ts +268 -0
- package/dist/root/safe-write.d.ts.map +1 -0
- package/dist/root/safe-write.js +966 -0
- package/dist/root/write-artifacts.d.ts +20 -0
- package/dist/root/write-artifacts.d.ts.map +1 -0
- package/dist/root/write-artifacts.js +42 -0
- package/dist/scriptorium/compile.d.ts +4 -0
- package/dist/scriptorium/compile.d.ts.map +1 -0
- package/dist/scriptorium/compile.js +185 -0
- package/dist/scriptorium/frontmatter.d.ts +13 -0
- package/dist/scriptorium/frontmatter.d.ts.map +1 -0
- package/dist/scriptorium/frontmatter.js +90 -0
- package/dist/scriptorium/index.d.ts +3 -0
- package/dist/scriptorium/index.d.ts.map +1 -0
- package/dist/scriptorium/index.js +1 -0
- package/dist/scriptorium/markdown.d.ts +31 -0
- package/dist/scriptorium/markdown.d.ts.map +1 -0
- package/dist/scriptorium/markdown.js +88 -0
- package/dist/scriptorium/types.d.ts +78 -0
- package/dist/scriptorium/types.d.ts.map +1 -0
- package/dist/scriptorium/types.js +1 -0
- package/dist/types/enforcement.d.ts +11 -0
- package/dist/types/enforcement.d.ts.map +1 -0
- package/dist/types/enforcement.js +1 -0
- package/dist/types/integrity.d.ts +33 -0
- package/dist/types/integrity.d.ts.map +1 -0
- package/dist/types/integrity.js +1 -0
- package/dist/types/project-definition.d.ts +30 -0
- package/dist/types/project-definition.d.ts.map +1 -0
- package/dist/types/project-definition.js +1 -0
- package/dist/ui/assets/cosmic-glass-bg-Dwx47zPu.webp +0 -0
- package/dist/ui/assets/index-C4NhMaq7.js +28 -0
- package/dist/ui/assets/index-DMZ7ZvZY.css +1 -0
- package/dist/ui/index.html +13 -0
- package/dist/validate/index.d.ts +6 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +214 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +1 -0
- package/package.json +67 -4
- package/templates/.gitkeep +0 -0
- package/templates/default-instance/instruction/.cursorrules +53 -0
- package/templates/default-instance/instruction/.windsurfrules +53 -0
- package/templates/default-instance/instruction/CLAUDE.md +53 -0
- package/templates/default-instance/monolith/context/boot/HANDOFF.md +49 -0
- package/templates/default-instance/monolith/context/boot/WORK_SESSION.md +30 -0
- package/templates/default-instance/monolith/context/execution/current-state.md +30 -0
- package/templates/default-instance/monolith/context/maps/dependency-map.md +38 -0
- package/templates/default-instance/monolith/context/maps/project-map.md +85 -0
- package/templates/default-instance/monolith/context/maps/roadmap-index.md +41 -0
- package/templates/default-instance/monolith/context/maps/routing-map.md +147 -0
- package/templates/default-instance/monolith/context/maps/semantic-map.md +73 -0
- package/templates/default-instance/monolith/context/models/model-registry.md +37 -0
- package/templates/default-instance/monolith/context/models/privacy-classification.md +35 -0
- package/templates/default-instance/monolith/context/templates/plan-template.md +56 -0
- package/templates/default-instance/monolith/governance/README.md +29 -0
- package/templates/default-instance/monolith/governance/RULE_SCHEMA.md +58 -0
- package/templates/default-instance/monolith/learning/INDEX.md +48 -0
- package/templates/default-instance/monolith/learning/injection-map.md +49 -0
- package/templates/default-instance/monolith/learning/taxonomy.md +30 -0
- package/templates/default-instance/monolith/memory/errors/README.md +26 -0
- package/templates/default-instance/monolith/memory/errors/SCHEMA.md +47 -0
- package/templates/default-instance/monolith/memory/errors/TAXONOMY.md +27 -0
- package/templates/default-instance/monolith/memory/long-term/architecture-principles.md +31 -0
- package/templates/default-instance/monolith/memory/long-term/decisions.md +36 -0
- package/templates/default-instance/monolith/memory/long-term/execution-history.md +20 -0
- package/templates/default-instance/monolith/memory/long-term/tech-debt.md +25 -0
- package/templates/default-instance/monolith/memory/working/active.md +41 -0
- package/templates/default-instance/monolith/memory/working/governance-result.md +0 -0
- package/templates/default-instance/monolith/memory/working/integrity-result.md +0 -0
- package/templates/default-instance/monolith/memory/working/story-index.md +28 -0
- package/templates/default-instance/monolith/protocols/boot/boot-sequence.md +59 -0
- package/templates/default-instance/monolith/protocols/cognition/cognitive-modes.md +90 -0
- package/templates/default-instance/monolith/protocols/cognition/dry-run.md +56 -0
- package/templates/default-instance/monolith/protocols/cognition/execution-trace-format.md +52 -0
- package/templates/default-instance/monolith/protocols/cognition/semantic-planning.md +51 -0
- package/templates/default-instance/monolith/protocols/execution/hybrid-execution.md +37 -0
- package/templates/default-instance/monolith/protocols/execution/local-llm-governance.md +42 -0
- package/templates/default-instance/monolith/protocols/governance/command-policy.md +51 -0
- package/templates/default-instance/monolith/protocols/governance/core-invariants.md +40 -0
- package/templates/default-instance/monolith/protocols/governance/memory-governance.md +54 -0
- package/templates/default-instance/monolith/protocols/governance/metadata-schema.md +62 -0
- package/templates/default-instance/monolith/protocols/governance/skills.md +53 -0
- package/templates/default-instance/monolith/protocols/governance/work-session.md +46 -0
- package/templates/default-instance/monolith/skills/INDEX.md +28 -0
- package/templates/default-instance/monolith/skills/current-status/SKILL.md +47 -0
- package/templates/default-instance/monolith/skills/finalize-story/SKILL.md +86 -0
- package/templates/default-instance/monolith/skills/global-status/SKILL.md +56 -0
- package/templates/default-instance/monolith/skills/self-improvement/SKILL.md +77 -0
- package/templates/default-instance/monolith/state.json +11 -0
- package/templates/default-instance/monolith/tests/INDEX.md +57 -0
- package/templates/default-instance/monolith/tests/scenarios/architecture-review.md +32 -0
- package/templates/default-instance/monolith/tests/scenarios/debug-failure.md +32 -0
- package/templates/default-instance/monolith/tests/scenarios/dry-run-activation.md +33 -0
- package/templates/default-instance/monolith/tests/scenarios/execution-trace-verification.md +31 -0
- package/templates/default-instance/monolith/tests/scenarios/finalize-story.md +35 -0
- package/templates/default-instance/monolith/tests/scenarios/implement-feature.md +36 -0
- package/templates/default-instance/monolith/tests/scenarios/local-llm-delegation.md +31 -0
- package/templates/default-instance/monolith/tests/scenarios/planning-request.md +32 -0
- package/templates/default-instance/monolith/tests/scenarios/sensitive-context-task.md +30 -0
- package/templates/default-instance/monolith/tests/scenarios/validator-verification.md +33 -0
- package/templates/default-instance/monolith/tests/validation/expected-behavior.md +70 -0
- package/templates/default-instance/monolith/tests/validators/INDEX.md +17 -0
- package/templates/default-instance/monolith/tests/validators/delegation-semantics.md +22 -0
- package/templates/default-instance/monolith/tests/validators/mode-consistency.md +25 -0
- package/templates/default-instance/monolith/tests/validators/privacy-routing.md +23 -0
- package/templates/default-instance/monolith/tests/validators/protocol-references.md +27 -0
- package/templates/default-instance/monolith/tests/validators/routing-integrity.md +30 -0
- package/templates/default-instance/projectroot/AGENTS.md +107 -0
- package/templates/default-instance/projectroot/monolith.config.json +32 -0
- package/templates/default-instance/projectroot/project.definition.mjs.template +41 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projection — the pure fold from events to `TaskState`.
|
|
3
|
+
*
|
|
4
|
+
* Deterministic and total over valid logs: the same events always give the
|
|
5
|
+
* same state, with no clock, randomness or I/O. It is also *strict*: an event
|
|
6
|
+
* that violates the task's own rules (a second claim with the wrong epoch, a
|
|
7
|
+
* delivery to an unknown await, an event after a terminal one) is a corrupt
|
|
8
|
+
* log, not something to be skipped. Writers run every new event through
|
|
9
|
+
* `applyEvent` before publishing it, so a log that was written by this code
|
|
10
|
+
* always folds.
|
|
11
|
+
*/
|
|
12
|
+
import { LogCorruptError } from './errors.js';
|
|
13
|
+
import { GENESIS_HASH } from './types.js';
|
|
14
|
+
/** Idempotency keys are scoped to the await they were delivered to ('awaitId' never contains ':'). */
|
|
15
|
+
export function deliveryKey(awaitId, idempotencyKey) {
|
|
16
|
+
return `${awaitId}:${idempotencyKey}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A string-keyed dictionary that does not inherit from `Object.prototype`.
|
|
20
|
+
*
|
|
21
|
+
* Keys of these dictionaries are application data (assumption keys, effect keys, await ids, labels).
|
|
22
|
+
* On a plain object `d['__proto__'] = x` replaces the prototype instead of storing an entry, and
|
|
23
|
+
* `d['constructor']` / `d['toString']` read an inherited function for a key that was never written.
|
|
24
|
+
* A null-prototype object has neither problem; it serializes exactly like a plain one (JSON, canonical
|
|
25
|
+
* form, `Object.keys/values/entries`), so stored events and the public `Record<string, T>` types are unchanged.
|
|
26
|
+
*/
|
|
27
|
+
export function newDict(from) {
|
|
28
|
+
const out = Object.create(null);
|
|
29
|
+
if (from) {
|
|
30
|
+
// defineProperty, not assignment: an own "__proto__" key of `from` must stay an entry.
|
|
31
|
+
for (const k of Object.keys(from))
|
|
32
|
+
Object.defineProperty(out, k, { value: from[k], enumerable: true, writable: true, configurable: true });
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
function corrupt(taskId, seq, reason) {
|
|
37
|
+
throw new LogCorruptError(taskId, seq, reason);
|
|
38
|
+
}
|
|
39
|
+
/** Validates a plan declaration; returns the first problem or `null`. Shared by the runtime (nice errors) and the fold (strictness). */
|
|
40
|
+
export function planProblem(steps) {
|
|
41
|
+
const ids = new Set();
|
|
42
|
+
for (const s of steps) {
|
|
43
|
+
if (ids.has(s.id))
|
|
44
|
+
return `duplicate step id "${s.id}"`;
|
|
45
|
+
ids.add(s.id);
|
|
46
|
+
}
|
|
47
|
+
for (const s of steps) {
|
|
48
|
+
for (const d of s.dependsOn) {
|
|
49
|
+
if (!ids.has(d))
|
|
50
|
+
return `step "${s.id}" depends on unknown step "${d}"`;
|
|
51
|
+
if (d === s.id)
|
|
52
|
+
return `step "${s.id}" depends on itself`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// cycle detection (Kahn)
|
|
56
|
+
const indeg = new Map(steps.map((s) => [s.id, s.dependsOn.length]));
|
|
57
|
+
const queue = steps.filter((s) => s.dependsOn.length === 0).map((s) => s.id);
|
|
58
|
+
let visited = 0;
|
|
59
|
+
while (queue.length > 0) {
|
|
60
|
+
const id = queue.pop();
|
|
61
|
+
visited++;
|
|
62
|
+
for (const s of steps) {
|
|
63
|
+
if (s.dependsOn.includes(id)) {
|
|
64
|
+
const n = indeg.get(s.id) - 1;
|
|
65
|
+
indeg.set(s.id, n);
|
|
66
|
+
if (n === 0)
|
|
67
|
+
queue.push(s.id);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return visited === steps.length ? null : 'the plan has a dependency cycle';
|
|
72
|
+
}
|
|
73
|
+
export function applyEvent(prevState, e) {
|
|
74
|
+
const t = e.taskId;
|
|
75
|
+
if (prevState === null) {
|
|
76
|
+
if (e.seq !== 1 || e.type !== 'task.created')
|
|
77
|
+
corrupt(t, e.seq, 'a log must start with task.created at seq 1');
|
|
78
|
+
const d = e.data;
|
|
79
|
+
return {
|
|
80
|
+
taskId: t,
|
|
81
|
+
kind: d.kind,
|
|
82
|
+
goal: d.goal,
|
|
83
|
+
input: d.input,
|
|
84
|
+
parentTaskId: d.parentTaskId,
|
|
85
|
+
dependsOn: [...d.dependsOn],
|
|
86
|
+
labels: newDict(d.labels),
|
|
87
|
+
status: 'active',
|
|
88
|
+
createdAt: e.at,
|
|
89
|
+
updatedAt: e.at,
|
|
90
|
+
closedAt: null,
|
|
91
|
+
result: null,
|
|
92
|
+
error: null,
|
|
93
|
+
headSeq: 1,
|
|
94
|
+
headHash: e.hash,
|
|
95
|
+
epoch: 0,
|
|
96
|
+
lease: null,
|
|
97
|
+
plan: null,
|
|
98
|
+
decisions: [],
|
|
99
|
+
assumptions: newDict(),
|
|
100
|
+
observations: newDict(),
|
|
101
|
+
effects: newDict(),
|
|
102
|
+
awaits: newDict(),
|
|
103
|
+
deliveryKeys: newDict(),
|
|
104
|
+
eventCount: 1,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const s = prevState;
|
|
108
|
+
if (e.seq !== s.headSeq + 1)
|
|
109
|
+
corrupt(t, e.seq, `sequence gap (expected ${s.headSeq + 1})`);
|
|
110
|
+
if (s.status !== 'active')
|
|
111
|
+
corrupt(t, e.seq, `event after the terminal state (${s.status})`);
|
|
112
|
+
switch (e.type) {
|
|
113
|
+
case 'task.created':
|
|
114
|
+
return corrupt(t, e.seq, 'task.created after seq 1');
|
|
115
|
+
case 'run.claimed': {
|
|
116
|
+
const d = e.data;
|
|
117
|
+
if (d.epoch !== s.epoch + 1)
|
|
118
|
+
corrupt(t, e.seq, `claim epoch ${d.epoch} is not ${s.epoch + 1}`);
|
|
119
|
+
s.epoch = d.epoch;
|
|
120
|
+
s.lease = { owner: d.owner, epoch: d.epoch, leaseUntil: d.leaseUntil, released: false };
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case 'run.heartbeat': {
|
|
124
|
+
const d = e.data;
|
|
125
|
+
if (!s.lease || s.lease.released || s.lease.epoch !== d.epoch || s.lease.owner !== d.owner) {
|
|
126
|
+
corrupt(t, e.seq, 'heartbeat from a non-current lease holder');
|
|
127
|
+
}
|
|
128
|
+
s.lease.leaseUntil = d.leaseUntil;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case 'run.released': {
|
|
132
|
+
const d = e.data;
|
|
133
|
+
if (!s.lease || s.lease.released || s.lease.epoch !== d.epoch || s.lease.owner !== d.owner) {
|
|
134
|
+
corrupt(t, e.seq, 'release from a non-current lease holder');
|
|
135
|
+
}
|
|
136
|
+
s.lease.released = true;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case 'plan.declared': {
|
|
140
|
+
const problem = planProblem(e.data.steps);
|
|
141
|
+
if (problem)
|
|
142
|
+
corrupt(t, e.seq, `invalid plan: ${problem}`);
|
|
143
|
+
const previous = new Map((s.plan ?? []).map((p) => [p.id, p]));
|
|
144
|
+
s.plan = e.data.steps.map((decl) => {
|
|
145
|
+
const old = previous.get(decl.id);
|
|
146
|
+
// A re-plan never reopens work that is already closed.
|
|
147
|
+
if (old && old.status !== 'pending')
|
|
148
|
+
return { ...old, title: decl.title, dependsOn: [...decl.dependsOn] };
|
|
149
|
+
return { id: decl.id, title: decl.title, dependsOn: [...decl.dependsOn], status: 'pending', result: null, skipReason: null, closedAtSeq: null };
|
|
150
|
+
});
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case 'plan.step_done':
|
|
154
|
+
case 'plan.step_skipped': {
|
|
155
|
+
const step = s.plan?.find((p) => p.id === e.data.stepId);
|
|
156
|
+
if (!step)
|
|
157
|
+
corrupt(t, e.seq, `unknown plan step "${e.data.stepId}"`);
|
|
158
|
+
if (step.status !== 'pending')
|
|
159
|
+
corrupt(t, e.seq, `plan step "${step.id}" is already ${step.status}`);
|
|
160
|
+
if (e.type === 'plan.step_done') {
|
|
161
|
+
step.status = 'done';
|
|
162
|
+
step.result = e.data.result;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
step.status = 'skipped';
|
|
166
|
+
step.skipReason = e.data.reason;
|
|
167
|
+
}
|
|
168
|
+
step.closedAtSeq = e.seq;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case 'decision.recorded': {
|
|
172
|
+
if (s.decisions.some((x) => x.id === e.data.id))
|
|
173
|
+
corrupt(t, e.seq, `duplicate decision id "${e.data.id}"`);
|
|
174
|
+
s.decisions.push({ id: e.data.id, seq: e.seq, at: e.at, summary: e.data.summary, rationale: e.data.rationale, basedOn: [...e.data.basedOn] });
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case 'assumption.recorded': {
|
|
178
|
+
const d = e.data;
|
|
179
|
+
s.assumptions[d.key] = {
|
|
180
|
+
key: d.key, statement: d.statement, criticality: d.criticality, fingerprint: d.fingerprint, value: d.value,
|
|
181
|
+
evidence: d.evidence.map((x) => ({ ...x })), status: 'active', recordedAtSeq: e.seq, retractedReason: null,
|
|
182
|
+
};
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case 'assumption.retracted': {
|
|
186
|
+
const a = s.assumptions[e.data.key];
|
|
187
|
+
if (!a || a.status !== 'active')
|
|
188
|
+
corrupt(t, e.seq, `no active assumption "${e.data.key}"`);
|
|
189
|
+
a.status = 'retracted';
|
|
190
|
+
a.retractedReason = e.data.reason;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case 'fact.observed': {
|
|
194
|
+
const d = e.data;
|
|
195
|
+
s.observations[d.key] = { key: d.key, fingerprint: d.fingerprint, value: d.value, source: d.source, seq: e.seq, at: e.at };
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case 'effect.intended': {
|
|
199
|
+
const d = e.data;
|
|
200
|
+
const old = s.effects[d.key];
|
|
201
|
+
if (old && old.status === 'completed')
|
|
202
|
+
corrupt(t, e.seq, `effect "${d.key}" is already completed`);
|
|
203
|
+
s.effects[d.key] = {
|
|
204
|
+
key: d.key, description: d.description, params: d.params, status: 'intended', intendedAtSeq: e.seq,
|
|
205
|
+
intendedEpoch: d.epoch, result: null, error: null, retryable: true, uncertain: false,
|
|
206
|
+
};
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case 'effect.completed': {
|
|
210
|
+
const x = s.effects[e.data.key];
|
|
211
|
+
if (!x || x.status === 'completed')
|
|
212
|
+
corrupt(t, e.seq, `effect "${e.data.key}" cannot be completed from ${x ? x.status : 'nothing'}`);
|
|
213
|
+
x.status = 'completed';
|
|
214
|
+
x.result = e.data.result;
|
|
215
|
+
x.error = null;
|
|
216
|
+
x.uncertain = false;
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
case 'effect.failed': {
|
|
220
|
+
const x = s.effects[e.data.key];
|
|
221
|
+
if (!x || x.status !== 'intended')
|
|
222
|
+
corrupt(t, e.seq, `effect "${e.data.key}" cannot fail from ${x ? x.status : 'nothing'}`);
|
|
223
|
+
x.status = 'failed';
|
|
224
|
+
x.error = e.data.error;
|
|
225
|
+
x.retryable = e.data.retryable;
|
|
226
|
+
x.uncertain = e.data.uncertain === true;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
case 'await.registered': {
|
|
230
|
+
const d = e.data;
|
|
231
|
+
if (s.awaits[d.awaitId])
|
|
232
|
+
corrupt(t, e.seq, `duplicate await id "${d.awaitId}"`);
|
|
233
|
+
if (Object.values(s.awaits).some((a) => a.token === d.token))
|
|
234
|
+
corrupt(t, e.seq, 'duplicate await token');
|
|
235
|
+
s.awaits[d.awaitId] = {
|
|
236
|
+
awaitId: d.awaitId, token: d.token, purpose: d.purpose, stepId: d.stepId, request: d.request, deadlineAt: d.deadlineAt,
|
|
237
|
+
basisSeq: d.basisSeq, registeredAtSeq: e.seq, status: 'pending', resolvedAtSeq: null, payload: null, idempotencyKey: null,
|
|
238
|
+
source: null, late: false, rejectedDeliveries: 0,
|
|
239
|
+
};
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
case 'await.resolved': {
|
|
243
|
+
const d = e.data;
|
|
244
|
+
const a = s.awaits[d.awaitId];
|
|
245
|
+
if (!a)
|
|
246
|
+
corrupt(t, e.seq, `delivery to unknown await "${d.awaitId}"`);
|
|
247
|
+
if (a.status === 'resolved')
|
|
248
|
+
corrupt(t, e.seq, `await "${a.awaitId}" is already resolved`);
|
|
249
|
+
if (a.status === 'expired' && !d.late)
|
|
250
|
+
corrupt(t, e.seq, 'delivery after expiry must be marked late');
|
|
251
|
+
const dk = deliveryKey(d.awaitId, d.idempotencyKey);
|
|
252
|
+
if (dk in s.deliveryKeys)
|
|
253
|
+
corrupt(t, e.seq, 'idempotency key reused');
|
|
254
|
+
a.status = 'resolved';
|
|
255
|
+
a.resolvedAtSeq = e.seq;
|
|
256
|
+
a.payload = d.payload;
|
|
257
|
+
a.idempotencyKey = d.idempotencyKey;
|
|
258
|
+
a.source = d.source;
|
|
259
|
+
a.late = d.late;
|
|
260
|
+
s.deliveryKeys[dk] = e.seq;
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
case 'await.delivery_rejected': {
|
|
264
|
+
const d = e.data;
|
|
265
|
+
const a = s.awaits[d.awaitId];
|
|
266
|
+
if (!a || a.status !== 'resolved')
|
|
267
|
+
corrupt(t, e.seq, 'rejected delivery for an await that is not resolved');
|
|
268
|
+
const dk = deliveryKey(d.awaitId, d.idempotencyKey);
|
|
269
|
+
if (dk in s.deliveryKeys)
|
|
270
|
+
corrupt(t, e.seq, 'idempotency key reused');
|
|
271
|
+
a.rejectedDeliveries++;
|
|
272
|
+
s.deliveryKeys[dk] = e.seq;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case 'await.expired': {
|
|
276
|
+
const a = s.awaits[e.data.awaitId];
|
|
277
|
+
if (!a || a.status !== 'pending')
|
|
278
|
+
corrupt(t, e.seq, `await "${e.data.awaitId}" cannot expire`);
|
|
279
|
+
a.status = 'expired';
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
case 'task.completed':
|
|
283
|
+
s.status = 'completed';
|
|
284
|
+
s.result = e.data.result;
|
|
285
|
+
s.closedAt = e.at;
|
|
286
|
+
break;
|
|
287
|
+
case 'task.failed':
|
|
288
|
+
s.status = 'failed';
|
|
289
|
+
s.error = e.data.error;
|
|
290
|
+
s.closedAt = e.at;
|
|
291
|
+
break;
|
|
292
|
+
case 'task.cancelled':
|
|
293
|
+
s.status = 'cancelled';
|
|
294
|
+
s.error = e.data.reason;
|
|
295
|
+
s.closedAt = e.at;
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
s.headSeq = e.seq;
|
|
299
|
+
s.headHash = e.hash;
|
|
300
|
+
s.updatedAt = e.at;
|
|
301
|
+
s.eventCount++;
|
|
302
|
+
return s;
|
|
303
|
+
}
|
|
304
|
+
/** Folds a verified, contiguous list of events (starting at seq 1, or continuing `from`). */
|
|
305
|
+
export function foldEvents(events, from = null) {
|
|
306
|
+
let state = from;
|
|
307
|
+
for (const e of events)
|
|
308
|
+
state = applyEvent(state, e);
|
|
309
|
+
if (state === null)
|
|
310
|
+
throw new LogCorruptError('?', null, 'empty log');
|
|
311
|
+
return state;
|
|
312
|
+
}
|
|
313
|
+
/** The state as it was when the log had `seq` events — "what did the task look like when this was sent". */
|
|
314
|
+
export function foldUntil(events, seq) {
|
|
315
|
+
return foldEvents(events.filter((e) => e.seq <= seq));
|
|
316
|
+
}
|
|
317
|
+
/** Deep copy. `structuredClone` alone would turn the null-prototype dictionaries back into plain objects. */
|
|
318
|
+
export function cloneState(s) {
|
|
319
|
+
const c = structuredClone(s);
|
|
320
|
+
c.labels = newDict(c.labels);
|
|
321
|
+
c.assumptions = newDict(c.assumptions);
|
|
322
|
+
c.observations = newDict(c.observations);
|
|
323
|
+
c.effects = newDict(c.effects);
|
|
324
|
+
c.awaits = newDict(c.awaits);
|
|
325
|
+
c.deliveryKeys = newDict(c.deliveryKeys);
|
|
326
|
+
return c;
|
|
327
|
+
}
|
|
328
|
+
export { GENESIS_HASH };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preconditions of an irreversible prune, checked against the task's own log. A pure function over verified events: the
|
|
3
|
+
* stores call it AFTER the prune attempt is visible in the register, so that any append that lands later closes the
|
|
4
|
+
* attempt through G2 (ADR-019) instead of being missed by a check-then-act gap.
|
|
5
|
+
*/
|
|
6
|
+
import { type TaskEvent, type TaskState, type Tombstone } from './types.js';
|
|
7
|
+
/** sha256 of the canonical final result/error: what the tombstone keeps instead of the data. */
|
|
8
|
+
export declare function outcomeDigestOf(state: TaskState): string;
|
|
9
|
+
/** The tombstone of a finished task: what remains of it once its data is removed. */
|
|
10
|
+
export declare function tombstoneFor(state: TaskState, prunedAt: string): Tombstone;
|
|
11
|
+
/**
|
|
12
|
+
* Why `tombstone` may not be used to remove the task whose log is `events`, or `null` when it may. Throws
|
|
13
|
+
* `LogCorruptError` when the log itself does not verify (a corrupt task is never pruned). `prunedAt` is the pruner's own
|
|
14
|
+
* clock and is not compared.
|
|
15
|
+
*/
|
|
16
|
+
export declare function tombstoneProblem(taskId: string, events: readonly TaskEvent[], t: Tombstone): string | null;
|
|
17
|
+
//# sourceMappingURL=prune-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune-check.d.ts","sourceRoot":"","sources":["../../src/durable/prune-check.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAExF,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAGxD;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAK1E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAW1G"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preconditions of an irreversible prune, checked against the task's own log. A pure function over verified events: the
|
|
3
|
+
* stores call it AFTER the prune attempt is visible in the register, so that any append that lands later closes the
|
|
4
|
+
* attempt through G2 (ADR-019) instead of being missed by a check-then-act gap.
|
|
5
|
+
*/
|
|
6
|
+
import { canonicalize, sha256Hex } from './canonical.js';
|
|
7
|
+
import { GENESIS_HASH, verifyChain } from './log.js';
|
|
8
|
+
import { foldEvents } from './projection.js';
|
|
9
|
+
import { isTerminal } from './types.js';
|
|
10
|
+
/** sha256 of the canonical final result/error: what the tombstone keeps instead of the data. */
|
|
11
|
+
export function outcomeDigestOf(state) {
|
|
12
|
+
const outcome = state.status === 'completed' ? state.result : { error: state.error };
|
|
13
|
+
return sha256Hex(canonicalize((outcome ?? null)));
|
|
14
|
+
}
|
|
15
|
+
/** The tombstone of a finished task: what remains of it once its data is removed. */
|
|
16
|
+
export function tombstoneFor(state, prunedAt) {
|
|
17
|
+
return {
|
|
18
|
+
v: 1, taskId: state.taskId, kind: state.kind, finalStatus: state.status, createdAt: state.createdAt, closedAt: state.closedAt,
|
|
19
|
+
prunedAt, headSeq: state.headSeq, headHash: state.headHash, outcomeDigest: outcomeDigestOf(state),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Why `tombstone` may not be used to remove the task whose log is `events`, or `null` when it may. Throws
|
|
24
|
+
* `LogCorruptError` when the log itself does not verify (a corrupt task is never pruned). `prunedAt` is the pruner's own
|
|
25
|
+
* clock and is not compared.
|
|
26
|
+
*/
|
|
27
|
+
export function tombstoneProblem(taskId, events, t) {
|
|
28
|
+
if (events.length === 0)
|
|
29
|
+
return 'its log has no readable events';
|
|
30
|
+
verifyChain(taskId, events, 0, GENESIS_HASH);
|
|
31
|
+
const s = foldEvents(events);
|
|
32
|
+
if (!isTerminal(s.status))
|
|
33
|
+
return `the task is ${s.status}, not finished`;
|
|
34
|
+
if (t.headSeq !== s.headSeq)
|
|
35
|
+
return `the tombstone names head ${t.headSeq}, the log ends at ${s.headSeq}`;
|
|
36
|
+
if (t.headHash !== s.headHash)
|
|
37
|
+
return 'the tombstone head hash is not the hash of the last event of the log';
|
|
38
|
+
if (t.finalStatus !== s.status)
|
|
39
|
+
return `the tombstone says "${t.finalStatus}", the task ended "${s.status}"`;
|
|
40
|
+
if (t.kind !== s.kind || t.createdAt !== s.createdAt || t.closedAt !== s.closedAt)
|
|
41
|
+
return 'the tombstone does not describe this task';
|
|
42
|
+
if (t.outcomeDigest !== outcomeDigestOf(s))
|
|
43
|
+
return 'the tombstone outcome digest is not the digest of the final outcome';
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The persisted prune decision register: record formats and the pure derivation of the prune state.
|
|
3
|
+
*
|
|
4
|
+
* Design A (docs/architecture/DURABLE-PRUNE-PROTOCOL-DESIGN-004.md, sections 5, 19, 20, 32, 37, 41; ADR-019).
|
|
5
|
+
* This module does no I/O of its own. `derivePruneState` is a function of the names in the task directory and of what
|
|
6
|
+
* `RegisterIO` returns for them, so its decisions can be tested with injected partial listings and I/O errors
|
|
7
|
+
* without a filesystem. It never writes, never deletes and never repairs.
|
|
8
|
+
*
|
|
9
|
+
* Every verdict is fail-closed: `corrupt`, `unreadable`, `missing` and `legacy` never grant an irreversible action,
|
|
10
|
+
* and a missing name is never read as permission to delete anything (section 37, "absence of information is not
|
|
11
|
+
* permission").
|
|
12
|
+
*/
|
|
13
|
+
import { MAX_PRUNE_ATTEMPTS, type DecisionBy, type PruneOutcome, type PruneState, type Tombstone } from './types.js';
|
|
14
|
+
export { MAX_PRUNE_ATTEMPTS };
|
|
15
|
+
/** Re-checks of the register by a writer that has published a file (Design A, section 24.2). */
|
|
16
|
+
export declare const MAX_WRITE_RESOLVE = 3;
|
|
17
|
+
/** A register record is tiny; anything larger is refused before it is read. */
|
|
18
|
+
export declare const MAX_REGISTER_BYTES: number;
|
|
19
|
+
export declare const REGISTER_FORMAT_VERSION = 2;
|
|
20
|
+
/**
|
|
21
|
+
* Staging files of the write primitive: `<name>.tmp.<pid>.<hex16>`. The ONE definition: the filesystem store uses it
|
|
22
|
+
* for its own temp names too (Design A, section 20.2, N1), so the register can never mistake a staging file for a record.
|
|
23
|
+
*/
|
|
24
|
+
export declare const STAGING_RE: RegExp;
|
|
25
|
+
export declare const TOMBSTONE_FILE = "tombstone.json";
|
|
26
|
+
export declare const PROTOCOL_MARKER_FILE = "durable-protocol.json";
|
|
27
|
+
export declare const prepareFile: (n: number) => string;
|
|
28
|
+
export declare const decisionFile: (n: number) => string;
|
|
29
|
+
export interface PrepareRecord {
|
|
30
|
+
v: 2;
|
|
31
|
+
attempt: number;
|
|
32
|
+
tombstone: Tombstone;
|
|
33
|
+
check: string;
|
|
34
|
+
}
|
|
35
|
+
export type DecisionRecord = {
|
|
36
|
+
v: 2;
|
|
37
|
+
attempt: number;
|
|
38
|
+
outcome: 'abort';
|
|
39
|
+
by?: DecisionBy;
|
|
40
|
+
check: string;
|
|
41
|
+
} | {
|
|
42
|
+
v: 2;
|
|
43
|
+
attempt: number;
|
|
44
|
+
outcome: 'commit';
|
|
45
|
+
tombstone: Tombstone;
|
|
46
|
+
migrated?: true;
|
|
47
|
+
legacySha256?: string;
|
|
48
|
+
check: string;
|
|
49
|
+
};
|
|
50
|
+
/** SHA-256 of the canonical serialization of every other field: a guard against accidental damage, not against an adversary. */
|
|
51
|
+
export declare function checkOf(record: object): string;
|
|
52
|
+
export declare function encodePrepare(attempt: number, tombstone: Tombstone): string;
|
|
53
|
+
export declare function encodeDecision(attempt: number, outcome: PruneOutcome, tombstone: Tombstone | undefined, by: DecisionBy | undefined): string;
|
|
54
|
+
/** The `tombstone.json` file published from a commit. Same content, any reader of the v1 format understands it. */
|
|
55
|
+
export declare function encodeTombstone(tombstone: Tombstone): string;
|
|
56
|
+
/** Closed schema of a v1 tombstone. `null` when it is anything else. */
|
|
57
|
+
export declare function asTombstone(v: unknown, taskId: string): Tombstone | null;
|
|
58
|
+
/** Same tombstone, whatever the key order. */
|
|
59
|
+
export declare const sameTombstone: (a: Tombstone, b: Tombstone) => boolean;
|
|
60
|
+
/**
|
|
61
|
+
* What reading one file gave. `bad` is a PRESENT file that is not a valid record (damage, an unknown schema, a symlink,
|
|
62
|
+
* a special file) — evidence. `ioerr` is "the value is unknown" (EIO, EACCES, EMFILE): never evidence of anything.
|
|
63
|
+
*/
|
|
64
|
+
export type Obs<T> = {
|
|
65
|
+
k: 'ok';
|
|
66
|
+
v: T;
|
|
67
|
+
} | {
|
|
68
|
+
k: 'absent';
|
|
69
|
+
} | {
|
|
70
|
+
k: 'bad';
|
|
71
|
+
reason: string;
|
|
72
|
+
} | {
|
|
73
|
+
k: 'ioerr';
|
|
74
|
+
reason: string;
|
|
75
|
+
};
|
|
76
|
+
export declare function parsePrepare(text: string, n: number, taskId: string): Obs<PrepareRecord>;
|
|
77
|
+
export declare function parseDecision(text: string, n: number, taskId: string): Obs<DecisionRecord>;
|
|
78
|
+
/** `tombstone.json` is the v1 format and is written by older code with its own key order: parse leniently, validate strictly. */
|
|
79
|
+
export declare function parseTombstoneFile(text: string, taskId: string): Obs<Tombstone>;
|
|
80
|
+
/**
|
|
81
|
+
* Reads for `derivePruneState`. Each returns an observation of ONE name in the task directory; a name that is not there
|
|
82
|
+
* is `absent`. The caller maps its filesystem errors to `ioerr` (never to `absent`) and a refused file (symlink, special
|
|
83
|
+
* file, wrong size) to `bad`.
|
|
84
|
+
*/
|
|
85
|
+
export interface RegisterIO {
|
|
86
|
+
prepare(n: number): Obs<PrepareRecord>;
|
|
87
|
+
decision(n: number): Obs<DecisionRecord>;
|
|
88
|
+
tombstone(): Obs<Tombstone>;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The state of a task's register.
|
|
92
|
+
*
|
|
93
|
+
* `names` is ONE directory listing of `tasks/<id>/` (not an atomic snapshot: a name created during the listing may be
|
|
94
|
+
* missing from it). `io` reads individual files. A verdict that rests only on names that were NOT in the listing is
|
|
95
|
+
* not given without looking those names up (section 32.3); if the lookup finds the names the verdict is recomputed, if
|
|
96
|
+
* every one is confirmed absent it stands with `basis: 'lookup'`, and if anything cannot be confirmed the answer is
|
|
97
|
+
* `unreadable` — never a guess.
|
|
98
|
+
*/
|
|
99
|
+
export declare function derivePruneState(names: readonly string[], io: RegisterIO, maxAttempts?: number): PruneState;
|
|
100
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/durable/register.ts"],"names":[],"mappings":"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"}
|