@hraness/direct 0.7.5

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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +436 -0
  3. package/dist/core/index.js +162 -0
  4. package/dist/index-1csg00w4.js +1167 -0
  5. package/dist/index-6mdfd2ey.js +464 -0
  6. package/dist/index-7n1h75n6.js +616 -0
  7. package/dist/index.js +232 -0
  8. package/dist/react.js +32 -0
  9. package/dist/testing/index.js +1069 -0
  10. package/dist/tooling/bombadil.js +2117 -0
  11. package/dist/tooling/browser-verification-entry.js +1499 -0
  12. package/dist/tooling/bundle-boundary.js +119 -0
  13. package/dist/web.js +605 -0
  14. package/package.json +179 -0
  15. package/skills/direct/AGENTS.md +13 -0
  16. package/skills/direct/SKILL.md +49 -0
  17. package/skills/direct/agents/openai.yaml +4 -0
  18. package/skills/direct/references/adoption.md +131 -0
  19. package/skills/direct/references/install.md +91 -0
  20. package/skills/direct/references/verification.md +247 -0
  21. package/src/core/coverage.ts +336 -0
  22. package/src/core/definition.ts +378 -0
  23. package/src/core/effects.ts +88 -0
  24. package/src/core/fixture.ts +185 -0
  25. package/src/core/ids.ts +77 -0
  26. package/src/core/index.ts +13 -0
  27. package/src/core/json-value.ts +7 -0
  28. package/src/core/json.ts +593 -0
  29. package/src/core/query.ts +230 -0
  30. package/src/core/reason.ts +16 -0
  31. package/src/core/resource.ts +10 -0
  32. package/src/core/result.ts +19 -0
  33. package/src/core/runtime.ts +229 -0
  34. package/src/core/scenario.ts +149 -0
  35. package/src/core/store.ts +784 -0
  36. package/src/index.ts +51 -0
  37. package/src/react.ts +54 -0
  38. package/src/testing/activity.ts +228 -0
  39. package/src/testing/coverage-binding.ts +99 -0
  40. package/src/testing/evidence.ts +59 -0
  41. package/src/testing/index.ts +22 -0
  42. package/src/testing/manifest.ts +559 -0
  43. package/src/testing/probe.ts +446 -0
  44. package/src/testing/scripted-transport.ts +775 -0
  45. package/src/testing/session.ts +525 -0
  46. package/src/tooling/bombadil-campaign.ts +288 -0
  47. package/src/tooling/bombadil-internal.d.ts +46 -0
  48. package/src/tooling/bombadil-runner.ts +1424 -0
  49. package/src/tooling/bombadil.ts +27 -0
  50. package/src/tooling/browser-verification-entry.ts +32 -0
  51. package/src/tooling/browser-verification.ts +916 -0
  52. package/src/tooling/bundle-boundary.ts +159 -0
  53. package/src/web/browser-bridge.ts +296 -0
  54. package/src/web/browser.ts +277 -0
  55. package/src/web/fetch-firewall.ts +251 -0
  56. package/src/web.ts +27 -0
