@voce-engine/testkit 0.1.0-rc.1

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 ADDED
@@ -0,0 +1 @@
1
+ Apache License 2.0
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # @voce-engine/testkit
2
+
3
+ Small deterministic fixtures and Mock-only helpers for offline VOCE contract tests.
4
+
5
+ > `0.1.0-rc.1` is a release candidate, not production-ready. Test contracts may change before `0.1.0`.
6
+
7
+ ```bash
8
+ npm install --save-dev @voce-engine/testkit@0.1.0-rc.1
9
+ ```
@@ -0,0 +1,23 @@
1
+ import type { ArtifactHandle, CaseSpec, ChangeIntent, EvidenceAndSourceResolverInput, Observation, ObservationDecision, Provenance, RequestedScope, RequestedScopePlan } from '@voce-engine/contracts';
2
+ import { createSourceBinding } from '@voce-engine/core';
3
+ import type { JsonValue } from '@voce-engine/contracts';
4
+ export declare function assert(condition: boolean, message: string): void;
5
+ export declare const FIXTURE_CONTEXT_HASH: string;
6
+ export declare const FIXTURE_CASE_ID = "case-m3-fixture";
7
+ export declare const FIXTURE_CASE_REVISION = 1;
8
+ export declare const FIXTURE_CREATED_AT = "2026-01-01T00:00:00.000Z";
9
+ export declare function fixtureCaseSpec(assets?: ArtifactHandle[]): CaseSpec;
10
+ export declare function fixtureProvenance(source?: Provenance['source'], sourceIds?: string[]): Provenance;
11
+ export declare function fixtureArtifact(id?: string, contentHash?: string): ArtifactHandle;
12
+ export declare function fixtureScope(id: string, ontologyPath: string, assetId?: string, required?: boolean): RequestedScope;
13
+ export declare function fixtureScopePlan(paths: string[], assetId?: string, caseId?: string, caseRevision?: number): RequestedScopePlan;
14
+ export declare function fixtureObservationDecision(observation: Observation, contextHash?: string, status?: ObservationDecision['status']): ObservationDecision;
15
+ export declare function fixtureChangeIntent(id: string, operation: ChangeIntent['operation'], targetPath: string, requestedValue?: JsonValue): ChangeIntent;
16
+ export declare function fixtureResolverInput(overrides?: Partial<EvidenceAndSourceResolverInput>): EvidenceAndSourceResolverInput;
17
+ export declare function confirmBinding(binding: Parameters<typeof createSourceBinding>[0], contextHash?: string): {
18
+ binding: import("@voce-engine/contracts").SourceBinding;
19
+ decision: import("@voce-engine/contracts").BindingDecision;
20
+ };
21
+ export * from './m4.js';
22
+ export * from './m5.js';
23
+ export * from './m6.js';
package/dist/index.js ADDED
@@ -0,0 +1,110 @@
1
+ import { createBindingDecision, createObservationDecision, createSourceBinding, computeRequestedScopePlanHash, sha256, } from '@voce-engine/core';
2
+ export function assert(condition, message) {
3
+ if (!condition)
4
+ throw new Error(message);
5
+ }
6
+ export const FIXTURE_CONTEXT_HASH = sha256({ fixture: 'm3-context', revision: 1 });
7
+ export const FIXTURE_CASE_ID = 'case-m3-fixture';
8
+ export const FIXTURE_CASE_REVISION = 1;
9
+ export const FIXTURE_CREATED_AT = '2026-01-01T00:00:00.000Z';
10
+ export function fixtureCaseSpec(assets = [fixtureArtifact()]) {
11
+ return {
12
+ schemaVersion: 'voce.case-spec/v1alpha1',
13
+ id: FIXTURE_CASE_ID,
14
+ revision: FIXTURE_CASE_REVISION,
15
+ mode: 'manual',
16
+ scenario: { root: { packId: 'fixture.root', versionRange: '1.0.0' }, extensions: [] },
17
+ userIntent: 'Preserve the selected reference properties and create only explicitly requested target values.',
18
+ assets,
19
+ trustedMetadata: [],
20
+ policies: { schemaVersion: 'voce.case-policies/v1alpha1', observationConfirmation: 'explicit', bindingConfirmation: 'explicit', allowDeclaredDefaults: false },
21
+ requestedOutput: { artifactKind: 'image', dataType: 'image', mediaTypes: ['image/png'], cardinality: { min: 1, max: 1 } },
22
+ };
23
+ }
24
+ export function fixtureProvenance(source = 'reference_observed', sourceIds = ['ref-01']) {
25
+ return { source, sourceIds: [...sourceIds].sort(), createdBy: 'voce-testkit', createdAt: FIXTURE_CREATED_AT };
26
+ }
27
+ export function fixtureArtifact(id = 'ref-01', contentHash = sha256({ fixtureAsset: id })) {
28
+ return {
29
+ id,
30
+ storeId: 'fixture-store',
31
+ contentHash,
32
+ mediaType: 'image/png',
33
+ role: 'reference',
34
+ resolverId: 'fixture-resolver',
35
+ availability: 'available',
36
+ retentionClass: 'fixture',
37
+ redactionPolicy: 'safe-hash-only',
38
+ };
39
+ }
40
+ export function fixtureScope(id, ontologyPath, assetId = 'ref-01', required = true) {
41
+ return { schemaVersion: 'voce.requested-scope/v1alpha1', id, ontologyPath, assetIds: [assetId], purpose: 'find_source', required };
42
+ }
43
+ export function fixtureScopePlan(paths, assetId = 'ref-01', caseId = FIXTURE_CASE_ID, caseRevision = FIXTURE_CASE_REVISION) {
44
+ const scopes = paths.map((path, index) => fixtureScope(`scope-${index + 1}`, path, assetId));
45
+ const base = { schemaVersion: 'voce.requested-scope-plan/v1alpha1', id: 'scope-plan-m3-fixture', caseId, caseRevision, scopes, excludedScopes: [], questions: [] };
46
+ return { ...base, planHash: computeRequestedScopePlanHash(base) };
47
+ }
48
+ export function fixtureObservationDecision(observation, contextHash = FIXTURE_CONTEXT_HASH, status = 'confirmed') {
49
+ return createObservationDecision({
50
+ schemaVersion: 'voce.observation-decision/v1alpha1',
51
+ decisionId: `decision-${observation.id}`,
52
+ observationId: observation.id,
53
+ observationHash: observation.contentHash,
54
+ contextHash,
55
+ status,
56
+ authority: 'user',
57
+ decidedBy: 'fixture-reviewer',
58
+ decidedAt: FIXTURE_CREATED_AT,
59
+ reasonCode: status === 'confirmed' ? 'FIXTURE_CONFIRMED' : 'FIXTURE_NOT_CONFIRMED',
60
+ });
61
+ }
62
+ export function fixtureChangeIntent(id, operation, targetPath, requestedValue) {
63
+ return {
64
+ schemaVersion: 'voce.change-intent/v1alpha1',
65
+ id,
66
+ operation,
67
+ targetPath,
68
+ ...(requestedValue === undefined ? {} : { requestedValue }),
69
+ importance: 'required',
70
+ provenance: fixtureProvenance('user_explicit', [id]),
71
+ };
72
+ }
73
+ export function fixtureResolverInput(overrides = {}) {
74
+ const requestedScopePlan = fixtureScopePlan(['person.identity', 'person.hair', 'expression', 'pose', 'wardrobe.top', 'environment.background', 'camera.framing']);
75
+ return {
76
+ schemaVersion: 'voce.evidence-source-resolver-input/v1alpha1',
77
+ caseId: FIXTURE_CASE_ID,
78
+ caseRevision: FIXTURE_CASE_REVISION,
79
+ contextHash: FIXTURE_CONTEXT_HASH,
80
+ requestedScopePlan,
81
+ changeIntents: [],
82
+ observations: [],
83
+ observationDecisions: [],
84
+ sourceBindings: [],
85
+ bindingDecisions: [],
86
+ trustedMetadata: [],
87
+ ...overrides,
88
+ };
89
+ }
90
+ export function confirmBinding(binding, contextHash = FIXTURE_CONTEXT_HASH) {
91
+ const normalized = createSourceBinding(binding);
92
+ return {
93
+ binding: normalized,
94
+ decision: createBindingDecision({
95
+ schemaVersion: 'voce.binding-decision/v1alpha1',
96
+ decisionId: `decision-${normalized.id}`,
97
+ bindingId: normalized.id,
98
+ bindingHash: normalized.contentHash,
99
+ contextHash,
100
+ status: 'confirmed',
101
+ authority: 'user',
102
+ decidedBy: 'fixture-reviewer',
103
+ decidedAt: FIXTURE_CREATED_AT,
104
+ reasonCode: 'FIXTURE_CONFIRMED',
105
+ }),
106
+ };
107
+ }
108
+ export * from './m4.js';
109
+ export * from './m5.js';
110
+ export * from './m6.js';
package/dist/m4.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { ArtifactHandle, CompilationContext, ConstraintCompilationInput, ConstraintIR, OntologyFact, OntologyInstance, OutputContract, ProviderCapabilityProfile, ReferenceCandidate, ReferenceDependency, ReferencePlanningInput } from '@voce-engine/contracts';
2
+ export declare const M4_FIXTURE_CASE_ID = "case-m4-fixture";
3
+ export declare const M4_FIXTURE_CASE_REVISION = 1;
4
+ export declare const M4_FIXTURE_PLAN_HASH: string;
5
+ export declare const M4_FIXTURE_CREATED_AT = "2026-01-01T00:00:00.000Z";
6
+ export declare function fixtureM4Artifact(id?: string, byteLength?: number, mediaType?: string): ArtifactHandle;
7
+ export declare function fixtureM4Context(overrides?: Partial<Omit<CompilationContext, 'contextHash'>>): CompilationContext;
8
+ export declare function fixtureM4Ontology(facts?: OntologyFact[], contextHash?: string, requestedScopePlanHash?: string, status?: 'ok' | 'blocked'): OntologyInstance;
9
+ export declare function fixtureM4Output(background?: OutputContract['background']): OutputContract;
10
+ export declare function fixtureM4ConstraintInput(overrides?: Partial<ConstraintCompilationInput>): ConstraintCompilationInput;
11
+ export declare function fixtureM4ConstraintIR(overrides?: Partial<ConstraintCompilationInput>): ConstraintIR;
12
+ export declare function fixtureM4Candidate(id: string, importance?: ReferenceCandidate['importance'], byteLength?: number, profile?: ProviderCapabilityProfile): ReferenceCandidate;
13
+ export declare function fixtureM4ReferenceInput(profile?: ProviderCapabilityProfile, candidates?: ReferenceCandidate[]): ReferencePlanningInput;
14
+ export declare function fixtureM4ReferencePlan(profile?: ProviderCapabilityProfile, candidates?: ReferenceCandidate[]): import("@voce-engine/contracts").ReferencePlan;
15
+ export declare function fixtureM4ReferenceDependency(parentCandidateId: string, childCandidateId: string, importance?: ReferenceDependency['importance']): ReferenceDependency;
package/dist/m4.js ADDED
@@ -0,0 +1,92 @@
1
+ import { computeCompilationContextHash, computeOntologyInstanceHash, computeReferenceCandidateHash, compileConstraints, createReferenceDependency, MOCK_IMAGE_PROFILE, planReferences, sha256, } from '@voce-engine/core';
2
+ export const M4_FIXTURE_CASE_ID = 'case-m4-fixture';
3
+ export const M4_FIXTURE_CASE_REVISION = 1;
4
+ export const M4_FIXTURE_PLAN_HASH = sha256({ fixture: 'm4-scope-plan' });
5
+ export const M4_FIXTURE_CREATED_AT = '2026-01-01T00:00:00.000Z';
6
+ export function fixtureM4Artifact(id = 'ref-01', byteLength, mediaType = 'image/png') {
7
+ return {
8
+ id,
9
+ storeId: 'm4-fixture-store',
10
+ contentHash: sha256({ fixtureAsset: id }),
11
+ mediaType,
12
+ ...(byteLength === undefined ? {} : { byteLength }),
13
+ role: 'reference',
14
+ resolverId: 'm4-fixture-resolver',
15
+ availability: 'available',
16
+ retentionClass: 'fixture',
17
+ redactionPolicy: 'safe-hash-only',
18
+ };
19
+ }
20
+ export function fixtureM4Context(overrides = {}) {
21
+ const base = {
22
+ caseSpecId: M4_FIXTURE_CASE_ID,
23
+ caseSpecRevision: M4_FIXTURE_CASE_REVISION,
24
+ caseSpecHash: sha256({ fixture: 'm4-case-spec' }),
25
+ artifactHashes: [],
26
+ decisionHashes: [],
27
+ scenarioCompositionLockHash: sha256({ fixture: 'm4-lock' }),
28
+ effectiveScenarioHash: sha256({ fixture: 'm4-scenario' }),
29
+ rulePackPlugins: [],
30
+ optimizer: { id: 'voce.deterministic', version: '1.0.0', digest: sha256({ fixture: 'm4-optimizer' }) },
31
+ ...overrides,
32
+ };
33
+ return { ...base, contextHash: computeCompilationContextHash(base) };
34
+ }
35
+ export function fixtureM4Ontology(facts = [], contextHash = fixtureM4Context().contextHash, requestedScopePlanHash = M4_FIXTURE_PLAN_HASH, status = 'ok') {
36
+ const base = {
37
+ schemaVersion: 'voce.ontology-instance/v1alpha1',
38
+ id: 'ontology-m4-fixture',
39
+ caseId: M4_FIXTURE_CASE_ID,
40
+ caseRevision: M4_FIXTURE_CASE_REVISION,
41
+ contextHash,
42
+ requestedScopePlanHash,
43
+ facts,
44
+ unknownPaths: [],
45
+ unspecifiedPaths: [],
46
+ unresolvedItems: [],
47
+ conflicts: [],
48
+ decisionTrace: [],
49
+ };
50
+ return { ...base, instanceHash: computeOntologyInstanceHash({ ...base, instanceHash: '' }), status };
51
+ }
52
+ export function fixtureM4Output(background = 'opaque') {
53
+ return { artifactKind: 'image', dataType: 'image', mediaTypes: ['image/png'], cardinality: { min: 1, max: 1 }, dimensions: { width: 1024, height: 1024 }, background, allowAlpha: false };
54
+ }
55
+ export function fixtureM4ConstraintInput(overrides = {}) {
56
+ const context = overrides.context ?? fixtureM4Context();
57
+ const contextHash = overrides.contextHash ?? context.contextHash;
58
+ const requestedScopePlanHash = overrides.requestedScopePlanHash ?? M4_FIXTURE_PLAN_HASH;
59
+ const ontologyInstance = overrides.ontologyInstance ?? fixtureM4Ontology([], contextHash, requestedScopePlanHash);
60
+ return {
61
+ schemaVersion: 'voce.constraint-compilation-input/v1alpha1',
62
+ caseId: M4_FIXTURE_CASE_ID,
63
+ caseRevision: M4_FIXTURE_CASE_REVISION,
64
+ context,
65
+ contextHash,
66
+ requestedScopePlanHash,
67
+ ontologyInstance,
68
+ changeIntents: [],
69
+ sourceBindings: [],
70
+ bindingDecisions: [],
71
+ outputContract: fixtureM4Output(),
72
+ ...overrides,
73
+ };
74
+ }
75
+ export function fixtureM4ConstraintIR(overrides = {}) {
76
+ return compileConstraints(fixtureM4ConstraintInput(overrides));
77
+ }
78
+ export function fixtureM4Candidate(id, importance = 'preferred', byteLength, profile = MOCK_IMAGE_PROFILE) {
79
+ const artifact = fixtureM4Artifact(id, byteLength, profile.allowedReferenceMediaTypes?.[0] ?? 'image/png');
80
+ const candidate = { schemaVersion: 'voce.reference-candidate/v1alpha1', id, assetId: id, artifact, contentHash: artifact.contentHash, mediaType: artifact.mediaType, ...(byteLength === undefined ? {} : { byteLength }), role: 'detail', ontologyScopes: [`scope.${id}`], importance, constraintIds: [], sourceBindingIds: [], goalIds: [] };
81
+ return { ...candidate, candidateHash: computeReferenceCandidateHash(candidate) };
82
+ }
83
+ export function fixtureM4ReferenceInput(profile = MOCK_IMAGE_PROFILE, candidates = [fixtureM4Candidate('ref-01', 'required', 100_000, profile)]) {
84
+ const constraintIR = fixtureM4ConstraintIR();
85
+ return { schemaVersion: 'voce.reference-planning-input/v1alpha1', caseId: M4_FIXTURE_CASE_ID, caseRevision: M4_FIXTURE_CASE_REVISION, contextHash: constraintIR.contextHash, constraintIR, candidates, dependencies: [], profile };
86
+ }
87
+ export function fixtureM4ReferencePlan(profile = MOCK_IMAGE_PROFILE, candidates) {
88
+ return planReferences(fixtureM4ReferenceInput(profile, candidates));
89
+ }
90
+ export function fixtureM4ReferenceDependency(parentCandidateId, childCandidateId, importance = 'required') {
91
+ return createReferenceDependency({ schemaVersion: 'voce.reference-dependency/v1alpha1', id: `dependency-${parentCandidateId}-${childCandidateId}`, parentCandidateId, childCandidateId, kind: 'parent_detail', importance, reasonCode: 'FIXTURE_PARENT_DETAIL', explanation: 'Fixture parent/detail dependency.' });
92
+ }
package/dist/m5.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { CompilationContext, OfflineExecutionInput, OutputContract, PromptCandidateIR, PromptCompilationInput, PromptGuardInput, PromptIR, PromptTransformation, ProviderCapabilityProfile, RemoteCallAuthorization } from '@voce-engine/contracts';
2
+ export declare function fixtureM5Output(): OutputContract;
3
+ export declare function fixtureM5Context(overrides?: Partial<Omit<CompilationContext, 'contextHash'>>): CompilationContext;
4
+ export declare function fixtureM5CompilationInput(profile?: ProviderCapabilityProfile, overrides?: Partial<PromptCompilationInput>): PromptCompilationInput;
5
+ export declare function fixtureM5PromptIR(profile?: ProviderCapabilityProfile, overrides?: Partial<PromptCompilationInput>): PromptIR;
6
+ export declare function fixtureM5Candidate(prompt?: PromptIR, transformations?: PromptTransformation[]): PromptCandidateIR;
7
+ export declare function fixtureM5GuardInput(prompt?: PromptIR, candidate?: PromptCandidateIR, policy?: PromptGuardInput['policy']): PromptGuardInput;
8
+ export declare function fixtureM5RemoteAuthorizations(input: Omit<OfflineExecutionInput, 'executionAuthorization' | 'remoteCallAuthorizations'>, promptArtifactHash?: string): RemoteCallAuthorization[];
9
+ export declare function fixtureM5ExecutionInput(profile?: ProviderCapabilityProfile, promptArtifact?: PromptIR | PromptCandidateIR, options?: OfflineExecutionInput['options']): OfflineExecutionInput;
package/dist/m5.js ADDED
@@ -0,0 +1,145 @@
1
+ import { computeExecutionBudgetDigest, computeExecutionDataTransferDigest, computeExecutionStepInputHash, computeOutputContractHash, computePromptIRHash, createExecutionAuthorization, createPromptCandidateIR, createRemoteCallAuthorization, compilePromptIR, MOCK_IMAGE_PROFILE, MOCK_JPEG_PROFILE, planPipeline, } from '@voce-engine/core';
2
+ import { fixtureM4ConstraintIR, fixtureM4Context, fixtureM4Output, fixtureM4ReferencePlan, M4_FIXTURE_CASE_ID, M4_FIXTURE_CASE_REVISION, } from './m4.js';
3
+ const FIXED_M5_TIME = '2026-01-01T00:00:00.000Z';
4
+ function sorted(values) {
5
+ return [...new Set(values)].sort();
6
+ }
7
+ function profileForPrompt(prompt) {
8
+ return prompt.targetCapabilityProfile.id === MOCK_JPEG_PROFILE.id ? MOCK_JPEG_PROFILE : MOCK_IMAGE_PROFILE;
9
+ }
10
+ export function fixtureM5Output() {
11
+ return fixtureM4Output('opaque');
12
+ }
13
+ export function fixtureM5Context(overrides = {}) {
14
+ return fixtureM4Context(overrides);
15
+ }
16
+ export function fixtureM5CompilationInput(profile = MOCK_IMAGE_PROFILE, overrides = {}) {
17
+ const context = overrides.context ?? fixtureM5Context();
18
+ const constraintIR = overrides.constraintIR ?? fixtureM4ConstraintIR({ context });
19
+ const referencePlan = overrides.referencePlan ?? fixtureM4ReferencePlan(profile);
20
+ const outputContract = overrides.outputContract ?? fixtureM5Output();
21
+ const pipelineResult = overrides.pipelinePlan ? { status: 'ok', pipelinePlan: overrides.pipelinePlan } : planPipeline({ schemaVersion: 'voce.pipeline-planning-input/v1alpha1', caseId: M4_FIXTURE_CASE_ID, caseRevision: M4_FIXTURE_CASE_REVISION, contextHash: context.contextHash, outputContract, constraintIR, referencePlan, profile });
22
+ if (!pipelineResult.pipelinePlan)
23
+ throw new Error('M5_FIXTURE_PIPELINE_BLOCKED');
24
+ return {
25
+ schemaVersion: 'voce.prompt-compilation-input/v1alpha1',
26
+ caseId: M4_FIXTURE_CASE_ID,
27
+ caseRevision: M4_FIXTURE_CASE_REVISION,
28
+ context,
29
+ contextHash: context.contextHash,
30
+ constraintIR,
31
+ referencePlan,
32
+ pipelinePlan: pipelineResult.pipelinePlan,
33
+ outputContract,
34
+ targetAdapter: { id: profile.adapterId, version: profile.version, digest: profile.adapterDigest },
35
+ targetCapabilityProfile: { id: profile.id, version: profile.version, digest: profile.profileHash },
36
+ ...overrides,
37
+ };
38
+ }
39
+ export function fixtureM5PromptIR(profile = MOCK_IMAGE_PROFILE, overrides = {}) {
40
+ return compilePromptIR(fixtureM5CompilationInput(profile, overrides));
41
+ }
42
+ export function fixtureM5Candidate(prompt = fixtureM5PromptIR(), transformations = []) {
43
+ return createPromptCandidateIR(prompt, transformations);
44
+ }
45
+ export function fixtureM5GuardInput(prompt = fixtureM5PromptIR(), candidate = fixtureM5Candidate(prompt), policy = 'reject') {
46
+ const profile = profileForPrompt(prompt);
47
+ const constraintIR = fixtureM4ConstraintIR();
48
+ const referencePlan = fixtureM4ReferencePlan(profile);
49
+ const pipelineResult = planPipeline({ schemaVersion: 'voce.pipeline-planning-input/v1alpha1', caseId: prompt.caseId, caseRevision: prompt.caseRevision, contextHash: prompt.contextHash, outputContract: prompt.output, constraintIR, referencePlan, profile });
50
+ if (!pipelineResult.pipelinePlan)
51
+ throw new Error('M5_FIXTURE_PIPELINE_BLOCKED');
52
+ return {
53
+ schemaVersion: 'voce.prompt-guard-input/v1alpha1',
54
+ promptIR: prompt,
55
+ candidate,
56
+ constraintIR,
57
+ referencePlan,
58
+ pipelinePlan: pipelineResult.pipelinePlan,
59
+ outputContract: prompt.output,
60
+ context: fixtureM5Context(),
61
+ policy,
62
+ };
63
+ }
64
+ function stepPurpose(type) {
65
+ if (type === 'generate')
66
+ return 'generation';
67
+ if (type === 'semantic_review')
68
+ return 'semantic_review';
69
+ if (type === 'publish_asset')
70
+ return 'asset_publication';
71
+ if (type === 'resolve_asset')
72
+ return 'reference_interpretation';
73
+ return 'postprocessing';
74
+ }
75
+ export function fixtureM5RemoteAuthorizations(input, promptArtifactHash = 'sha256:' + '0'.repeat(64)) {
76
+ const artifactHashes = sorted(input.referencePlan.ordered.map((reference) => reference.contentHash));
77
+ const scopeIds = sorted(input.referencePlan.ordered.flatMap((reference) => reference.ontologyScopes));
78
+ const constraintIds = sorted(input.constraintIR.constraints.map((constraint) => constraint.id));
79
+ return input.pipelinePlan.steps.filter((step) => step.mayCreateChargedSubmission || step.destination !== 'local').sort((left, right) => left.id.localeCompare(right.id)).map((step) => createRemoteCallAuthorization({
80
+ schemaVersion: 'voce.remote-call-authorization/v1alpha1',
81
+ id: `m5-remote-${step.id}`,
82
+ caseId: input.pipelinePlan.caseId,
83
+ caseRevision: input.pipelinePlan.caseRevision,
84
+ contextHash: input.contextHash,
85
+ stepId: step.id,
86
+ purpose: stepPurpose(step.type),
87
+ inputHash: computeExecutionStepInputHash(step, input.contextHash, input.pipelinePlan.planHash, input.referencePlan.planHash, promptArtifactHash, artifactHashes),
88
+ permittedArtifactHashes: artifactHashes,
89
+ permittedScopeIds: scopeIds,
90
+ constraintIds,
91
+ adapterId: step.adapterId,
92
+ adapterDigest: step.adapterVersion.digest,
93
+ profileDigest: step.profileVersion.digest,
94
+ destination: step.destination,
95
+ dataCategories: sorted(step.dataTransfer.dataCategories),
96
+ maximumCalls: step.budget.maximumCalls,
97
+ maximumRetries: step.budget.maximumRetries,
98
+ ...(step.budget.maximumBytes === undefined && step.dataTransfer.maximumBytes === undefined ? {} : { maximumBytes: step.budget.maximumBytes ?? step.dataTransfer.maximumBytes }),
99
+ timeoutMs: step.budget.timeoutMs,
100
+ ...(step.budget.maximumCost === undefined ? {} : { maximumCost: step.budget.maximumCost }),
101
+ ...(step.budget.currency === undefined ? {} : { currency: step.budget.currency }),
102
+ idempotencyKey: `m5-idempotency-${step.id}`,
103
+ authority: 'fixture-authority',
104
+ authorizedBy: 'fixture-reviewer',
105
+ authorizedAt: FIXED_M5_TIME,
106
+ }));
107
+ }
108
+ export function fixtureM5ExecutionInput(profile = MOCK_IMAGE_PROFILE, promptArtifact = fixtureM5PromptIR(profile), options = {}) {
109
+ const promptHash = 'candidateHash' in promptArtifact ? promptArtifact.candidateHash : computePromptIRHash(promptArtifact);
110
+ const compilation = fixtureM5CompilationInput(profile);
111
+ const base = {
112
+ schemaVersion: 'voce.offline-execution-input/v1alpha1',
113
+ context: compilation.context,
114
+ contextHash: compilation.contextHash,
115
+ constraintIR: compilation.constraintIR,
116
+ referencePlan: compilation.referencePlan,
117
+ pipelinePlan: compilation.pipelinePlan,
118
+ outputContract: compilation.outputContract,
119
+ promptArtifact,
120
+ options,
121
+ };
122
+ const remoteCallAuthorizations = fixtureM5RemoteAuthorizations(base, promptHash);
123
+ const executionAuthorization = createExecutionAuthorization({
124
+ schemaVersion: 'voce.execution-authorization/v1alpha1',
125
+ id: 'm5-execution-authorization',
126
+ caseId: compilation.pipelinePlan.caseId,
127
+ caseRevision: compilation.pipelinePlan.caseRevision,
128
+ contextHash: compilation.contextHash,
129
+ constraintIRHash: compilation.constraintIR.deterministicSignature,
130
+ compilationSignature: compilation.constraintIR.deterministicSignature,
131
+ referencePlanHash: compilation.referencePlan.planHash,
132
+ pipelinePlanHash: compilation.pipelinePlan.planHash,
133
+ outputContractHash: computeOutputContractHash(compilation.outputContract),
134
+ promptArtifactHash: promptHash,
135
+ adapterProfileDigests: sorted([compilation.pipelinePlan.profileDigest, ...compilation.pipelinePlan.adapterDigests, ...compilation.pipelinePlan.steps.map((step) => step.profileVersion.digest)]),
136
+ destinations: sorted(compilation.pipelinePlan.dataTransfers.map((transfer) => transfer.destination)),
137
+ dataTransferDigest: computeExecutionDataTransferDigest(compilation.pipelinePlan),
138
+ budgetDigest: computeExecutionBudgetDigest(compilation.pipelinePlan),
139
+ remoteCallAuthorizationIds: remoteCallAuthorizations.map((authorization) => authorization.id),
140
+ authority: 'fixture-authority',
141
+ authorizedBy: 'fixture-reviewer',
142
+ authorizedAt: FIXED_M5_TIME,
143
+ });
144
+ return { ...base, remoteCallAuthorizations, executionAuthorization };
145
+ }
package/dist/m6.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ import type { ArtifactHandle, AssetSink, Budget, JsonObject, ProviderResponseEnvelope, RemoteCallAuthorization, StructuralValidationArtifactInput, VersionPin } from '@voce-engine/contracts';
2
+ export declare const FIXTURE_M6_ALPHA_PNG: Uint8Array<ArrayBuffer>;
3
+ export declare const FIXTURE_M6_OPAQUE_PNG: Uint8Array<ArrayBuffer>;
4
+ export declare const FIXTURE_M6_JPEG: Uint8Array<ArrayBuffer>;
5
+ export declare function fixtureM6Artifact(id: string, bytes?: Uint8Array, mediaType?: string, role?: string): ArtifactHandle;
6
+ export declare class RecordingAssetSink implements AssetSink {
7
+ readonly puts: Array<{
8
+ artifact: ArtifactHandle;
9
+ bytes: Uint8Array;
10
+ }>;
11
+ readonly remoteUrls: string[];
12
+ private readonly remoteBytes;
13
+ constructor(remoteOutputs?: Record<string, Uint8Array>);
14
+ put(input: {
15
+ bytes: Uint8Array;
16
+ mediaType: string;
17
+ role: string;
18
+ }): Promise<ArtifactHandle>;
19
+ putRemote(input: {
20
+ url: string;
21
+ mediaType?: string;
22
+ role: string;
23
+ }): Promise<ArtifactHandle | undefined>;
24
+ resolve(handle: ArtifactHandle): Promise<Uint8Array | undefined>;
25
+ }
26
+ export declare function fixtureM6Authorization(input: {
27
+ id?: string;
28
+ caseId?: string;
29
+ caseRevision?: number;
30
+ contextHash?: string;
31
+ stepId: string;
32
+ purpose: RemoteCallAuthorization['purpose'];
33
+ inputHash: string;
34
+ artifactHashes?: string[];
35
+ scopeIds?: string[];
36
+ constraintIds?: string[];
37
+ adapter: VersionPin;
38
+ profileDigest: string;
39
+ destination: string;
40
+ region?: string;
41
+ dataCategories?: string[];
42
+ budget?: Budget;
43
+ modelId?: string;
44
+ modelVersion?: string;
45
+ }): RemoteCallAuthorization;
46
+ export declare function fixtureStructuralArtifactInput(id?: string, bytes?: Uint8Array<ArrayBuffer>, mediaType?: string): StructuralValidationArtifactInput;
47
+ export declare function fixtureProviderResponse(requestHash: string, body: JsonObject, status?: ProviderResponseEnvelope['status']): ProviderResponseEnvelope;
package/dist/m6.js ADDED
@@ -0,0 +1,93 @@
1
+ import { computeArtifactBytesHash, computeProviderResponseEnvelopeHash, createRemoteCallAuthorization, sha256, } from '@voce-engine/core';
2
+ export const FIXTURE_M6_ALPHA_PNG = Uint8Array.from([
3
+ 137, 80, 78, 71, 13, 10, 26, 10,
4
+ 0, 0, 0, 13, 73, 72, 68, 82,
5
+ 0, 0, 0, 1, 0, 0, 0, 1,
6
+ 8, 6, 0, 0, 0, 31, 21, 196, 137,
7
+ ]);
8
+ export const FIXTURE_M6_OPAQUE_PNG = Uint8Array.from([
9
+ 137, 80, 78, 71, 13, 10, 26, 10,
10
+ 0, 0, 0, 13, 73, 72, 68, 82,
11
+ 0, 0, 0, 1, 0, 0, 0, 1,
12
+ 8, 2, 0, 0, 0, 144, 119, 83, 222,
13
+ ]);
14
+ export const FIXTURE_M6_JPEG = Uint8Array.from([255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 255, 217]);
15
+ export function fixtureM6Artifact(id, bytes = FIXTURE_M6_OPAQUE_PNG, mediaType = 'image/png', role = 'generated-image') {
16
+ return {
17
+ id,
18
+ storeId: 'm6-fixture-store',
19
+ contentHash: computeArtifactBytesHash(bytes),
20
+ mediaType,
21
+ byteLength: bytes.byteLength,
22
+ role,
23
+ resolverId: 'm6-fixture-resolver',
24
+ availability: 'available',
25
+ retentionClass: 'fixture',
26
+ redactionPolicy: 'safe-hash-only',
27
+ };
28
+ }
29
+ export class RecordingAssetSink {
30
+ puts = [];
31
+ remoteUrls = [];
32
+ remoteBytes = new Map();
33
+ constructor(remoteOutputs = {}) {
34
+ for (const [url, bytes] of Object.entries(remoteOutputs))
35
+ this.remoteBytes.set(url, new Uint8Array(bytes));
36
+ }
37
+ async put(input) {
38
+ const bytes = new Uint8Array(input.bytes);
39
+ const artifact = fixtureM6Artifact(`m6-artifact-${this.puts.length + 1}`, bytes, input.mediaType, input.role);
40
+ this.puts.push({ artifact, bytes });
41
+ return { ...artifact };
42
+ }
43
+ async putRemote(input) {
44
+ this.remoteUrls.push(input.url);
45
+ const bytes = this.remoteBytes.get(input.url);
46
+ return bytes ? this.put({ bytes, mediaType: input.mediaType ?? 'image/png', role: input.role }) : undefined;
47
+ }
48
+ async resolve(handle) {
49
+ const found = this.puts.find((item) => item.artifact.id === handle.id);
50
+ return found ? new Uint8Array(found.bytes) : undefined;
51
+ }
52
+ }
53
+ export function fixtureM6Authorization(input) {
54
+ const budget = input.budget ?? { schemaVersion: 'voce.budget/v1alpha1', id: `m6-budget-${input.stepId}`, maximumCalls: 1, maximumRetries: 0, timeoutMs: 60_000 };
55
+ return createRemoteCallAuthorization({
56
+ schemaVersion: 'voce.remote-call-authorization/v1alpha1',
57
+ id: input.id ?? `m6-auth-${input.stepId}`,
58
+ caseId: input.caseId ?? 'm6-fixture-case',
59
+ caseRevision: input.caseRevision ?? 1,
60
+ contextHash: input.contextHash ?? sha256({ fixture: 'm6-context' }),
61
+ stepId: input.stepId,
62
+ purpose: input.purpose,
63
+ inputHash: input.inputHash,
64
+ permittedArtifactHashes: [...(input.artifactHashes ?? [])].sort(),
65
+ permittedScopeIds: [...(input.scopeIds ?? [])].sort(),
66
+ constraintIds: [...(input.constraintIds ?? [])].sort(),
67
+ ...(input.modelId === undefined ? {} : { modelId: input.modelId }),
68
+ ...(input.modelVersion === undefined ? {} : { modelVersion: input.modelVersion }),
69
+ adapterId: input.adapter.id,
70
+ adapterDigest: input.adapter.digest,
71
+ profileDigest: input.profileDigest,
72
+ destination: input.destination,
73
+ ...(input.region === undefined ? {} : { region: input.region }),
74
+ dataCategories: [...(input.dataCategories ?? ['image'])].sort(),
75
+ maximumCalls: budget.maximumCalls,
76
+ maximumRetries: budget.maximumRetries,
77
+ ...(budget.maximumBytes === undefined ? {} : { maximumBytes: budget.maximumBytes }),
78
+ timeoutMs: budget.timeoutMs,
79
+ ...(budget.maximumCost === undefined ? {} : { maximumCost: budget.maximumCost }),
80
+ ...(budget.currency === undefined ? {} : { currency: budget.currency }),
81
+ idempotencyKey: `m6-idempotency-${input.stepId}`,
82
+ authority: 'm6-fixture-authority',
83
+ authorizedBy: 'm6-fixture-reviewer',
84
+ authorizedAt: '2026-01-01T00:00:00.000Z',
85
+ });
86
+ }
87
+ export function fixtureStructuralArtifactInput(id = 'm6-image', bytes = FIXTURE_M6_OPAQUE_PNG, mediaType = 'image/png') {
88
+ return { artifact: fixtureM6Artifact(id, bytes, mediaType), bytes: new Uint8Array(bytes) };
89
+ }
90
+ export function fixtureProviderResponse(requestHash, body, status = 'succeeded') {
91
+ const base = { schemaVersion: 'voce.provider-response-envelope/v1alpha1', requestHash, status, outputArtifactIds: [], body };
92
+ return { ...base, responseHash: computeProviderResponseEnvelopeHash(base) };
93
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@voce-engine/testkit",
3
+ "version": "0.1.0-rc.1",
4
+ "description": "Deterministic fixtures and Mock-only helpers for offline VOCE contract and runtime tests.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": "./dist/index.js"
9
+ },
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist/index.js",
13
+ "dist/index.d.ts",
14
+ "dist/m4.js",
15
+ "dist/m4.d.ts",
16
+ "dist/m5.js",
17
+ "dist/m5.d.ts",
18
+ "dist/m6.js",
19
+ "dist/m6.d.ts",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "engines": {
24
+ "node": ">=20"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/windforce19820520-ai/visual-ontology-constraint-engine.git",
29
+ "directory": "packages/testkit"
30
+ },
31
+ "homepage": "https://github.com/windforce19820520-ai/visual-ontology-constraint-engine#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/windforce19820520-ai/visual-ontology-constraint-engine/issues"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public",
37
+ "tag": "next"
38
+ },
39
+ "dependencies": {
40
+ "@voce-engine/core": "0.1.0-rc.1",
41
+ "@voce-engine/contracts": "0.1.0-rc.1"
42
+ }
43
+ }