@hypercarrier/pi-team-durable 0.1.0-rc.1 → 0.1.0-rc.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.
Files changed (35) hide show
  1. package/README.md +100 -9
  2. package/dist/authority/contracts.d.ts +7 -0
  3. package/dist/authority/contracts.js +20 -4
  4. package/dist/authority/delivery.d.ts +4 -3
  5. package/dist/authority/delivery.js +35 -29
  6. package/dist/authority/graph-control.d.ts +1 -1
  7. package/dist/authority/incremental-graph-control.d.ts +156 -0
  8. package/dist/authority/incremental-graph-control.js +1051 -0
  9. package/dist/authority/index.d.ts +5 -1
  10. package/dist/authority/index.js +5 -1
  11. package/dist/authority/interrupt.js +3 -3
  12. package/dist/authority/notifier.d.ts +1 -1
  13. package/dist/authority/notifier.js +26 -20
  14. package/dist/authority/observation-store.d.ts +104 -0
  15. package/dist/authority/observation-store.js +226 -0
  16. package/dist/authority/observation.d.ts +3 -45
  17. package/dist/authority/observation.js +86 -68
  18. package/dist/authority/panel.d.ts +121 -0
  19. package/dist/authority/panel.js +44 -0
  20. package/dist/authority/projection.d.ts +5 -4
  21. package/dist/authority/projection.js +11 -11
  22. package/dist/authority/rc7-contract.json +57 -1
  23. package/dist/authority/runtime.d.ts +38 -2
  24. package/dist/authority/runtime.js +13 -14
  25. package/dist/authority/state.d.ts +19 -4
  26. package/dist/authority/state.js +14 -12
  27. package/dist/authority/store.d.ts +144 -0
  28. package/dist/authority/store.js +675 -0
  29. package/dist/authority/sync.d.ts +4 -3
  30. package/dist/authority/sync.js +20 -19
  31. package/dist/authority/tools.d.ts +41 -4
  32. package/dist/authority/tools.js +63 -87
  33. package/dist/testing.d.ts +11 -0
  34. package/dist/testing.js +10 -0
  35. package/package.json +7 -1
@@ -109,6 +109,10 @@ export interface Event {
109
109
  text?: string;
110
110
  entryId?: EntryId;
111
111
  }
