geospec 0.0.0 → 0.1.0-beta.3

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 (100) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +244 -0
  3. package/agent/doctrine.md +55 -0
  4. package/agent/geospec-authoring/SKILL.md +495 -0
  5. package/agent/geospec-authoring/api-classes.md +13 -0
  6. package/agent/geospec-authoring/api-constants.md +16 -0
  7. package/agent/geospec-authoring/api-functions.md +57 -0
  8. package/agent/geospec-authoring/api-index.md +377 -0
  9. package/agent/geospec-authoring/api-types.md +1788 -0
  10. package/agent/geospec-authoring/public-api-classes.md +22 -0
  11. package/agent/geospec-authoring/public-api-constants.md +51 -0
  12. package/agent/geospec-authoring/public-api-functions.md +215 -0
  13. package/agent/geospec-authoring/public-api-index.md +893 -0
  14. package/agent/geospec-authoring/public-api-types-2.md +1560 -0
  15. package/agent/geospec-authoring/public-api-types-3.md +217 -0
  16. package/agent/geospec-authoring/public-api-types.md +1948 -0
  17. package/agent/resources.d.ts +19 -0
  18. package/agent/resources.js +27 -0
  19. package/agent/skills.d.cts +13 -0
  20. package/agent/skills.json +28 -0
  21. package/dist/assertion-client/client.d.mts +134 -0
  22. package/dist/assertion-client/client.mjs +2 -0
  23. package/dist/assertion-client/index.d.mts +5 -0
  24. package/dist/assertion-client/index.mjs +1 -0
  25. package/dist/config/index.d.mts +3 -0
  26. package/dist/config/index.mjs +1 -0
  27. package/dist/config/node/index.d.mts +3 -0
  28. package/dist/config/node/index.mjs +1 -0
  29. package/dist/config/node/load.d.mts +19 -0
  30. package/dist/config/node/load.mjs +1 -0
  31. package/dist/config/tau-project-artifact.d.mts +54 -0
  32. package/dist/config/tau-project-artifact.mjs +3 -0
  33. package/dist/config/types.d.mts +57 -0
  34. package/dist/config/validate.mjs +1 -0
  35. package/dist/create-geospec.d.mts +50 -0
  36. package/dist/create-geospec.mjs +1 -0
  37. package/dist/engine/client.d.mts +113 -0
  38. package/dist/engine/client.mjs +1 -0
  39. package/dist/engine/index.d.mts +3 -0
  40. package/dist/engine/index.mjs +1 -0
  41. package/dist/engine/matchers.d.mts +70 -0
  42. package/dist/engine/matchers.mjs +1 -0
  43. package/dist/engine/pmi.types.d.mts +78 -0
  44. package/dist/engine/protocol.d.mts +20 -0
  45. package/dist/engine/protocol.mjs +1 -0
  46. package/dist/geometry-unit.d.mts +12 -0
  47. package/dist/index.d.mts +6 -0
  48. package/dist/index.mjs +1 -0
  49. package/dist/mesh/index.d.mts +4 -0
  50. package/dist/mesh/index.mjs +1 -0
  51. package/dist/mesh/types.d.mts +575 -0
  52. package/dist/model/errors.d.mts +20 -0
  53. package/dist/model/errors.mjs +2 -0
  54. package/dist/model/export-intent.d.mts +79 -0
  55. package/dist/model/export-intent.mjs +1 -0
  56. package/dist/model/index.d.mts +7 -0
  57. package/dist/model/index.mjs +1 -0
  58. package/dist/model/load-model.d.mts +25 -0
  59. package/dist/model/load-model.mjs +1 -0
  60. package/dist/model/native-model-loader.d.mts +142 -0
  61. package/dist/model/native-model-loader.mjs +1 -0
  62. package/dist/model/region-scope.d.mts +23 -0
  63. package/dist/model/region-scope.mjs +1 -0
  64. package/dist/model/subject-assertions.mjs +1 -0
  65. package/dist/model/subject.d.mts +11 -0
  66. package/dist/model/subject.mjs +1 -0
  67. package/dist/model/types.d.mts +254 -0
  68. package/dist/runner/collector.d.mts +64 -0
  69. package/dist/runner/collector.mjs +2 -0
  70. package/dist/runner/discovery.d.mts +93 -0
  71. package/dist/runner/discovery.mjs +1 -0
  72. package/dist/runner/filter.d.mts +50 -0
  73. package/dist/runner/filter.mjs +1 -0
  74. package/dist/runner/index.d.mts +7 -0
  75. package/dist/runner/index.mjs +1 -0
  76. package/dist/runner/native/index.d.mts +4 -0
  77. package/dist/runner/native/index.mjs +1 -0
  78. package/dist/runner/native/native-pool-grants.d.mts +21 -0
  79. package/dist/runner/native/native-pool-grants.mjs +1 -0
  80. package/dist/runner/native/native-serial-runner.d.mts +29 -0
  81. package/dist/runner/native/native-serial-runner.mjs +1 -0
  82. package/dist/runner/pool/pool-messages.d.mts +94 -0
  83. package/dist/runner/run-geospec-module.d.mts +13 -0
  84. package/dist/runner/run-geospec-module.mjs +47 -0
  85. package/dist/runner/timeout-codes.d.mts +45 -0
  86. package/dist/runner/timeout-codes.mjs +1 -0
  87. package/dist/runner/types.d.mts +776 -0
  88. package/dist/runner/worker/index.d.mts +4 -0
  89. package/dist/runner/worker/index.mjs +1 -0
  90. package/dist/runner/worker/no-matching-tests-issue.d.mts +12 -0
  91. package/dist/runner/worker/no-matching-tests-issue.mjs +1 -0
  92. package/dist/runner/worker/runner-types.d.mts +167 -0
  93. package/dist/runner/worker/serial-runner.mjs +1 -0
  94. package/dist/selector/types.d.mts +271 -0
  95. package/dist/step/types.d.mts +134 -0
  96. package/dist/vitest/adapter.d.mts +56 -0
  97. package/dist/vitest/adapter.mjs +3 -0
  98. package/dist/vitest/index.d.mts +4 -0
  99. package/dist/vitest/index.mjs +1 -0
  100. package/package.json +114 -5
