@you-agent-factory/factory-replay 0.0.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.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Port
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # `@you-agent-factory/factory-replay`
2
+
3
+ Framework-independent, deterministic Factory-event replay primitives.
4
+
5
+ The package accepts public `FactoryEvent` aliases from
6
+ `@you-agent-factory/client`, canonicalizes event history by logical tick,
7
+ sequence, event time, and id, accepts each event id once, and reconstructs a
8
+ caller-defined Factory world at either the latest or an explicit historical
9
+ logical tick. The caller supplies a pure reducer and projection adapter, so the
10
+ package has no React, Zustand, browser, network, session-routing, persistence,
11
+ or diagnostics dependencies.
12
+
13
+ `createFactoryReplayCheckpoint` and `advanceFactoryReplay` support live replay
14
+ from an accepted tail. Callers provide state-clone and selected-tick adapters;
15
+ the kernel applies only unseen events after the checkpoint tick in canonical
16
+ order and never mutates the supplied checkpoint.
17
+
18
+ `projectFactoryTopologyAtTick` reconstructs the latest public Factory topology
19
+ at or before an explicit logical tick. `projectFactoryTopology` projects an
20
+ already selected `FactoryDefinition`. Both operations return deterministically
21
+ ordered resource, worker, workstation, Work Type, and Work State nodes plus
22
+ canonical connections. Node and connection IDs follow the public graph ID
23
+ contract, and connection endpoints include renderer-compatible handle IDs.
24
+ References that cannot be resolved are omitted from the connection collection
25
+ and returned as structured projection issues, so consumers never receive a
26
+ dangling edge.
27
+
28
+ Canonical initial and replacement topology events retain durable IDs for
29
+ resources, workers, workstations, Work Types, and Work States, plus authored
30
+ worker and workstation resource requirements. This lets recordings preserve
31
+ stable graph identity and both resource connection kinds even when public
32
+ entity names change. Internal resource availability arcs present in canonical
33
+ workstation IO are excluded from public Work-State routes and do not create
34
+ false unresolved-connection issues.
35
+
36
+ `projectFactoryActivityAtTick` reconstructs active customer Dispatches,
37
+ affected workstations, consumed Work IDs, workers, and resource occupancy from
38
+ canonical event history. Consumers that already hold selected replay evidence
39
+ can call `projectFactoryActivity` directly. Occupancy reports known occupied
40
+ and available quantities, or explicitly reports unavailable evidence when an
41
+ active Dispatch lacks resource facts; it never turns missing evidence into a
42
+ fabricated zero occupancy.
43
+
44
+ `projectFactoryWorkProgressAtTick` reconstructs known customer Work and active
45
+ Dispatch consumption at an explicit logical tick, then assigns every Work ID
46
+ to exactly one of failed, completed, active, queued, or unclassified. The
47
+ classification applies that precedence once, excludes internal time Work, and
48
+ uses `unclassified` when partial event or topology evidence cannot safely
49
+ determine a lifecycle category. `projectFactoryWorkProgress` exposes the same
50
+ pure partition for consumers that already hold selected replay evidence.
51
+
52
+ The hosted dashboard projects these three public read models from its selected
53
+ checkpoint-safe replay state and exposes them together on the timeline world as
54
+ `factoryReplay`. The production timeline projector also derives the legacy
55
+ dashboard topology/runtime compatibility fields from the shared topology,
56
+ activity, occupancy, and Work-progress decisions. Petri-shaped structures
57
+ remain reducer evidence and supplemental dashboard diagnostics, not a second
58
+ public topology or progress classifier.
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@you-agent-factory/factory-replay",
3
+ "version": "0.0.0",
4
+ "description": "Framework-independent deterministic replay primitives for Factory events.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/portpowered/you-agent-factory.git"
9
+ },
10
+ "type": "module",
11
+ "files": [
12
+ "README.md",
13
+ "LICENSE.md",
14
+ "src"
15
+ ],
16
+ "types": "./src/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./src/index.d.ts",
20
+ "import": "./src/index.js"
21
+ }
22
+ },
23
+ "dependencies": {
24
+ "@you-agent-factory/client": "file:../client"
25
+ }
26
+ }
@@ -0,0 +1,208 @@
1
+ /** @param {string | undefined} explicitID @param {string} name */
2
+ function entityID(explicitID, name) {
3
+ return explicitID?.trim() || name;
4
+ }
5
+
6
+ /** @param {string} id */
7
+ function workstationNodeID(id) {
8
+ return `workstation:${id}`;
9
+ }
10
+
11
+ /** @param {string} id */
12
+ function resourceNodeID(id) {
13
+ return `resource:${id}`;
14
+ }
15
+
16
+ /**
17
+ * Project active Dispatch and resource occupancy evidence from one selected
18
+ * canonical replay state without mutating caller-owned data.
19
+ *
20
+ * @param {import("./index.d.ts").FactoryActivityProjectionInput} input
21
+ * @returns {import("./index.d.ts").FactoryActivityProjection}
22
+ */
23
+ export function projectFactoryActivity(input) {
24
+ const issues = new Map();
25
+ const { resourcesByName, workstationsByTransition } = indexFactory(
26
+ input.factory,
27
+ );
28
+
29
+ const occupiedByResource = new Map();
30
+ const occupancyEvidenceAvailable = input.activeDispatches.every(
31
+ (dispatch) => dispatch.resourceNames !== undefined,
32
+ );
33
+ const activeDispatches = input.activeDispatches.map((evidence) => {
34
+ const resolved = workstationsByTransition.get(evidence.transitionId);
35
+ const resourceIds = [];
36
+ for (const resourceName of evidence.resourceNames ?? []) {
37
+ const resource = resourcesByName.get(resourceName);
38
+ if (!resource) {
39
+ addIssue(
40
+ issues,
41
+ "UNRESOLVED_RESOURCE",
42
+ `dispatch:${evidence.id}:resource:${resourceName}`,
43
+ `Dispatch ${evidence.id} refers to unknown resource ${resourceName}.`,
44
+ evidence.id,
45
+ resourceName,
46
+ );
47
+ continue;
48
+ }
49
+ resourceIds.push(resource.id);
50
+ occupiedByResource.set(
51
+ resource.id,
52
+ (occupiedByResource.get(resource.id) ?? 0) + 1,
53
+ );
54
+ }
55
+ if (!resolved) {
56
+ addIssue(
57
+ issues,
58
+ "UNRESOLVED_WORKSTATION",
59
+ `dispatch:${evidence.id}:workstation:${evidence.transitionId}`,
60
+ `Dispatch ${evidence.id} refers to unknown workstation transition ${evidence.transitionId}.`,
61
+ evidence.id,
62
+ evidence.transitionId,
63
+ );
64
+ }
65
+ const workerName = resolved?.workstation.worker?.trim();
66
+ const worker = workerName
67
+ ? (input.factory?.workers ?? []).find(
68
+ (candidate) =>
69
+ candidate.name === workerName || candidate.id === workerName,
70
+ )
71
+ : undefined;
72
+ if (workerName && !worker) {
73
+ addIssue(
74
+ issues,
75
+ "UNRESOLVED_WORKER",
76
+ `dispatch:${evidence.id}:worker:${workerName}`,
77
+ `Dispatch ${evidence.id} refers to unknown worker ${workerName}.`,
78
+ evidence.id,
79
+ workerName,
80
+ );
81
+ }
82
+ return {
83
+ id: evidence.id,
84
+ resourceIds: [...resourceIds].sort(),
85
+ startedTick: evidence.startedTick,
86
+ transitionId: evidence.transitionId,
87
+ workIds: [...new Set(evidence.workIds)].sort(),
88
+ ...(resolved
89
+ ? {
90
+ workstationId: resolved.id,
91
+ workstationNodeId: workstationNodeID(resolved.id),
92
+ }
93
+ : {}),
94
+ ...(worker
95
+ ? { workerId: entityID(worker.id, worker.name) }
96
+ : {}),
97
+ };
98
+ });
99
+
100
+ const resourceOccupancy = projectResourceOccupancy(
101
+ resourcesByName,
102
+ occupiedByResource,
103
+ occupancyEvidenceAvailable,
104
+ issues,
105
+ );
106
+
107
+ return {
108
+ activeDispatches: activeDispatches.sort((left, right) =>
109
+ left.id.localeCompare(right.id),
110
+ ),
111
+ activeWorkstationIds: [
112
+ ...new Set(
113
+ activeDispatches.flatMap((dispatch) =>
114
+ dispatch.workstationId ? [dispatch.workstationId] : [],
115
+ ),
116
+ ),
117
+ ].sort(),
118
+ issues: [...issues.values()].sort((left, right) =>
119
+ left.id.localeCompare(right.id),
120
+ ),
121
+ resourceOccupancy: resourceOccupancy.sort((left, right) =>
122
+ left.resourceId.localeCompare(right.resourceId),
123
+ ),
124
+ selectedTick: input.selectedTick,
125
+ };
126
+ }
127
+
128
+ /** @param {import("@you-agent-factory/client").FactoryDefinition | undefined} factory */
129
+ function indexFactory(factory) {
130
+ const resourcesByName = new Map();
131
+ const workstationsByTransition = new Map();
132
+ for (const resource of factory?.resources ?? []) {
133
+ resourcesByName.set(resource.name, {
134
+ capacity: Math.max(0, resource.capacity),
135
+ id: entityID(resource.id, resource.name),
136
+ });
137
+ }
138
+ for (const workstation of factory?.workstations ?? []) {
139
+ const id = entityID(workstation.id, workstation.name);
140
+ workstationsByTransition.set(workstation.name, { id, workstation });
141
+ if (workstation.id?.trim()) {
142
+ workstationsByTransition.set(workstation.id, { id, workstation });
143
+ }
144
+ }
145
+ return { resourcesByName, workstationsByTransition };
146
+ }
147
+
148
+ /**
149
+ * @param {Map<string, {capacity: number, id: string}>} resourcesByName
150
+ * @param {Map<string, number>} occupiedByResource
151
+ * @param {boolean} evidenceAvailable
152
+ * @param {Map<string, import("./index.d.ts").FactoryActivityProjectionIssue>} issues
153
+ * @returns {import("./index.d.ts").FactoryResourceOccupancyProjection[]}
154
+ */
155
+ function projectResourceOccupancy(
156
+ resourcesByName,
157
+ occupiedByResource,
158
+ evidenceAvailable,
159
+ issues,
160
+ ) {
161
+ return [...resourcesByName.values()].map((resource) => {
162
+ if (!evidenceAvailable) {
163
+ return {
164
+ capacity: resource.capacity,
165
+ evidence: "unavailable",
166
+ resourceId: resource.id,
167
+ resourceNodeId: resourceNodeID(resource.id),
168
+ };
169
+ }
170
+ const occupiedQuantity = occupiedByResource.get(resource.id) ?? 0;
171
+ if (occupiedQuantity > resource.capacity) {
172
+ addIssue(
173
+ issues,
174
+ "RESOURCE_CAPACITY_EXCEEDED",
175
+ `resource:${resource.id}:capacity-exceeded`,
176
+ `Resource ${resource.id} has ${occupiedQuantity} occupied units for capacity ${resource.capacity}.`,
177
+ undefined,
178
+ resource.id,
179
+ );
180
+ }
181
+ return {
182
+ availableQuantity: Math.max(0, resource.capacity - occupiedQuantity),
183
+ capacity: resource.capacity,
184
+ evidence: "known",
185
+ occupiedQuantity,
186
+ resourceId: resource.id,
187
+ resourceNodeId: resourceNodeID(resource.id),
188
+ };
189
+ });
190
+ }
191
+
192
+ /**
193
+ * @param {Map<string, import("./index.d.ts").FactoryActivityProjectionIssue>} issues
194
+ * @param {import("./index.d.ts").FactoryActivityProjectionIssue["code"]} code
195
+ * @param {string} id
196
+ * @param {string} message
197
+ * @param {string | undefined} dispatchId
198
+ * @param {string | undefined} reference
199
+ */
200
+ function addIssue(issues, code, id, message, dispatchId, reference) {
201
+ issues.set(id, {
202
+ code,
203
+ id,
204
+ message,
205
+ ...(dispatchId ? { dispatchId } : {}),
206
+ ...(reference ? { reference } : {}),
207
+ });
208
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,324 @@
1
+ import type { FactoryEvent } from "@you-agent-factory/client";
2
+ import type { FactoryDefinition } from "@you-agent-factory/client";
3
+
4
+ export type FactoryTopologyNodeKind =
5
+ | "resource"
6
+ | "worker"
7
+ | "work-state"
8
+ | "work-type"
9
+ | "workstation";
10
+
11
+ export type FactoryTopologyConnectionKind =
12
+ | "worker-assignment"
13
+ | "worker-resource"
14
+ | "workstation-input"
15
+ | "workstation-on-continue"
16
+ | "workstation-on-failure"
17
+ | "workstation-on-rejection"
18
+ | "workstation-output"
19
+ | "workstation-resource"
20
+ | "work-type-state";
21
+
22
+ export interface FactoryTopologyHandle {
23
+ id: string;
24
+ role: "source" | "target";
25
+ }
26
+
27
+ interface FactoryTopologyNodeBase {
28
+ entityId: string;
29
+ handles: FactoryTopologyHandle[];
30
+ id: string;
31
+ kind: FactoryTopologyNodeKind;
32
+ label: string;
33
+ }
34
+
35
+ export interface FactoryResourceTopologyNode extends FactoryTopologyNodeBase {
36
+ capacity: number;
37
+ kind: "resource";
38
+ }
39
+
40
+ export interface FactoryWorkerTopologyNode extends FactoryTopologyNodeBase {
41
+ kind: "worker";
42
+ }
43
+
44
+ export interface FactoryWorkTypeTopologyNode extends FactoryTopologyNodeBase {
45
+ kind: "work-type";
46
+ }
47
+
48
+ export interface FactoryWorkStateTopologyNode extends FactoryTopologyNodeBase {
49
+ category: NonNullable<FactoryDefinition["workTypes"]>[number]["states"][number]["type"];
50
+ kind: "work-state";
51
+ workTypeId: string;
52
+ }
53
+
54
+ export interface FactoryWorkstationTopologyNode
55
+ extends FactoryTopologyNodeBase {
56
+ kind: "workstation";
57
+ }
58
+
59
+ export type FactoryTopologyNode =
60
+ | FactoryResourceTopologyNode
61
+ | FactoryWorkerTopologyNode
62
+ | FactoryWorkStateTopologyNode
63
+ | FactoryWorkTypeTopologyNode
64
+ | FactoryWorkstationTopologyNode;
65
+
66
+ export interface FactoryTopologyConnectionEndpoint {
67
+ handleId: string;
68
+ nodeId: string;
69
+ }
70
+
71
+ export interface FactoryTopologyConnection {
72
+ id: string;
73
+ kind: FactoryTopologyConnectionKind;
74
+ source: FactoryTopologyConnectionEndpoint;
75
+ target: FactoryTopologyConnectionEndpoint;
76
+ }
77
+
78
+ export interface FactoryTopologyProjectionIssue {
79
+ code: "DUPLICATE_ENTITY_ID" | "MISSING_FACTORY" | "UNRESOLVED_CONNECTION";
80
+ connectionKind?: FactoryTopologyConnectionKind;
81
+ id: string;
82
+ message: string;
83
+ nodeId?: string;
84
+ sourceReference?: string;
85
+ targetReference?: string;
86
+ }
87
+
88
+ export interface FactoryTopologyProjection {
89
+ connections: FactoryTopologyConnection[];
90
+ issues: FactoryTopologyProjectionIssue[];
91
+ nodes: FactoryTopologyNode[];
92
+ selectedTick: number;
93
+ }
94
+
95
+ export interface FactoryTopologyProjectionInput {
96
+ factory?: FactoryDefinition | undefined;
97
+ selectedTick: number;
98
+ }
99
+
100
+ export interface FactoryTopologyAtTickInput {
101
+ events: readonly FactoryEvent[];
102
+ tick: number;
103
+ }
104
+
105
+ export interface FactoryActiveDispatchEvidence {
106
+ id: string;
107
+ resourceNames?: readonly string[];
108
+ startedTick: number;
109
+ transitionId: string;
110
+ workIds: readonly string[];
111
+ }
112
+
113
+ export interface FactoryActiveDispatchProjection {
114
+ id: string;
115
+ resourceIds: string[];
116
+ startedTick: number;
117
+ transitionId: string;
118
+ workIds: string[];
119
+ workerId?: string;
120
+ workstationId?: string;
121
+ workstationNodeId?: string;
122
+ }
123
+
124
+ export interface FactoryResourceOccupancyProjection {
125
+ availableQuantity?: number;
126
+ capacity: number;
127
+ evidence: "known" | "unavailable";
128
+ occupiedQuantity?: number;
129
+ occupiedTokenIds?: string[];
130
+ resourceId: string;
131
+ resourceNodeId: string;
132
+ }
133
+
134
+ export interface FactoryActivityProjectionIssue {
135
+ code:
136
+ | "RESOURCE_CAPACITY_EXCEEDED"
137
+ | "UNRESOLVED_RESOURCE"
138
+ | "UNRESOLVED_WORKER"
139
+ | "UNRESOLVED_WORKSTATION";
140
+ dispatchId?: string;
141
+ id: string;
142
+ message: string;
143
+ reference?: string;
144
+ }
145
+
146
+ export interface FactoryActivityProjection {
147
+ activeDispatches: FactoryActiveDispatchProjection[];
148
+ activeWorkstationIds: string[];
149
+ issues: FactoryActivityProjectionIssue[];
150
+ resourceOccupancy: FactoryResourceOccupancyProjection[];
151
+ selectedTick: number;
152
+ }
153
+
154
+ export interface FactoryActivityProjectionInput {
155
+ activeDispatches: readonly FactoryActiveDispatchEvidence[];
156
+ factory?: FactoryDefinition | undefined;
157
+ selectedTick: number;
158
+ }
159
+
160
+ export interface FactoryActivityAtTickInput {
161
+ events: readonly FactoryEvent[];
162
+ tick: number;
163
+ }
164
+
165
+ export type FactoryWorkStateCategory =
166
+ | "FAILED"
167
+ | "INITIAL"
168
+ | "PROCESSING"
169
+ | "TERMINAL";
170
+
171
+ export type FactoryWorkProgressCategory =
172
+ | "failed"
173
+ | "completed"
174
+ | "active"
175
+ | "queued"
176
+ | "unclassified";
177
+
178
+ export interface FactoryWorkProgressStateEvidence {
179
+ category?: FactoryWorkStateCategory;
180
+ id?: string;
181
+ name?: string;
182
+ }
183
+
184
+ export interface FactoryWorkProgressEvidence {
185
+ id: string;
186
+ state?: FactoryWorkProgressStateEvidence;
187
+ workTypeId?: string;
188
+ }
189
+
190
+ export interface FactoryWorkProgressItem {
191
+ id: string;
192
+ stateId?: string;
193
+ stateName?: string;
194
+ workTypeId?: string;
195
+ }
196
+
197
+ export type FactoryWorkProgressCounts = Record<FactoryWorkProgressCategory, number>;
198
+
199
+ export interface FactoryWorkProgressProjection {
200
+ active: FactoryWorkProgressItem[];
201
+ completed: FactoryWorkProgressItem[];
202
+ counts: FactoryWorkProgressCounts;
203
+ failed: FactoryWorkProgressItem[];
204
+ queued: FactoryWorkProgressItem[];
205
+ selectedTick: number;
206
+ total: number;
207
+ unclassified: FactoryWorkProgressItem[];
208
+ }
209
+
210
+ export interface FactoryWorkProgressProjectionInput {
211
+ activeWorkIds: readonly string[];
212
+ factory?: FactoryDefinition | undefined;
213
+ selectedTick: number;
214
+ works: readonly FactoryWorkProgressEvidence[];
215
+ }
216
+
217
+ export interface FactoryWorkProgressAtTickInput {
218
+ events: readonly FactoryEvent[];
219
+ tick: number;
220
+ }
221
+
222
+ export type FactoryReplaySelection =
223
+ | { mode: "current" }
224
+ | { mode: "fixed"; tick: number };
225
+
226
+ export interface FactoryReplayReducer<State, World> {
227
+ createState(selectedTick: number): State;
228
+ applyEvent(state: State, event: FactoryEvent): State;
229
+ projectWorld(state: State): World;
230
+ }
231
+
232
+ export interface FactoryReplayInitialization<State, World> {
233
+ events: readonly FactoryEvent[];
234
+ reducer: FactoryReplayReducer<State, World>;
235
+ selection: FactoryReplaySelection;
236
+ }
237
+
238
+ export interface FactoryReplayResult<State, World> {
239
+ appliedEvents: FactoryEvent[];
240
+ events: FactoryEvent[];
241
+ latestTick: number;
242
+ selectedTick: number;
243
+ selection: FactoryReplaySelection;
244
+ state: State;
245
+ world: World;
246
+ }
247
+
248
+ export type FactoryReplayStateCloner<State> = (state: State) => State;
249
+
250
+ export interface FactoryReplayCheckpoint<State> {
251
+ acceptedEventIDs: readonly string[];
252
+ selectedTick: number;
253
+ state: State;
254
+ }
255
+
256
+ export interface FactoryReplayAdvanceInput<State, World> {
257
+ checkpoint: FactoryReplayCheckpoint<State>;
258
+ cloneState: FactoryReplayStateCloner<State>;
259
+ events: readonly FactoryEvent[];
260
+ reducer: FactoryReplayReducer<State, World>;
261
+ setSelectedTick(state: State, tick: number): State;
262
+ tick: number;
263
+ }
264
+
265
+ export interface FactoryReplayAdvanceResult<State, World> {
266
+ appliedEvents: FactoryEvent[];
267
+ checkpoint: FactoryReplayCheckpoint<State>;
268
+ latestTick: number;
269
+ selectedTick: number;
270
+ state: State;
271
+ world: World;
272
+ }
273
+
274
+ export function compareFactoryEvents(
275
+ left: FactoryEvent,
276
+ right: FactoryEvent,
277
+ ): number;
278
+
279
+ export function canonicalizeFactoryEvents(
280
+ events: readonly FactoryEvent[],
281
+ ): FactoryEvent[];
282
+
283
+ export function initializeFactoryReplay<State, World>(
284
+ input: FactoryReplayInitialization<State, World>,
285
+ ): FactoryReplayResult<State, World>;
286
+
287
+ export function createFactoryReplayCheckpoint<State, World>(
288
+ result: FactoryReplayResult<State, World>,
289
+ cloneState: FactoryReplayStateCloner<State>,
290
+ ): FactoryReplayCheckpoint<State>;
291
+
292
+ export function advanceFactoryReplay<State, World>(
293
+ input: FactoryReplayAdvanceInput<State, World>,
294
+ ): FactoryReplayAdvanceResult<State, World>;
295
+
296
+ export function projectFactoryWorldAtTick<State, World>(
297
+ input: Omit<FactoryReplayInitialization<State, World>, "selection"> & {
298
+ tick: number;
299
+ },
300
+ ): FactoryReplayResult<State, World>;
301
+
302
+ export function projectFactoryTopology(
303
+ input: FactoryTopologyProjectionInput,
304
+ ): FactoryTopologyProjection;
305
+
306
+ export function projectFactoryTopologyAtTick(
307
+ input: FactoryTopologyAtTickInput,
308
+ ): FactoryTopologyProjection;
309
+
310
+ export function projectFactoryActivity(
311
+ input: FactoryActivityProjectionInput,
312
+ ): FactoryActivityProjection;
313
+
314
+ export function projectFactoryActivityAtTick(
315
+ input: FactoryActivityAtTickInput,
316
+ ): FactoryActivityProjection;
317
+
318
+ export function projectFactoryWorkProgress(
319
+ input: FactoryWorkProgressProjectionInput,
320
+ ): FactoryWorkProgressProjection;
321
+
322
+ export function projectFactoryWorkProgressAtTick(
323
+ input: FactoryWorkProgressAtTickInput,
324
+ ): FactoryWorkProgressProjection;