112
+ export type JournalRef = Event | {
113
+ seq: number;
114
+ entryId: EntryId;
115
+ };
112
116
  export interface JournalState {
113
117
  seq: number;
114
118
  events: Event[];
@@ -136,15 +140,26 @@ export declare const GraphDoc: import("@earendil-works/pi-durable").SessionDocTo
136
140
  export declare const JournalDoc: import("@earendil-works/pi-durable").SessionDocToken<JsonObject>;
137
141
  export declare const OutboxDoc: import("@earendil-works/pi-durable").SessionDocToken<JsonObject>;
138
142
  export declare const ReceiptDoc: import("@earendil-works/pi-durable").SessionDocToken<JsonObject>;
139
- export declare function open(tx: Tx): Promise<{
143
+ export declare function hasLegacyFence(value: object): boolean;
144
+ /** Keep the v2 address occupied so an old reader cannot create a v1 incarnation. */
145
+ export declare function fenceLegacyDoc(value: object): void;
146
+ export interface State {
140
147
  team: TeamState;
141
148
  graph: GraphState;
142
149
  journal: JournalState;
143
150
  outbox: OutboxState;
144
151
  receipts: ReceiptState;
145
- }>;
146
- export type State = Awaited<ReturnType<typeof open>>;
152
+ }
153
+ /** Full historical inspection. Runtime commands use openAuthority's indexed state. */
154
+ export declare function open(tx: Tx): Promise<State>;
147
155
  export declare const plain: <T>(value: T) => T;
148
156
  export declare const JOURNAL_RESIDENT_LIMIT = 100;
149
157
  /** History is append-only storage; the document contains a bounded recent projection. */
150
- export declare function event(tx: Tx, s: State, actor: string, kind: string, extra?: Pick<Event, 'taskId' | 'taskIds' | 'worker' | 'at' | 'text'>): Promise<void>;
158
+ export declare function event(tx: Tx, s: {
159
+ team: TeamState;
160
+ journal: {
161
+ seq: number;
162
+ events: JournalRef[];
163
+ };
164
+ flush?: () => void;
165
+ }, actor: string, kind: string, extra?: Pick<Event, 'taskId' | 'taskIds' | 'worker' | 'at' | 'text'>): Promise<void>;
@@ -1,18 +1,21 @@
1
1
  import { defineDoc } from '@earendil-works/pi-durable';
2
- const doc = (kind, initial) => defineDoc({ kind, version: 1, scope: 'session', checkpointWhen: () => false, initial });
2
+ const doc = (kind, initial) => defineDoc({ kind, version: 2, migrate: value => value, scope: 'session', checkpointWhen: () => true, initial });
3
3
  export const TeamDoc = doc('ptb.team', () => ({ history: [], stops: {} }));
4
4
  export const GraphDoc = doc('ptb.graph', () => ({}));
5
- export const JournalDoc = defineDoc({ kind: 'ptb.journal', version: 1, scope: 'session', initial: () => ({ seq: 0, events: [], acknowledged: 0 }), checkpointWhen: (_value, _ops, info) => info.deltasSinceBase >= 31 });
5
+ export const JournalDoc = doc('ptb.journal', () => ({ seq: 0, events: [], acknowledged: 0 }));
6
6
  export const OutboxDoc = doc('ptb.outbox', () => ({ alerts: {}, obligations: {} }));
7
7
  export const ReceiptDoc = doc('ptb.receipts', () => ({ calls: {} }));
8
+ const fenceMarker = 'ptb-authority-v2';
9
+ export function hasLegacyFence(value) { return value.fence === fenceMarker; }
10
+ /** Keep the v2 address occupied so an old reader cannot create a v1 incarnation. */
11
+ export function fenceLegacyDoc(value) {
12
+ for (const key of Object.keys(value))
13
+ Reflect.deleteProperty(value, key);
14
+ Object.assign(value, { fence: fenceMarker });
15
+ }
16
+ /** Full historical inspection. Runtime commands use openAuthority's indexed state. */
8
17
  export async function open(tx) {
9
- return {
10
- team: await tx.doc(TeamDoc),
11
- graph: await tx.doc(GraphDoc),
12
- journal: await tx.doc(JournalDoc),
13
- outbox: await tx.doc(OutboxDoc),
14
- receipts: await tx.doc(ReceiptDoc),
15
- };
18
+ return (await import("./store.js")).inspectAuthority(tx);
16
19
  }
17
20
  export const plain = (value) => JSON.parse(JSON.stringify(value));
18
21
  export const JOURNAL_RESIDENT_LIMIT = 100;
@@ -20,7 +23,6 @@ export const JOURNAL_RESIDENT_LIMIT = 100;
20
23
  export async function event(tx, s, actor, kind, extra = {}) {
21
24
  const value = { seq: ++s.journal.seq, epoch: s.team.current.epoch, actor, kind, ...extra };
22
25
  const entry = await tx.appendEntry(s.team.current.lead, { kind: 'ptb.event', data: value });
23
- s.journal.events.push({ ...value, entryId: entry.id });
24
- if (s.journal.events.length > JOURNAL_RESIDENT_LIMIT)
25
- s.journal.events.splice(0, s.journal.events.length - JOURNAL_RESIDENT_LIMIT);
26
+ s.journal.events = [...s.journal.events, { ...value, entryId: entry.id }].slice(-JOURNAL_RESIDENT_LIMIT);
27
+ s.flush?.();
26
28
  }
@@ -0,0 +1,144 @@
1
+ import { type Tx, type JsonObject, type ConversationId, type TaskId } from '@earendil-works/pi-durable';
2
+ import { type GraphControlSnapshot, type GraphApplyInput, type GraphTaskTransitionInput } from './graph-control.ts';
3
+ import { type GraphMaterializedHead, type GraphMaterializedTask } from './incremental-graph-control.ts';
4
+ import type { GraphTaskCard } from './card-types.ts';
5
+ import { type TeamState, type JournalState, type JournalRef, type Event, type Alert, type Obligation, type Receipt, type State } from './state.ts';
6
+ type GraphHead = Omit<GraphMaterializedHead, 'topology' | 'projections'>;
7
+ export interface AuthorityHead {
8
+ initialized: boolean;
9
+ legacyFenced?: boolean;
10
+ epoch?: string;
11
+ graph?: GraphHead;
12
+ taskCount: number;
13
+ log?: ConversationId;
14
+ journal: Omit<JournalState, 'events'> & {
15
+ events: string;
16
+ };
17
+ pendingBuckets: Record<string, true>;
18
+ unscheduledBuckets: Record<string, true>;
19
+ obligationSequence: number;
20
+ recentObligations: string[];
21
+ recentAlerts: string[];
22
+ leadAlerts: string[];
23
+ leadAlertCount: number;
24
+ obligationTail?: string;
25
+ alertTail?: string;
26
+ callTail?: string;
27
+ attention: Record<string, 'blocked' | 'failed'>;
28
+ frontier: Record<string, {
29
+ id: string;
30
+ version: string;
31
+ generation: number;
32
+ }>;
33
+ taskObligations: Record<string, string[]>;
34
+ workerBindings: Record<string, string>;
35
+ stopRefresh?: boolean;
36
+ }
37
+ export declare const HeadDoc: import("@earendil-works/pi-durable").SessionDocToken<JsonObject>;
38
+ export declare const TaskDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
39
+ export declare const GraphIndexDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
40
+ export declare const WorkerIndexDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
41
+ export declare const OrdinalDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
42
+ export declare const OperationDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
43
+ export declare const ObligationDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
44
+ export declare const EligibilityDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
45
+ export declare const AlertDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
46
+ export declare const DirectCallDoc: import("@earendil-works/pi-durable").SessionDocFamilyToken<JsonObject, null>;
47
+ export declare const CallDoc: import("@earendil-works/pi-durable").TaskDocToken<JsonObject>;
48
+ export declare const taskAddress: (epoch: string, id: string) => string;
49
+ export interface OperatorTask {
50
+ key: string;
51
+ title: string;
52
+ goal: string;
53
+ assignee: string;
54
+ needs: string[];
55
+ version: string;
56
+ current_context: string;
57
+ attempts: {
58
+ id: string;
59
+ ordinal: number;
60
+ startedAt?: number;
61
+ endedAt?: number;
62
+ outcome?: string;
63
+ evidence?: string;
64
+ }[];
65
+ derived: string;
66
+ status: string;
67
+ derivedReason?: string;
68
+ evidence?: string;
69
+ }
70
+ export interface TaskRecord {
71
+ materialized: GraphMaterializedTask;
72
+ card: GraphTaskCard;
73
+ operator: OperatorTask;
74
+ }
75
+ interface StoredCall {
76
+ fingerprint?: string;
77
+ result?: string;
78
+ stops?: string[];
79
+ epoch?: string;
80
+ previous?: string;
81
+ }
82
+ type CurrentJournal = Omit<JournalState, 'events'> & {
83
+ events: JournalRef[];
84
+ };
85
+ interface Eligibility {
86
+ doc: JsonObject;
87
+ pending: Record<string, number>;
88
+ unscheduled: Record<string, number>;
89
+ }
90
+ export interface Authority {
91
+ tx: Tx;
92
+ team: TeamState;
93
+ head: AuthorityHead;
94
+ journal: CurrentJournal;
95
+ headDoc: JsonObject;
96
+ deferFlush: boolean;
97
+ flush: () => void;
98
+ records: Map<string, TaskRecord | undefined>;
99
+ obligations: Map<string, Obligation>;
100
+ eligibility: Map<string, Eligibility>;
101
+ newObligations: Set<string>;
102
+ calls: Map<number, {
103
+ doc: StoredCall;
104
+ native: boolean;
105
+ }>;
106
+ workerIndexes: Map<string, string[]>;
107
+ migratedHistory?: Map<string, GraphControlSnapshot>;
108
+ }
109
+ export declare function recentEvents(s: Authority, refs?: JournalRef[]): Promise<Event[]>;
110
+ export declare function flushAuthority(s: Authority): void;
111
+ export declare function openAuthority(tx: Tx): Promise<Authority>;
112
+ export declare function startEpoch(s: Authority, epoch: string): Promise<void>;
113
+ export declare function taskIds(s: Authority): Promise<string[]>;
114
+ export declare function taskRecord(s: Authority, id: string): Promise<TaskRecord | undefined>;
115
+ export declare function taskCards(s: Authority, ids?: string[]): Promise<GraphTaskCard[]>;
116
+ export declare function unfinished(s: Authority, worker?: string): Promise<string[]>;
117
+ export declare function obligation(s: Authority, key: string): Promise<Obligation | undefined>;
118
+ export declare function markScheduled(s: Authority, key: string): Promise<void>;
119
+ export declare function unscheduledObligations(s: Authority): Promise<Obligation[]>;
120
+ export declare function addObligation(s: Authority, value: Obligation): Promise<void>;
121
+ export declare function setObligationState(s: Authority, value: Obligation, state: Obligation['state']): Promise<void>;
122
+ export declare function allObligations(s: Authority): Promise<Obligation[]>;
123
+ export declare function pendingObligations(s: Authority): Promise<Obligation[]>;
124
+ export declare function alertRecord(s: Authority, id: string): Promise<Alert | undefined>;
125
+ export declare function addAlert(s: Authority, value: Alert): Promise<void>;
126
+ export declare function callReceipt(s: Authority, id: TaskId, native?: boolean): Promise<StoredCall>;
127
+ export declare function saveCall(s: Authority, id: TaskId, receipt: Receipt): Promise<void>;
128
+ export declare function hasOperation(s: Authority, operationId: string): Promise<boolean>;
129
+ export declare function graphCommand(s: Authority, command: {
130
+ kind: 'apply';
131
+ input: GraphApplyInput;
132
+ } | {
133
+ kind: 'transition';
134
+ input: GraphTaskTransitionInput;
135
+ }, now: () => number): Promise<(import("./graph-control.ts").GraphApplyResult & {
136
+ replayed: boolean;
137
+ }) | (import("./graph-control.ts").GraphTransitionResult & {
138
+ replayed: boolean;
139
+ })>;
140
+ /** History materialization for diagnostics, migration checks, and generation reconciliation. */
141
+ export declare function readGraphHistory(s: Authority, epoch?: string): Promise<GraphControlSnapshot>;
142
+ /** Legacy-shaped, full inspection for diagnostics and existing recovery tests. */
143
+ export declare function inspectAuthority(tx: Tx): Promise<State>;
144
+ export {};