@@ -0,0 +1,4 @@
1
+ import { createNoMatchingGeoSpecTestsIssue } from "./no-matching-tests-issue.mjs";
2
+ import { GeoSpecPoolHostMessage, GeoSpecPoolShard, GeoSpecPoolWorkerHandle, GeoSpecPoolWorkerMessage } from "../pool/pool-messages.mjs";
3
+ import { GeoSpecForensicEvent, GeoSpecRunner, GeoSpecRunnerEvent, GeoSpecRunnerFileResult, GeoSpecRunnerOptions, GeoSpecRunnerResult, GeoSpecRunnerRunOptions } from "./runner-types.mjs";
4
+ export { type GeoSpecForensicEvent, type GeoSpecPoolHostMessage, type GeoSpecPoolShard, type GeoSpecPoolWorkerHandle, type GeoSpecPoolWorkerMessage, type GeoSpecRunner, type GeoSpecRunnerEvent, type GeoSpecRunnerFileResult, type GeoSpecRunnerOptions, type GeoSpecRunnerResult, type GeoSpecRunnerRunOptions, createNoMatchingGeoSpecTestsIssue };
@@ -0,0 +1 @@
1
+ import{createNoMatchingGeoSpecTestsIssue as e}from"./no-matching-tests-issue.mjs";export{e as createNoMatchingGeoSpecTestsIssue};
@@ -0,0 +1,12 @@
1
+ import { VmIssue } from "@taucad/esbuild/vm";
2
+ //#region src/runner/worker/no-matching-tests-issue.d.ts
3
+ /**
4
+ * Create a run-level issue when filters select no tests.
5
+ *
6
+ * @returns A structured VM issue for empty GeoSpec filter selections.
7
+ *
8
+ * @public
9
+ */
10
+ declare const createNoMatchingGeoSpecTestsIssue: () => VmIssue;
11
+ //#endregion
12
+ export { createNoMatchingGeoSpecTestsIssue };
@@ -0,0 +1 @@
1
+ const e=()=>({code:`NO_MATCHING_GEOSPEC_TESTS`,message:`No matching GeoSpec tests were selected by the supplied filters.`,severity:`error`,type:`runtime`});export{e as createNoMatchingGeoSpecTestsIssue};
@@ -0,0 +1,167 @@
1
+ import { ManagedGeoSpecNativeModelLoader } from "../../model/native-model-loader.mjs";
2
+ import { GeoSpecRunResult, GeoSpecTestAccounting, GeoSpecTestCase, RunGeoSpecModuleOptions } from "../types.mjs";
3
+ import { VmFileSystem, VmIssue } from "@taucad/esbuild/vm";
4
+ //#region src/runner/worker/runner-types.d.ts
5
+ /**
6
+ * One GeoSpec test file executed by a worker-style runner.
7
+ *
8
+ * @public
9
+ */
10
+ type GeoSpecRunnerFileResult = {
11
+ /** Absolute or project-relative GeoSpec test file path supplied to the runner. */
12
+ file: string;
13
+ /** Low-level module execution result for this file. */
14
+ result: GeoSpecRunResult;
15
+ /** Wall-clock cost of executing this file, in milliseconds (R1). */
16
+ durationMs?: number;
17
+ /** First deterministic model-load cache key observed in this file (R9 affinity telemetry). */
18
+ primaryLoadKey?: string;
19
+ /** Executing worker's isolate-resident memory at file completion, in bytes (R15 memory-class telemetry). */
20
+ workerMemoryBytes?: number;
21
+ };
22
+ /**
23
+ * Aggregate result returned by GeoSpec worker-style runners.
24
+ *
25
+ * @public
26
+ */
27
+ type GeoSpecRunnerResult = {
28
+ /** True when no files or tests failed and at least one test was selected. */
29
+ success: boolean;
30
+ /** Number of non-skipped tests that passed. */
31
+ passed: number;
32
+ /** Number of file-level or test-level failures. */
33
+ failed: number;
34
+ /** Number of collected tests after filters were applied. */
35
+ selectedTests: number;
36
+ /** Per-file module execution results. */
37
+ files: GeoSpecRunnerFileResult[];
38
+ /** Run-level issues such as aborts or empty filter selections. */
39
+ issues?: VmIssue[];
40
+ /** Wall-clock cost of the whole run, in milliseconds (R1). */
41
+ durationMs?: number;
42
+ /** Complete requested-file accounting; discovery may remain unknown in unstarted or broken modules. */
43
+ accounting?: GeoSpecRunnerAccounting;
44
+ /** Coherence of the consumed source graphs, not a geometry verdict. */
45
+ lineageStatus?: 'complete' | 'unavailable' | 'mixed';
46
+ };
47
+ /** File and observed-test accounting for a worker run. @public */
48
+ type GeoSpecRunnerAccounting = GeoSpecTestAccounting & {
49
+ requestedFiles: readonly string[];
50
+ completedFiles: readonly string[];
51
+ notRunFiles: readonly string[];
52
+ discoveryComplete: boolean;
53
+ cancelled: boolean;
54
+ bailed: boolean;
55
+ };
56
+ /** Identity of a test that has started but not settled. @public */
57
+ type GeoSpecRunnerTestRef = {
58
+ readonly suite: readonly string[];
59
+ readonly name: string;
60
+ readonly ordinal?: number;
61
+ };
62
+ /**
63
+ * Lifecycle event emitted by GeoSpec worker-style runners. Test events are
64
+ * emitted by in-process runners; a pool reports per file.
65
+ *
66
+ * @public
67
+ */
68
+ type GeoSpecRunnerEvent = {
69
+ type: 'run-start';
70
+ files: readonly string[];
71
+ } | {
72
+ type: 'file-start';
73
+ file: string;
74
+ } | {
75
+ type: 'test-start';
76
+ file: string;
77
+ test: GeoSpecRunnerTestRef;
78
+ } | {
79
+ type: 'test-complete';
80
+ file: string;
81
+ test: GeoSpecTestCase;
82
+ } | {
83
+ type: 'file-complete';
84
+ file: string;
85
+ result: GeoSpecRunResult;
86
+ durationMs?: number;
87
+ primaryLoadKey?: string;
88
+ workerMemoryBytes?: number;
89
+ } | {
90
+ type: 'run-complete';
91
+ result: GeoSpecRunnerResult;
92
+ } | GeoSpecForensicEvent | {
93
+ type: 'abort';
94
+ reason?: string;
95
+ } | {
96
+ type: 'close';
97
+ };
98
+ /** One structured forensic measurement emitted by a runner. @public */
99
+ type GeoSpecForensicEvent = {
100
+ type: 'forensic';
101
+ name: string;
102
+ value: number;
103
+ unit: 'milliseconds' | 'count';
104
+ shardId?: number;
105
+ };
106
+ /**
107
+ * Options accepted by a GeoSpec worker-style runner run.
108
+ *
109
+ * @public
110
+ */
111
+ type GeoSpecRunnerRunOptions = {
112
+ /** GeoSpec test files to execute. Files run serially by default. */
113
+ files: readonly string[];
114
+ /** JavaScript regular expression matched against full `suite > test` names. */
115
+ testNamePattern?: string | RegExp;
116
+ /** Timeout for each async test callback, in milliseconds. */
117
+ testTimeout?: number;
118
+ /** Non-verdict matcher wall backstop. Milliseconds. */
119
+ matcherWallBackstop?: number;
120
+ /**
121
+ * Engine work-unit budget for this run's claims, replacing the runner's
122
+ * `nativeAssertions.workUnitLimit`. A `loadModel` or `expectGeo` budget still
123
+ * wins for its own claims.
124
+ */
125
+ workUnitLimit?: number;
126
+ /** Emit structured forensic measurements for this run. */
127
+ forensic?: boolean;
128
+ /**
129
+ * Stop after the first failing file (R1). Interactive fail-fast only —
130
+ * never the default for reward runs, which want the complete red set.
131
+ */
132
+ bail?: boolean;
133
+ };
134
+ /**
135
+ * Shared options for GeoSpec runner factories.
136
+ *
137
+ * @public
138
+ */
139
+ type GeoSpecRunnerOptions = {
140
+ /** Filesystem containing the project and test modules. */
141
+ filesystem: VmFileSystem;
142
+ /** Protocol-3 assertion client shared by every authored assertion and model admission. */
143
+ nativeAssertions: RunGeoSpecModuleOptions['nativeAssertions'];
144
+ /** Managed native model loader released after each settled run. */
145
+ nativeModelLoader?: ManagedGeoSpecNativeModelLoader;
146
+ /** Additional in-memory modules made available to the VM. */
147
+ builtinModules?: RunGeoSpecModuleOptions['builtinModules'];
148
+ };
149
+ /**
150
+ * Public GeoSpec runner lifecycle surface.
151
+ *
152
+ * @public
153
+ */
154
+ type GeoSpecRunner = {
155
+ /** Execute GeoSpec files and return a compact aggregate result. */
156
+ run(options: GeoSpecRunnerRunOptions): Promise<GeoSpecRunnerResult>;
157
+ /** Subscribe to one lifecycle event type. */
158
+ on<Type extends GeoSpecRunnerEvent['type']>(event: Type, handler: (event: Extract<GeoSpecRunnerEvent, {
159
+ type: Type;
160
+ }>) => void): () => void;
161
+ /** Request cooperative abort before the next file starts. */
162
+ abort(reason?: string): void;
163
+ /** Close the runner and release owned resources. */
164
+ close(): Promise<void>;
165
+ };
166
+ //#endregion
167
+ export { GeoSpecForensicEvent, GeoSpecRunner, GeoSpecRunnerAccounting, GeoSpecRunnerEvent, GeoSpecRunnerFileResult, GeoSpecRunnerOptions, GeoSpecRunnerResult, GeoSpecRunnerRunOptions, GeoSpecRunnerTestRef };
@@ -0,0 +1 @@
1
+ import{runGeoSpecModule as e}from"../run-geospec-module.mjs";import{createNoMatchingGeoSpecTestsIssue as t}from"./no-matching-tests-issue.mjs";const n=()=>({code:`GEOSPEC_RUNNER_CLOSED`,message:`GeoSpec runner is closed.`,severity:`error`,type:`runtime`}),r=()=>({code:`GEOSPEC_RUNNER_ACTIVE`,message:`GeoSpec runner already has an active run.`,severity:`error`,type:`runtime`}),i=e=>({code:`GEOSPEC_RUNNER_ABORTED`,message:e?`GeoSpec run aborted: ${e}`:`GeoSpec run aborted.`,severity:`error`,type:`runtime`}),a=e=>({code:`GEOSPEC_RUNNER_BAILED`,message:`GeoSpec run stopped after first failure (--bail): ${e}. Remaining files were not executed.`,severity:`error`,type:`runtime`}),o=e=>{let t=0,n=0;for(let r of e)r.status!==`skipped`&&(r.status===`failed`?n+=1:r.status===`passed`&&(t+=1));return{passed:t,failed:n}},s=s=>{let c={closed:!1},l=new Set,u,d,f=new Map,p=e=>{for(let t of l)t(e)},m=()=>c.aborted,h=e=>({requestedFiles:[...e],completedFiles:[],notRunFiles:[...e],discoveryComplete:!1,discovered:0,selected:0,completed:0,passed:0,failed:0,unsupported:0,inconclusive:0,skipped:0,notRun:0,cancelled:!1,bailed:!1}),g=(e,t)=>({success:!1,passed:0,failed:1,selectedTests:0,files:[],issues:[e],accounting:h(t),lineageStatus:`unavailable`}),_=async n=>{let r=[...n.files],c=performance.now();p({type:`run-start`,files:r});let l=!1,u=async()=>{l||(l=!0,await s.nativeModelLoader?.releaseAll())},d=0,g=0,_=0,v=[],y=[],b=h(r),x=!0,S=`complete`,C=new Map;try{for(let t of r){let c=m();if(c!==void 0){let e=i(c);y.push(e),g+=1,p({type:`abort`,reason:c}),b.cancelled=!0,x=!1;break}p({type:`file-start`,file:t});let l=performance.now(),u=await e({filesystem:s.filesystem,entryPath:t,testNamePattern:n.testNamePattern,testTimeout:n.testTimeout,matcherWallBackstop:n.matcherWallBackstop,forensic:n.forensic,onTestEvent:e=>{p(e.type===`test-start`?{type:`test-start`,file:t,test:{suite:[...e.test.suite],name:e.test.name,...e.test.ordinal===void 0?{}:{ordinal:e.test.ordinal}}}:{type:`test-complete`,file:t,test:e.test})},bundleCache:f,nativeAssertions:n.workUnitLimit===void 0?s.nativeAssertions:{...s.nativeAssertions,workUnitLimit:n.workUnitLimit},...s.nativeModelLoader?{nativeModelLoader:s.nativeModelLoader}:{},...s.builtinModules?{builtinModules:s.builtinModules}:{}}).catch(e=>({success:!1,issues:[{code:`GEOSPEC_MODULE_INTERRUPTED`,message:e instanceof Error?e.message:String(e),severity:`error`,type:`runtime`}]})),h=performance.now()-l;p({type:`file-complete`,file:t,result:u,durationMs:h}),v.push({file:t,result:u,durationMs:h}),b.completedFiles=v.map(e=>e.file),b.notRunFiles=r.slice(v.length),x&&=u.success&&u.passed,u.lineage===void 0||u.lineage.status===`unavailable`?S!==`mixed`&&(S=`unavailable`):u.lineage.status===`mixed`&&(S=`mixed`);let w=u.lineage?.loads.flatMap(e=>{let{evidence:t}=e,n=t?.artifacts[0];return t?.exportOptions===void 0?[...(t?.artifacts??[]).flatMap(e=>e.sourcePath===void 0?[]:[{[e.sourcePath]:`sha256:${e.sha256}`}]),...t?.sourcePath===void 0||n===void 0?[]:[{[t.sourcePath]:`sha256:${n.sha256}`}]]:[]})??[];for(let e of[...u.lineage?.modules.map(e=>e.files)??[],...w,...u.lineage?.loads.map(e=>e.evidence?.sourceRevision?.files??{})??[]])for(let[t,n]of Object.entries(e))C.has(t)&&C.get(t)!==n&&(S=`mixed`),C.set(t,n);if(u.accounting!==void 0)for(let e of[`discovered`,`selected`,`completed`,`passed`,`failed`,`unsupported`,`inconclusive`,`skipped`,`notRun`])b[e]+=u.accounting[e];if(u.success){_+=u.tests.length;let e=o(u.tests);d+=e.passed,g+=e.failed}else g+=1;if(n.bail===!0&&(!x||g>0)){y.push(a(t)),b.bailed=!0;break}}_===0&&g===0&&(y.push(t()),g+=1);try{await u()}catch(e){y.push({code:`GEOSPEC_NATIVE_CLEANUP_FAILED`,message:e instanceof Error?e.message:String(e),severity:`error`,type:`runtime`}),x=!1}b.discoveryComplete=b.notRunFiles.length===0&&v.every(e=>e.result.success&&e.result.accounting!==void 0);let l={success:x&&S===`complete`&&g===0&&y.length===0,passed:d,failed:g,selectedTests:_,files:v,...y.length>0?{issues:y}:{},durationMs:performance.now()-c,accounting:b,lineageStatus:S};return p({type:`run-complete`,result:l}),l}finally{await u()}};return{async run(e){if(new Set(e.files).size!==e.files.length)return g({code:`GEOSPEC_DUPLICATE_FILES`,message:`GeoSpec requested files must be unique.`,severity:`error`,type:`runtime`},e.files);if(c.closed)return g(n(),e.files);if(u!==void 0)return g(r(),e.files);delete c.aborted;let t=()=>void 0,i=new Promise(e=>{t=e});u=i;try{return await _(e)}finally{t(),u===i&&(u=void 0)}},on(e,t){let n=n=>{n.type===e&&t(n)};return l.add(n),()=>l.delete(n)},abort(e){c.aborted=e??`requested`},async close(){d===void 0&&(c.closed=!0,c.aborted??=`runner closed`,d=(async()=>{await u,f.clear(),p({type:`close`})})()),await d}}};export{o as countRunnerTests,s as createSerialGeoSpecRunner};
@@ -0,0 +1,271 @@
1
+ import { Vec3 } from "../mesh/types.mjs";
2
+ //#region src/selector/types.d.ts
3
+ /**
4
+ * Surface classification carried by selector face facts, matching the
5
+ * verification kernel's `faceFacts` payload vocabulary.
6
+ *
7
+ * @public
8
+ */
9
+ type SelectorSurfaceType = 'plane' | 'cylinder' | 'cone' | 'sphere' | 'torus' | 'bspline' | 'other';
10
+ /**
11
+ * Inclusive numeric band. A bare number matches within the linear tolerance.
12
+ *
13
+ * @public
14
+ */
15
+ type NumericRange = number | {
16
+ min?: number;
17
+ max?: number;
18
+ };
19
+ /**
20
+ * Cartesian coordinate record used by coordinate-band (`near`) predicates.
21
+ *
22
+ * @public
23
+ */
24
+ type Vec3Record = {
25
+ x: number;
26
+ y: number;
27
+ z: number;
28
+ };
29
+ /**
30
+ * Cardinality expectation for a selector resolution (master catalog G7).
31
+ * `'one'` is the default for relationship endpoints; `'many'` for groups.
32
+ *
33
+ * @public
34
+ */
35
+ type Cardinality = 'one' | 'many' | {
36
+ exactly: number;
37
+ } | {
38
+ atLeast: number;
39
+ };
40
+ /**
41
+ * Direction predicate with optional angular tolerance in degrees.
42
+ *
43
+ * @public
44
+ */
45
+ type DirectionPredicate = {
46
+ direction: Vec3;
47
+ angularToleranceDegrees?: number;
48
+ };
49
+ /**
50
+ * Ray probe predicate (world-space origin and direction, millimetres).
51
+ *
52
+ * @public
53
+ */
54
+ type RayPredicate = {
55
+ origin: Vec3;
56
+ direction: Vec3;
57
+ };
58
+ /**
59
+ * Face query predicates (master catalog G1/G2): geometric fact predicates,
60
+ * world-space probes, scoping, ordering with deterministic pick, and set
61
+ * algebra. All tolerances default to the shared tolerance contract.
62
+ *
63
+ * @public
64
+ */
65
+ type FaceQuery = {
66
+ surfaceType?: SelectorSurfaceType;
67
+ /** Face normal parallelism (planar faces). */
68
+ normal?: DirectionPredicate;
69
+ /** Rotation-axis parallelism (cylindrical/conical faces). */
70
+ axis?: DirectionPredicate;
71
+ radius?: NumericRange;
72
+ area?: NumericRange;
73
+ /** Plane offset band: signed distance of the plane from the origin. */
74
+ offset?: NumericRange;
75
+ /** Centroid coordinate bands, per-axis. */
76
+ near?: Partial<Vec3Record> & {
77
+ tolerance?: number;
78
+ };
79
+ /** Probe: point lying on the face surface (bounds + analytic residual). */
80
+ containsPoint?: Vec3;
81
+ /** Probe: face whose centroid is nearest to the point; ties are ambiguous. */
82
+ nearestTo?: Vec3;
83
+ /** Probe: first face hit by the ray (analytic plane/cylinder only in V1). */
84
+ hitByRay?: RayPredicate;
85
+ /** Restrict candidates to entities resolved by another selector. */
86
+ within?: GeometrySelector;
87
+ /** Deterministic ordering; `offsetAlong` projects centroids on `along`. */
88
+ orderBy?: 'area' | 'radius' | 'offsetAlong';
89
+ /** Projection direction for `orderBy: 'offsetAlong'`. */
90
+ along?: Vec3;
91
+ /** Deterministic pick after ordering: `'first' | 'last'` or 0-based index. */
92
+ pick?: 'first' | 'last' | number;
93
+ allOf?: FaceQuery[];
94
+ anyOf?: FaceQuery[];
95
+ not?: FaceQuery;
96
+ };
97
+ /**
98
+ * Axis query predicates over cylindrical/conical face facts.
99
+ *
100
+ * @public
101
+ */
102
+ type AxisQuery = {
103
+ /** Axis direction parallelism. */
104
+ axis?: DirectionPredicate;
105
+ radius?: NumericRange;
106
+ near?: Partial<Vec3Record> & {
107
+ tolerance?: number;
108
+ };
109
+ containsPoint?: Vec3;
110
+ nearestTo?: Vec3;
111
+ within?: GeometrySelector;
112
+ orderBy?: 'radius' | 'offsetAlong';
113
+ along?: Vec3;
114
+ pick?: 'first' | 'last' | number;
115
+ allOf?: AxisQuery[];
116
+ anyOf?: AxisQuery[];
117
+ not?: AxisQuery;
118
+ };
119
+ /**
120
+ * Plane query predicates over planar face facts.
121
+ *
122
+ * @public
123
+ */
124
+ type PlaneQuery = {
125
+ normal?: DirectionPredicate;
126
+ offset?: NumericRange;
127
+ area?: NumericRange;
128
+ near?: Partial<Vec3Record> & {
129
+ tolerance?: number;
130
+ };
131
+ containsPoint?: Vec3;
132
+ nearestTo?: Vec3;
133
+ within?: GeometrySelector;
134
+ orderBy?: 'area' | 'offsetAlong';
135
+ along?: Vec3;
136
+ pick?: 'first' | 'last' | number;
137
+ allOf?: PlaneQuery[];
138
+ anyOf?: PlaneQuery[];
139
+ not?: PlaneQuery;
140
+ };
141
+ /**
142
+ * Body query predicates over available source facts. The STEP index currently
143
+ * exposes per-occurrence solid aggregates. Qualified mesh Bodies are material
144
+ * roots, including their cavities; disconnected roots and cavity islands stay
145
+ * separate. Mesh measure, probe and ordering predicates without the required
146
+ * facts refuse, including inside boolean queries.
147
+ *
148
+ * @public
149
+ */
150
+ type BodyQuery = {
151
+ area?: NumericRange;
152
+ near?: Partial<Vec3Record> & {
153
+ tolerance?: number;
154
+ };
155
+ nearestTo?: Vec3;
156
+ within?: GeometrySelector;
157
+ orderBy?: 'area' | 'offsetAlong';
158
+ along?: Vec3;
159
+ pick?: 'first' | 'last' | number;
160
+ allOf?: BodyQuery[];
161
+ anyOf?: BodyQuery[];
162
+ not?: BodyQuery;
163
+ };
164
+ /**
165
+ * Occurrence selector: a placed instance in the assembly tree.
166
+ *
167
+ * @public
168
+ */
169
+ type OccurrenceSelector = {
170
+ kind: 'occurrence';
171
+ /** Product or instance name to match. */
172
+ name?: string | RegExp;
173
+ /** Occurrence path (dot-joined instance segments, root omitted) to match. */
174
+ path?: string | RegExp;
175
+ expect?: Cardinality;
176
+ };
177
+ /**
178
+ * Body selector over source-backed solid evidence. Qualified mesh input exposes
179
+ * one material root with its cavities; the STEP index currently exposes one
180
+ * solid aggregate per occurrence. These are not interchangeable body counts.
181
+ *
182
+ * @public
183
+ */
184
+ type BodySelector = {
185
+ kind: 'body';
186
+ /** STEP occurrence scope, or the exact retained mesh primitive label including any ordinal suffix. */
187
+ of?: string | RegExp;
188
+ query?: BodyQuery;
189
+ expect?: Cardinality;
190
+ };
191
+ /**
192
+ * Face selector resolved via query/probe predicates.
193
+ *
194
+ * @public
195
+ */
196
+ type FaceSelector = {
197
+ kind: 'face';
198
+ of?: string | RegExp;
199
+ query?: FaceQuery;
200
+ expect?: Cardinality;
201
+ };
202
+ /**
203
+ * Axis selector resolved from cylindrical/conical face facts.
204
+ *
205
+ * @public
206
+ */
207
+ type AxisSelector = {
208
+ kind: 'axis';
209
+ of?: string | RegExp;
210
+ query?: AxisQuery;
211
+ expect?: Cardinality;
212
+ };
213
+ /**
214
+ * Plane selector resolved from planar face facts.
215
+ *
216
+ * @public
217
+ */
218
+ type PlaneSelector = {
219
+ kind: 'plane';
220
+ of?: string | RegExp;
221
+ query?: PlaneQuery;
222
+ expect?: Cardinality;
223
+ };
224
+ /**
225
+ * Datum selector: a named coordinate frame authored as a native AP242 datum
226
+ * placement.
227
+ *
228
+ * @public
229
+ */
230
+ type DatumSelector = {
231
+ kind: 'datum';
232
+ /** Full datum name, or part-relative name when `of` scopes an occurrence. */
233
+ name: string;
234
+ of?: string | RegExp;
235
+ expect?: Cardinality;
236
+ };
237
+ /**
238
+ * Interface selector: an authored named interface transported as a STEP
239
+ * `SHAPE_ASPECT` subshape name — the production-preferred selector.
240
+ *
241
+ * @public
242
+ */
243
+ type InterfaceSelector = {
244
+ kind: 'interface';
245
+ /** Full interface name, or part-relative name when `of` scopes an occurrence. */
246
+ name: string;
247
+ of?: string | RegExp;
248
+ expect?: Cardinality;
249
+ };
250
+ /**
251
+ * Group selector: an ordered shared-name family (`bore[1]`…`bore[N]`).
252
+ *
253
+ * @public
254
+ */
255
+ type GroupSelector = {
256
+ kind: 'group';
257
+ /** Full group prefix, or part-relative prefix when `of` scopes an occurrence. */
258
+ name: string;
259
+ of?: string | RegExp;
260
+ expect?: Cardinality;
261
+ };
262
+ /**
263
+ * The V1 geometry selector union (D4 scope). Strings are shorthand: authored
264
+ * paths (`'block.deck.left'`, `'headL.boltHole[*]'`) or snapshot topology
265
+ * refs (`'#o1.2.f7'`, always `stability: 'derived-ordinal'`).
266
+ *
267
+ * @public
268
+ */
269
+ type GeometrySelector = string | OccurrenceSelector | BodySelector | FaceSelector | AxisSelector | PlaneSelector | DatumSelector | InterfaceSelector | GroupSelector;
270
+ //#endregion
271
+ export { AxisQuery, AxisSelector, BodyQuery, BodySelector, Cardinality, DatumSelector, DirectionPredicate, FaceQuery, FaceSelector, GeometrySelector, GroupSelector, InterfaceSelector, NumericRange, OccurrenceSelector, PlaneQuery, PlaneSelector, RayPredicate, SelectorSurfaceType, Vec3Record };
@@ -0,0 +1,134 @@
1
+ //#region src/step/types.d.ts
2
+ /**
3
+ * STEP source and AP242 structure types shared by model loading and subject evidence.
4
+ *
5
+ * @module
6
+ */
7
+ /**
8
+ * STEP source forms accepted by `loadModel`.
9
+ *
10
+ * @public
11
+ */
12
+ type StepSource = string | URL | Uint8Array<ArrayBuffer> | ArrayBuffer | Blob | File | ReadableStream<Uint8Array<ArrayBuffer>> | AsyncIterable<Uint8Array<ArrayBuffer>>;
13
+ /**
14
+ * STEP reader strategy used by GeoSpec model loading.
15
+ *
16
+ * @public
17
+ */
18
+ type StepStreamingMode = 'auto' | 'native-stream' | 'filesystem';
19
+ /**
20
+ * One placed occurrence recovered from an AP242 STEP structure read.
21
+ *
22
+ * `path` is dot-joined instance-name segments from the root (root omitted) per
23
+ * the GeoSpec AP242 profile; repeated names under one parent are disambiguated
24
+ * `name[k]` in the parent's stored component order.
25
+ *
26
+ * @public
27
+ */
28
+ type XdeOccurrence = {
29
+ path: string;
30
+ productName: string;
31
+ instanceName?: string;
32
+ /** 4x4 row-major placement transform (part-local frame -> subject frame). */
33
+ transform: number[];
34
+ /** Index into the native result's retained shape table (proof calls use it). */
35
+ shapeIndex: number;
36
+ /** Analytic axis-aligned bounds of the placed occurrence in subject space. */
37
+ bounds?: {
38
+ min: [number, number, number];
39
+ max: [number, number, number];
40
+ };
41
+ };
42
+ /**
43
+ * One part-relative authored subshape name, expanded per occurrence of the
44
+ * owning product (full selector name = `${occurrencePath}.${name}`).
45
+ *
46
+ * @public
47
+ */
48
+ type XdeSubshapeName = {
49
+ occurrencePath: string;
50
+ name: string;
51
+ shapeType: 'face' | 'edge' | 'vertex' | 'solid';
52
+ /** Index within the owning product shape's deterministic face traversal order. */
53
+ faceIndex: number;
54
+ };
55
+ /**
56
+ * One native AP242 datum placement row (a coordinate *frame* from the
57
+ * supplemental-geometry channel), expanded per occurrence like subshape names
58
+ * and expressed in subject-frame coordinates.
59
+ *
60
+ * Distinct from {@link XdeSemanticDatum}: this is supplemental geometry
61
+ * (`AXIS2_PLACEMENT_3D` items in a CONSTRUCTIVE_GEOMETRY_REPRESENTATION), not
62
+ * the GD&T `DATUM` family.
63
+ *
64
+ * @public
65
+ */
66
+ type XdeDatumPlacement = {
67
+ occurrencePath: string;
68
+ name: string;
69
+ origin: [number, number, number];
70
+ xAxis: [number, number, number];
71
+ zAxis: [number, number, number];
72
+ };
73
+ /**
74
+ * One semantic GD&T datum (`DATUM` + `DATUM_FEATURE` family) recovered from an
75
+ * AP242 file, attached to product faces via GEOMETRIC_ITEM_SPECIFIC_USAGE and
76
+ * expanded per occurrence of the owning product.
77
+ *
78
+ * @public
79
+ */
80
+ type XdeSemanticDatum = {
81
+ occurrencePath: string;
82
+ /** The GD&T datum identification letter(s): 'A', 'B', … */
83
+ label: string;
84
+ /** DATUM_FEATURE name when the file authored one. */
85
+ featureName?: string;
86
+ /** Attached faces in the owning product's deterministic face traversal order. */
87
+ faceIndexes: number[];
88
+ };
89
+ /**
90
+ * One GD&T datum reference frame (`DATUM_SYSTEM`) with its precedence
91
+ * compartments, expanded per occurrence of the owning product.
92
+ *
93
+ * @public
94
+ */
95
+ type XdeDatumSystem = {
96
+ occurrencePath: string;
97
+ name: string;
98
+ /** Compartments in precedence order; each holds one or more datum labels (common datums). */
99
+ references: string[][];
100
+ };
101
+ /**
102
+ * One supplemental-geometry `PLANE` item (e.g. `'Datum Plane 1'`), expanded per
103
+ * occurrence and expressed in subject-frame millimetres (per-context units
104
+ * resolved by the reader).
105
+ *
106
+ * @public
107
+ */
108
+ type XdeSupplementalPlane = {
109
+ occurrencePath: string;
110
+ name: string;
111
+ origin: [number, number, number];
112
+ normal: [number, number, number];
113
+ };
114
+ /**
115
+ * Structured AP242 read result produced by the GeoSpec verification kernel's
116
+ * XDE reader (SB1). One STEP-XDE read yields structure and geometry together.
117
+ *
118
+ * @public
119
+ */
120
+ type XdeReadResult = {
121
+ occurrences: XdeOccurrence[];
122
+ subshapeNames: XdeSubshapeName[];
123
+ datumPlacements: XdeDatumPlacement[];
124
+ /** Semantic GD&T datums (the `DATUM` family) — empty for graphical-only files. */
125
+ semanticDatums: XdeSemanticDatum[];
126
+ /** GD&T datum reference frames (`DATUM_SYSTEM`). */
127
+ datumSystems: XdeDatumSystem[];
128
+ /** Supplemental-geometry `PLANE` items. */
129
+ supplementalPlanes: XdeSupplementalPlane[];
130
+ /** Free (non-assembly) top-level shapes — the flat-export degenerate case. */
131
+ freeShapeCount: number;
132
+ };
133
+ //#endregion
134
+ export { StepSource, StepStreamingMode, XdeDatumPlacement, XdeDatumSystem, XdeOccurrence, XdeReadResult, XdeSemanticDatum, XdeSubshapeName, XdeSupplementalPlane };
@@ -0,0 +1,56 @@
1
+ import { GeoSpecSubject } from "../model/subject.mjs";
2
+ import { GeoSpecCanonicalClaimReport, GeoSpecNativeSubject } from "../engine/client.mjs";
3
+ import { GeoSpecAssertionClient, GeoSpecAssertionClientOptions, GeoSpecMatcherMethods } from "../assertion-client/client.mjs";
4
+ import "../assertion-client/index.mjs";
5
+ import { MatcherState } from "vitest";
6
+ //#region src/vitest/adapter.d.ts
7
+ type GeoSpecVitestMatcherMethods = GeoSpecMatcherMethods<Promise<void>>;
8
+ type GeoSpecVitestResult = {
9
+ readonly actual: GeoSpecCanonicalClaimReport;
10
+ readonly expected: Readonly<{
11
+ claimId: string;
12
+ polarity: string;
13
+ status: string;
14
+ }>;
15
+ readonly message: () => string;
16
+ readonly meta: Readonly<{
17
+ geoSpec: GeoSpecCanonicalClaimReport;
18
+ }>;
19
+ readonly pass: boolean;
20
+ };
21
+ type GeoSpecVitestMatcher = (this: MatcherState, received: GeoSpecNativeSubject | GeoSpecSubject | PromiseLike<GeoSpecNativeSubject | GeoSpecSubject>, ...arguments_: readonly unknown[]) => Promise<GeoSpecVitestResult>;
22
+ type GeoSpecVitestMatcherMap = Record<string, GeoSpecVitestMatcher>;
23
+ declare module 'vitest' {
24
+ interface Matchers<T = any> extends GeoSpecVitestMatcherMethods {}
25
+ }
26
+ /** Installed Vitest matcher map and lifecycle settlement hook. @public */
27
+ type GeoSpecVitestAdapter = {
28
+ readonly matchers: GeoSpecVitestMatcherMap;
29
+ flush(): Promise<void>;
30
+ };
31
+ /**
32
+ * Create Vitest matchers over an existing runner-independent client.
33
+ *
34
+ * @param client - Native GeoSpec assertion client shared with standalone use.
35
+ * @returns Matchers and a hook that settles every operation started by a test.
36
+ * @public
37
+ */
38
+ declare const createGeoSpecVitestAdapter: (client: GeoSpecAssertionClient) => GeoSpecVitestAdapter;
39
+ /**
40
+ * Register GeoSpec matchers and their settlement hook in the active Vitest file.
41
+ *
42
+ * @param client - Native client shared with standalone assertion calls.
43
+ * @returns The installed adapter for reporters or explicit flushing.
44
+ * @public
45
+ */
46
+ declare const installGeoSpecVitest: (client: GeoSpecAssertionClient) => GeoSpecVitestAdapter;
47
+ /**
48
+ * Create a native client and register it with the active Vitest file.
49
+ *
50
+ * @param options - Flat native assertion-client options.
51
+ * @returns The installed adapter for reporters or explicit flushing.
52
+ * @public
53
+ */
54
+ declare const setupGeoSpecVitest: (options: GeoSpecAssertionClientOptions) => GeoSpecVitestAdapter;
55
+ //#endregion
56
+ export { GeoSpecVitestAdapter, createGeoSpecVitestAdapter, installGeoSpecVitest, setupGeoSpecVitest };
@@ -0,0 +1,3 @@
1
+ import{geoSpecMatcherDescriptors as e}from"../engine/matchers.mjs";import{GeoSpecAssertionError as t,createGeoSpecAssertionClient as n}from"../assertion-client/client.mjs";import{afterEach as r,expect as i}from"vitest";const a=e=>e.evidence!==null&&typeof e.evidence==`object`&&!Array.isArray(e.evidence)?e.evidence:void 0,o=(e,t)=>{let n=a(t)?.positiveSatisfied;return{pass:(t.status===`passed`||t.status===`failed`)&&typeof n==`boolean`&&t.status===`passed`==(n===(t.polarity===`positive`))?n:e.isNot,actual:t,expected:{claimId:t.claimId,polarity:t.polarity,status:t.status},meta:{geoSpec:t},message:()=>JSON.stringify(t.result)}};var s=class{task;tracked=[];constructor(e){this.task=e,e.onFinished??=[],e.onFinished.push(()=>{for(;this.tracked.length>0;){let[e]=this.tracked;if(e===void 0)break;this.remove(e)}})}replace(e,t){return this.remove(e),this.track(t)}track(e){let t=new c(e,this);return this.task.promises??=[],this.task.promises.push(t),this.tracked.push(t),t}remove(e){let t=this.task.promises?.indexOf(e)??-1;t!==-1&&this.task.promises?.splice(t,1);let n=this.tracked.indexOf(e);n!==-1&&this.tracked.splice(n,1)}},c=class{promise;tracker;constructor(e,t){this.promise=e,this.tracker=t,e.catch(()=>void 0)}get[Symbol.toStringTag](){return`Promise`}then(e,t){return this.tracker.replace(this,this.promise.then(e,t))}catch(e){return this.tracker.replace(this,this.promise.catch(e))}finally(e){return this.tracker.replace(this,this.promise.finally(e))}},l=class{invocationStack;promise;task;constructor(e,t,n){this.promise=e,this.task=t,this.invocationStack=n}get[Symbol.toStringTag](){return`Promise`}then(e,t){let n=this.promise.then(e,t).catch(e=>{if(e instanceof Error&&this.invocationStack!==void 0){let t=this.invocationStack.split(`
2
+ `).slice(1).join(`
3
+ `);e.stack=`${e.stack??e.message}\nGeoSpec assertion invoked at:\n${t}`}throw e});return this.task===void 0?n:new s(this.task).track(n)}catch(e){return this.promise.catch(e)}finally(e){return this.promise.finally(e)}};const u=n=>{let r=new Set,i={};for(let a of Object.keys(e))i[a]=function(e,...i){if(!Reflect.has(this,`assertion`))throw TypeError(`GeoSpec Vitest matchers do not support asymmetric use.`);let s=Reflect.get(this,`task`),c=(async()=>{let r=await e,o=n.expectGeo(r),s=this.isNot?o.not:o;try{return Reflect.apply(s[a],s,i)}catch(e){if(e instanceof t)return e.report;throw e}})();return s===void 0&&r.add(c),new l((async()=>o(this,await c))(),s,Error(`Track GeoSpec assertion origin.`).stack)};let a=async()=>{let e=[...r];r.clear();let n=(await Promise.all(e)).find(e=>e.status!==`passed`);if(n!==void 0)throw new t(n);r.size>0&&await a()};return{matchers:i,flush:a}},d=e=>{let t=u(e);return i.extend(t.matchers),r(async()=>t.flush()),t},f=e=>d(n(e));export{u as createGeoSpecVitestAdapter,d as installGeoSpecVitest,f as setupGeoSpecVitest};
@@ -0,0 +1,4 @@
1
+ import { GeoSpecAssertionClient, GeoSpecAssertionClientOptions } from "../assertion-client/client.mjs";
2
+ import "../assertion-client/index.mjs";
3
+ import { GeoSpecVitestAdapter, createGeoSpecVitestAdapter, installGeoSpecVitest, setupGeoSpecVitest } from "./adapter.mjs";
4
+ export { type GeoSpecAssertionClient, type GeoSpecAssertionClientOptions, type GeoSpecVitestAdapter, createGeoSpecVitestAdapter, installGeoSpecVitest, setupGeoSpecVitest };
@@ -0,0 +1 @@
1
+ import{createGeoSpecVitestAdapter as e,installGeoSpecVitest as t,setupGeoSpecVitest as n}from"./adapter.mjs";export{e as createGeoSpecVitestAdapter,t as installGeoSpecVitest,n as setupGeoSpecVitest};