package/src/index.ts ADDED
@@ -0,0 +1,51 @@
1
+ import {
2
+ defineDirect,
3
+ parseDirectDefinition,
4
+ tryDefineDirect,
5
+ } from "./core/definition.js";
6
+
7
+ export const FIXTURE_QUERY_KEY = "__direct_fixture" as const;
8
+ export const SCENARIO_QUERY_KEY = "__direct_scenario" as const;
9
+
10
+ export {
11
+ defineDirect,
12
+ parseDirectDefinition,
13
+ tryDefineDirect,
14
+ };
15
+ export type {
16
+ DirectDefinition,
17
+ DirectDefinitionError,
18
+ DirectDefinitionInput,
19
+ DirectDefinitionLimits,
20
+ } from "./core/definition.js";
21
+ export type {
22
+ CoverageCatalogSnapshot,
23
+ CoverageEntry,
24
+ CoverageEntryInput,
25
+ CoverageMode,
26
+ } from "./core/coverage.js";
27
+ export type {
28
+ FixtureCreateInput,
29
+ FixtureEnvelope,
30
+ FixtureError,
31
+ } from "./core/fixture.js";
32
+ export type { WorldParser } from "./core/json.js";
33
+ export type {
34
+ JsonArray,
35
+ JsonObject,
36
+ JsonPrimitive,
37
+ JsonValue,
38
+ } from "./core/json-value.js";
39
+ export type {
40
+ ActiveDirect,
41
+ DirectActivation,
42
+ QueryError,
43
+ } from "./core/query.js";
44
+ export type {
45
+ LogicalRuntime,
46
+ LogicalRuntimeSnapshot,
47
+ } from "./core/runtime.js";
48
+ export type {
49
+ ScenarioDefinition,
50
+ ScenarioDefinitionInput,
51
+ } from "./core/scenario.js";
package/src/react.ts ADDED
@@ -0,0 +1,54 @@
1
+ import {
2
+ createContext,
3
+ createElement,
4
+ useContext,
5
+ useSyncExternalStore,
6
+ type Context,
7
+ type ReactElement,
8
+ type ReactNode,
9
+ } from "react";
10
+ import type { JsonValue } from "./core/json-value.js";
11
+ import type { DirectStore, DirectStoreSnapshot } from "./core/store.js";
12
+
13
+ export interface DirectProviderProps<World extends JsonValue> {
14
+ readonly store: DirectStore<World>;
15
+ readonly children: ReactNode;
16
+ }
17
+
18
+ export interface DirectReactBindings<World extends JsonValue> {
19
+ readonly Context: Context<DirectStore<World> | null>;
20
+ readonly Provider: (props: DirectProviderProps<World>) => ReactElement;
21
+ readonly useStore: () => DirectStore<World>;
22
+ readonly useSnapshot: () => DirectStoreSnapshot<World>;
23
+ readonly useWorld: () => World;
24
+ }
25
+
26
+ export function createDirectReactBindings<World extends JsonValue>(): DirectReactBindings<World> {
27
+ const StoreContext = createContext<DirectStore<World> | null>(null);
28
+
29
+ const useStore = (): DirectStore<World> => {
30
+ const store = useContext(StoreContext);
31
+ if (store === null) {
32
+ throw new Error("Direct hooks require their matching Direct Provider");
33
+ }
34
+ return store;
35
+ };
36
+
37
+ const useSnapshot = (): DirectStoreSnapshot<World> => {
38
+ const store = useStore();
39
+ return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
40
+ };
41
+
42
+ const bindings: DirectReactBindings<World> = {
43
+ Context: StoreContext,
44
+ Provider: ({ store, children }: DirectProviderProps<World>) => createElement(
45
+ StoreContext.Provider,
46
+ { value: store },
47
+ children,
48
+ ),
49
+ useStore,
50
+ useSnapshot,
51
+ useWorld: () => useSnapshot().world,
52
+ };
53
+ return Object.freeze(bindings);
54
+ }
@@ -0,0 +1,228 @@
1
+ import type { JsonValue } from "../core/json-value.js";
2
+ import type { LogicalRuntime } from "../core/runtime.js";
3
+ import type {
4
+ DirectStore,
5
+ StoreError,
6
+ StoreGeneration,
7
+ } from "../core/store.js";
8
+ import type { OperationId } from "../core/ids.js";
9
+ import { renderUnknownReason } from "../core/reason.js";
10
+ import { err, ok, type Result } from "../core/result.js";
11
+
12
+ export type DirectActivityScopeError =
13
+ | {
14
+ readonly code: "scope-closed";
15
+ readonly message: string;
16
+ readonly operation: null;
17
+ readonly storeError: null;
18
+ readonly reason: null;
19
+ }
20
+ | {
21
+ readonly code: "operation-id-failed";
22
+ readonly message: string;
23
+ readonly operation: null;
24
+ readonly storeError: null;
25
+ readonly reason: unknown;
26
+ }
27
+ | {
28
+ readonly code: "store-begin-failed" | "store-settle-failed";
29
+ readonly message: string;
30
+ readonly operation: OperationId;
31
+ readonly storeError: StoreError;
32
+ readonly reason: null;
33
+ };
34
+
35
+ export type DirectActivityRunError =
36
+ | {
37
+ readonly code: "begin-failed";
38
+ readonly message: string;
39
+ readonly operation: null;
40
+ readonly workError: null;
41
+ readonly activityError: DirectActivityScopeError;
42
+ }
43
+ | {
44
+ readonly code: "work-failed";
45
+ readonly message: string;
46
+ readonly operation: OperationId;
47
+ readonly workError: unknown;
48
+ readonly activityError: null;
49
+ }
50
+ | {
51
+ readonly code: "settlement-failed";
52
+ readonly message: string;
53
+ readonly operation: OperationId;
54
+ readonly workError: null;
55
+ readonly activityError: DirectActivityScopeError;
56
+ }
57
+ | {
58
+ readonly code: "work-and-settlement-failed";
59
+ readonly message: string;
60
+ readonly operation: OperationId;
61
+ readonly workError: unknown;
62
+ readonly activityError: DirectActivityScopeError;
63
+ };
64
+
65
+ export interface DirectActivityLease {
66
+ readonly generation: StoreGeneration;
67
+ readonly operation: OperationId;
68
+ /** Settle once. Later calls return the first settlement result unchanged. */
69
+ readonly release: () => Result<true, DirectActivityScopeError>;
70
+ readonly isReleased: () => boolean;
71
+ }
72
+
73
+ export interface DirectActivityScope {
74
+ readonly begin: (namespace?: string) => Result<DirectActivityLease, DirectActivityScopeError>;
75
+ readonly run: <Value>(
76
+ namespace: string,
77
+ work: () => Value | PromiseLike<Value>,
78
+ ) => Promise<Result<Value, DirectActivityRunError>>;
79
+ }
80
+
81
+ export interface DirectActivityScopeOptions {
82
+ /** Fence new activity once the owning composition has been aborted. */
83
+ readonly signal?: AbortSignal;
84
+ }
85
+
86
+ function storeErrorMessage(cause: StoreError): string {
87
+ return renderUnknownReason(cause, "Direct store operation failed");
88
+ }
89
+
90
+ function operationError(reason: unknown): DirectActivityScopeError {
91
+ return Object.freeze({
92
+ code: "operation-id-failed",
93
+ message: renderUnknownReason(reason),
94
+ operation: null,
95
+ storeError: null,
96
+ reason,
97
+ });
98
+ }
99
+
100
+ function closedScopeError(): DirectActivityScopeError {
101
+ return Object.freeze({
102
+ code: "scope-closed",
103
+ message: "The Direct activity scope is closed",
104
+ operation: null,
105
+ storeError: null,
106
+ reason: null,
107
+ });
108
+ }
109
+
110
+ function storeError(
111
+ code: "store-begin-failed" | "store-settle-failed",
112
+ operation: OperationId,
113
+ cause: StoreError,
114
+ ): DirectActivityScopeError {
115
+ return Object.freeze({
116
+ code,
117
+ message: storeErrorMessage(cause),
118
+ operation,
119
+ storeError: cause,
120
+ reason: null,
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Couple deterministic operation IDs to the store's generation-fenced activity
126
+ * ledger. A lease owns exactly one settlement attempt, including a failed one.
127
+ */
128
+ export function createDirectActivityScope<World extends JsonValue>(
129
+ store: DirectStore<World>,
130
+ runtime: LogicalRuntime,
131
+ options: DirectActivityScopeOptions = {},
132
+ ): DirectActivityScope {
133
+ const signal = options.signal;
134
+ const isClosed = (): boolean => signal?.aborted === true;
135
+ const begin = (namespace = "activity"): Result<DirectActivityLease, DirectActivityScopeError> => {
136
+ if (isClosed()) return err(closedScopeError());
137
+ let operation: OperationId;
138
+ try {
139
+ operation = runtime.nextOperationId(namespace);
140
+ } catch (reason) {
141
+ return err(operationError(reason));
142
+ }
143
+ if (isClosed()) return err(closedScopeError());
144
+
145
+ const currentGeneration = store.getSnapshot().generation;
146
+ const started = store.beginActivity(currentGeneration, operation);
147
+ if (!started.ok) {
148
+ return err(storeError("store-begin-failed", operation, started.error));
149
+ }
150
+ if (isClosed()) {
151
+ const settled = started.value.settle();
152
+ return settled.ok
153
+ ? err(closedScopeError())
154
+ : err(storeError("store-settle-failed", operation, settled.error));
155
+ }
156
+
157
+ let released = false;
158
+ let releaseResult: Result<true, DirectActivityScopeError> | null = null;
159
+ const lease: DirectActivityLease = Object.freeze({
160
+ generation: currentGeneration,
161
+ operation,
162
+ isReleased: () => released,
163
+ release: () => {
164
+ if (releaseResult !== null) return releaseResult;
165
+ released = true;
166
+ const settled = started.value.settle();
167
+ releaseResult = settled.ok
168
+ ? ok<true>(true)
169
+ : err(storeError("store-settle-failed", operation, settled.error));
170
+ return releaseResult;
171
+ },
172
+ });
173
+ return ok(lease);
174
+ };
175
+
176
+ const run: DirectActivityScope["run"] = async (namespace, work) => {
177
+ const started = begin(namespace);
178
+ if (!started.ok) {
179
+ return err(Object.freeze({
180
+ code: "begin-failed",
181
+ message: started.error.message,
182
+ operation: null,
183
+ workError: null,
184
+ activityError: started.error,
185
+ }));
186
+ }
187
+
188
+ let workResult: Result<Awaited<ReturnType<typeof work>>, unknown>;
189
+ try {
190
+ workResult = ok(await work());
191
+ } catch (reason) {
192
+ workResult = err(reason);
193
+ }
194
+ const released = started.value.release();
195
+
196
+ if (workResult.ok && released.ok) return ok(workResult.value);
197
+ if (!workResult.ok && released.ok) {
198
+ return err(Object.freeze({
199
+ code: "work-failed",
200
+ message: renderUnknownReason(workResult.error),
201
+ operation: started.value.operation,
202
+ workError: workResult.error,
203
+ activityError: null,
204
+ }));
205
+ }
206
+ if (workResult.ok && !released.ok) {
207
+ return err(Object.freeze({
208
+ code: "settlement-failed",
209
+ message: released.error.message,
210
+ operation: started.value.operation,
211
+ workError: null,
212
+ activityError: released.error,
213
+ }));
214
+ }
215
+ if (!workResult.ok && !released.ok) {
216
+ return err(Object.freeze({
217
+ code: "work-and-settlement-failed",
218
+ message: `${renderUnknownReason(workResult.error)}; settlement failed: ${released.error.message}`,
219
+ operation: started.value.operation,
220
+ workError: workResult.error,
221
+ activityError: released.error,
222
+ }));
223
+ }
224
+ throw new Error("Unreachable activity result");
225
+ };
226
+
227
+ return Object.freeze({ begin, run });
228
+ }
@@ -0,0 +1,99 @@
1
+ import {
2
+ createCoverageCatalogSnapshot,
3
+ parseCoverageCatalogSnapshot,
4
+ type CoverageCatalogSnapshot,
5
+ type CoverageEntry,
6
+ type CoverageError,
7
+ } from "../core/coverage.js";
8
+ import type { DirectDefinition } from "../core/definition.js";
9
+ import type { JsonValue } from "../core/json-value.js";
10
+ import { renderUnknownReason } from "../core/reason.js";
11
+ import { err, ok, type Result } from "../core/result.js";
12
+
13
+ export type CoverageBindingError =
14
+ | {
15
+ readonly code: "invalid-coverage";
16
+ readonly message: string;
17
+ readonly coverageError: CoverageError;
18
+ }
19
+ | {
20
+ readonly code: "coverage-mismatch" | "invalid-definition";
21
+ readonly message: string;
22
+ readonly coverageError: null;
23
+ };
24
+
25
+ function sameEntry(
26
+ actual: CoverageEntry,
27
+ expected: CoverageEntry,
28
+ ): boolean {
29
+ if (
30
+ actual.key !== expected.key
31
+ || actual.mode !== expected.mode
32
+ || actual.claim !== expected.claim
33
+ || actual.scenarios.length !== expected.scenarios.length
34
+ ) return false;
35
+ return actual.scenarios.every((scenario, index) => scenario === expected.scenarios[index]);
36
+ }
37
+
38
+ /** Parse a browser value and prove exact equality with an owned expected snapshot. */
39
+ export function parseExpectedCoverageCatalogSnapshot(
40
+ input: unknown,
41
+ expected: CoverageCatalogSnapshot,
42
+ ): Result<CoverageCatalogSnapshot, CoverageBindingError> {
43
+ const parsed = parseCoverageCatalogSnapshot(input);
44
+ if (!parsed.ok) {
45
+ return err(Object.freeze({
46
+ code: "invalid-coverage",
47
+ message: parsed.error.message,
48
+ coverageError: parsed.error,
49
+ }));
50
+ }
51
+
52
+ try {
53
+ if (
54
+ parsed.value.schema !== expected.schema
55
+ || parsed.value.entries.length !== expected.entries.length
56
+ || parsed.value.entries.some((entry, index) => {
57
+ const expectedEntry = expected.entries[index];
58
+ return expectedEntry === undefined || !sameEntry(entry, expectedEntry);
59
+ })
60
+ ) {
61
+ return err(Object.freeze({
62
+ code: "coverage-mismatch",
63
+ message: "Published Direct coverage does not exactly match the authored definition",
64
+ coverageError: null,
65
+ }));
66
+ }
67
+ } catch (reason) {
68
+ return err(Object.freeze({
69
+ code: "invalid-definition",
70
+ message: renderUnknownReason(reason, "Expected Direct coverage could not be inspected"),
71
+ coverageError: null,
72
+ }));
73
+ }
74
+ return ok(expected);
75
+ }
76
+
77
+ /**
78
+ * Parse a browser-published coverage value and prove that it is the exact
79
+ * snapshot authored by the definition running the verifier.
80
+ */
81
+ export function parseDefinitionCoverageSnapshot<
82
+ World extends JsonValue,
83
+ Route extends string,
84
+ >(
85
+ input: unknown,
86
+ definition: Pick<DirectDefinition<World, Route>, "coverage">,
87
+ ): Result<CoverageCatalogSnapshot, CoverageBindingError> {
88
+ let expected: CoverageCatalogSnapshot;
89
+ try {
90
+ expected = createCoverageCatalogSnapshot(definition.coverage);
91
+ } catch (reason) {
92
+ return err(Object.freeze({
93
+ code: "invalid-definition",
94
+ message: renderUnknownReason(reason, "Direct definition coverage could not be inspected"),
95
+ coverageError: null,
96
+ }));
97
+ }
98
+ return parseExpectedCoverageCatalogSnapshot(input, expected);
99
+ }
@@ -0,0 +1,59 @@
1
+ import type { CoverageEntry, CoverageMode } from "../core/coverage.js";
2
+
3
+ export type CoverageEvidenceStatus =
4
+ | "direct-required"
5
+ | "fixture-verified"
6
+ | "not-exercised"
7
+ | "partial"
8
+ | "verified";
9
+
10
+ export type CoverageEvidenceStatusFor<Mode extends CoverageMode> =
11
+ Mode extends "direct"
12
+ ? "direct-required" | "verified"
13
+ : Mode extends "fixture"
14
+ ? "not-exercised" | "partial" | "verified"
15
+ : "fixture-verified" | "not-exercised" | "partial" | "verified";
16
+
17
+ export interface CoverageEvidenceFacts {
18
+ /** Scenario IDs whose product-owned assertions passed in the current evidence set. */
19
+ readonly exercisedScenarios: ReadonlySet<string>;
20
+ /** Whether current direct evidence for the substituted production port passed. */
21
+ readonly directEvidence?: "missing" | "verified";
22
+ }
23
+
24
+ /**
25
+ * Classify claim evidence from its declared proof mode and current facts.
26
+ * Scenario actions and assertions remain product-owned; this function owns only
27
+ * the shared completion taxonomy.
28
+ */
29
+ export function classifyCoverageEvidence<
30
+ Entry extends CoverageEntry,
31
+ >(
32
+ entry: Entry,
33
+ facts: CoverageEvidenceFacts,
34
+ ): CoverageEvidenceStatusFor<Entry["mode"]> {
35
+ const directVerified = facts.directEvidence === "verified";
36
+ if (entry.mode === "direct") {
37
+ return (directVerified ? "verified" : "direct-required") as CoverageEvidenceStatusFor<
38
+ Entry["mode"]
39
+ >;
40
+ }
41
+
42
+ let exercised = 0;
43
+ for (const scenario of entry.scenarios) {
44
+ if (facts.exercisedScenarios.has(scenario)) exercised += 1;
45
+ }
46
+ if (exercised === 0) {
47
+ return (directVerified && entry.mode === "mixed" ? "partial" : "not-exercised") as
48
+ CoverageEvidenceStatusFor<Entry["mode"]>;
49
+ }
50
+ if (exercised < entry.scenarios.length) {
51
+ return "partial" as CoverageEvidenceStatusFor<Entry["mode"]>;
52
+ }
53
+ if (entry.mode === "fixture") {
54
+ return "verified" as CoverageEvidenceStatusFor<Entry["mode"]>;
55
+ }
56
+ return (directVerified ? "verified" : "fixture-verified") as CoverageEvidenceStatusFor<
57
+ Entry["mode"]
58
+ >;
59
+ }
@@ -0,0 +1,22 @@
1
+ import {
2
+ parseCoverageCatalogSnapshot as parseCoverageCatalogSnapshotCore,
3
+ } from "../core/coverage.js";
4
+
5
+ /** Parse an exact coverage snapshot, including `window.__direct.manifest.coverage`. */
6
+ export function parseCoverageCatalogSnapshot(
7
+ input: unknown,
8
+ ): ReturnType<typeof parseCoverageCatalogSnapshotCore> {
9
+ return parseCoverageCatalogSnapshotCore(input);
10
+ }
11
+ export type {
12
+ CoverageCatalogSnapshot,
13
+ CoverageEntry,
14
+ CoverageError,
15
+ } from "../core/coverage.js";
16
+ export * from "./activity.js";
17
+ export * from "./coverage-binding.js";
18
+ export * from "./evidence.js";
19
+ export * from "./manifest.js";
20
+ export * from "./probe.js";
21
+ export * from "./session.js";
22
+ export * from "./scripted-transport.js";