@voce-engine/cli 0.1.0-rc.2 → 0.1.0-rc.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.
- package/README.md +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +100 -21
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The `voce` command is the offline-first, explicit-path CLI for VOCE v0.1. It does not load lifecycle scripts, discover global packages, inspect credentials, or call a Provider unless the command explicitly selects the built-in `mock` provider.
|
|
4
4
|
|
|
5
|
-
> `0.1.0-rc.
|
|
5
|
+
> `0.1.0-rc.3` is a release candidate, not production-ready. CLI behavior may change before `0.1.0`.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install --global @voce-engine/cli@0.1.0-rc.
|
|
8
|
+
npm install --global @voce-engine/cli@0.1.0-rc.3
|
|
9
9
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.0-rc.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.0-rc.3";
|
|
2
2
|
export declare function runCli(argv?: string[]): Promise<number>;
|
package/dist/index.js
CHANGED
|
@@ -2,13 +2,13 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { lstat, mkdir, readdir, readFile, realpath, rename, writeFile } from 'node:fs/promises';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import * as process from 'node:process';
|
|
5
|
-
import { MOCK_IMAGE_PROFILE, MOCK_JPEG_PROFILE, MOCK_LIMITED_REFERENCE_PROFILE, compileEvaluationReport, computeExecutionRunHash, computeCompilationContextHash, computeOntologyInstanceHash, computeSemanticReviewRequestHash, createConstraintWaiver, createHumanAcceptanceDecision, compileConstraints, createScenarioPackRegistry, executeOffline, executeSemanticReview, FixtureReferenceInterpreter, FixtureSemanticReviewer, guardPromptCandidate, renderStaticTraceReport, sha256, traceModelFromExecution, validateStructuralImage, canonicalize, } from '@voce-engine/core';
|
|
5
|
+
import { MOCK_IMAGE_PROFILE, MOCK_JPEG_PROFILE, MOCK_LIMITED_REFERENCE_PROFILE, compileEvaluationReport, computeExecutionRunHash, computeCompilationContextHash, computeOntologyInstanceHash, computeSemanticReviewRequestHash, createConstraintWaiver, createHumanAcceptanceDecision, compileConstraints, compilePromptIR, createReferenceCandidate, planPipeline, planReferences, createScenarioPackRegistry, executeOffline, executeSemanticReview, FixtureReferenceInterpreter, FixtureSemanticReviewer, guardPromptCandidate, renderStaticTraceReport, sha256, traceModelFromExecution, validateStructuralImage, canonicalize, } from '@voce-engine/core';
|
|
6
6
|
import { FIXTURE_M6_OPAQUE_PNG, fixtureChangeIntent, fixtureM4ConstraintInput, fixtureM5Candidate, fixtureM5ExecutionInput, fixtureM5GuardInput, fixtureM5PromptIR, fixtureM6Artifact, fixtureM6Authorization, fixtureScopePlan, } from '@voce-engine/testkit';
|
|
7
7
|
import { BUNDLE_MANIFEST_SCHEMA_VERSION } from '@voce-engine/contracts';
|
|
8
|
-
export const CLI_VERSION = '0.1.0-rc.
|
|
8
|
+
export const CLI_VERSION = '0.1.0-rc.3';
|
|
9
9
|
const TOOL_ID = '@voce-engine/cli';
|
|
10
|
-
const CONTRACTS_VERSION = '0.1.0-rc.
|
|
11
|
-
const CORE_VERSION = '0.1.0-rc.
|
|
10
|
+
const CONTRACTS_VERSION = '0.1.0-rc.3';
|
|
11
|
+
const CORE_VERSION = '0.1.0-rc.3';
|
|
12
12
|
const SOURCE_SCHEMA = 'voce.scenario-pack-source/v1alpha1';
|
|
13
13
|
const PACK_SCHEMA = 'voce.scenario-pack/v1alpha1';
|
|
14
14
|
const HASH = /^sha256:[0-9a-f]{64}$/;
|
|
@@ -337,17 +337,93 @@ function probeInput(probe, resolution, caseSpec) {
|
|
|
337
337
|
const requestedScopePlan = fixtureScopePlan(['person.identity'], 'ref-01', caseSpec.id, caseSpec.revision);
|
|
338
338
|
const ontologyBase = { ...base.ontologyInstance, id: `ontology-${probe.id}`, caseId: caseSpec.id, caseRevision: caseSpec.revision, contextHash: context.contextHash, requestedScopePlanHash: requestedScopePlan.planHash, unknownPaths: probe.unknownPaths ?? [], unspecifiedPaths: [], facts: [], conflicts: [], unresolvedItems: [], decisionTrace: [] };
|
|
339
339
|
const ontologyInstance = { ...ontologyBase, instanceHash: computeOntologyInstanceHash({ ...ontologyBase, instanceHash: '' }) };
|
|
340
|
-
const intents = (probe.intents ?? []).map((intent) => ({ ...fixtureChangeIntent(intent.id, intent.operation, intent.targetPath, intent.requestedValue), importance: intent.importance ?? 'required' }));
|
|
340
|
+
const intents = (probe.intents ?? []).map((intent) => ({ ...fixtureChangeIntent(intent.id, intent.operation, intent.targetPath, intent.requestedValue), importance: intent.importance ?? 'required', ...(intent.sourceHintIds === undefined ? {} : { sourceHintIds: [...intent.sourceHintIds].sort(compare) }) }));
|
|
341
341
|
const waivers = probe.waiverTarget ? [createConstraintWaiver({ schemaVersion: 'voce.constraint-waiver/v1alpha1', id: `waiver-${probe.id}`, caseId: caseSpec.id, caseRevision: caseSpec.revision, contextHash: context.contextHash, targetId: probe.waiverTarget, authority: 'user', decidedBy: 'fixture-reviewer', reasonCode: 'FIXTURE_EXPLICIT_WAIVER', decidedAt: '2026-01-01T00:00:00.000Z' })] : [];
|
|
342
342
|
return fixtureM4ConstraintInput({ caseId: caseSpec.id, caseRevision: caseSpec.revision, context, contextHash: context.contextHash, requestedScopePlanHash: requestedScopePlan.planHash, ontologyInstance, changeIntents: intents, effectiveScenario: resolution.effectiveScenario, waivers });
|
|
343
343
|
}
|
|
344
|
-
function
|
|
344
|
+
function pathRelated(left, right) { return left === right || left.startsWith(`${right}.`) || right.startsWith(`${left}.`); }
|
|
345
|
+
function referenceProbeCandidates(probe, ir) {
|
|
346
|
+
return (probe.references ?? []).map((reference) => {
|
|
347
|
+
const constraintIds = ir.constraints.filter((constraint) => reference.ontologyScopes.some((scope) => constraint.targetPaths.some((target) => pathRelated(scope, target)))).map((constraint) => constraint.id);
|
|
348
|
+
const goalIds = ir.goals.filter((goal) => typeof goal.targetPath === 'string' && reference.ontologyScopes.some((scope) => pathRelated(scope, goal.targetPath))).map((goal) => goal.id);
|
|
349
|
+
const artifact = { id: reference.assetId ?? reference.id, storeId: 'fixture-store', contentHash: sha256({ fixtureReference: reference.id }), mediaType: 'image/png', byteLength: 64, role: 'reference', resolverId: 'fixture-resolver', availability: 'available', retentionClass: 'fixture', redactionPolicy: 'hash-only' };
|
|
350
|
+
return createReferenceCandidate({ schemaVersion: 'voce.reference-candidate/v1alpha1', id: reference.id, assetId: artifact.id, artifact, contentHash: artifact.contentHash, mediaType: artifact.mediaType, byteLength: artifact.byteLength, role: reference.role, ontologyScopes: reference.ontologyScopes, importance: reference.importance, constraintIds, sourceBindingIds: reference.sourceBindingIds ?? [], goalIds, orderKey: reference.orderKey ?? reference.id });
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
function coreProbeEvidence(probe, resolution, caseSpec, profile) {
|
|
345
354
|
const ir = compileConstraints(probeInput(probe, resolution, caseSpec));
|
|
346
|
-
|
|
355
|
+
const evidence = {
|
|
347
356
|
status: ir.status, constraintHash: ir.deterministicSignature, blockingConflictCount: ir.conflicts.filter((item) => item.blocking).length,
|
|
348
357
|
conflictCodes: ir.conflicts.map((item) => item.code).sort(compare), reviewRequirementCount: ir.reviewRequirements.length,
|
|
349
358
|
reviewReasons: ir.reviewRequirements.map((item) => item.reasonCode).sort(compare), waivedWarnings: ir.warnings.filter((item) => item === 'REQUIRED_CONFLICT_WAIVED' || item === 'HARD_CONFLICT_CANNOT_WAIVE').sort(compare),
|
|
350
359
|
degradationCount: ir.degradedPreferences.length, personIntentCount: (probe.intents ?? []).filter((item) => item.targetPath.startsWith('person.')).length,
|
|
360
|
+
constraintTargetPaths: ir.constraints.flatMap((item) => item.targetPaths).sort(compare),
|
|
361
|
+
constraintSourceIds: [...new Set(ir.constraints.flatMap((item) => item.sourceIds))].sort(compare),
|
|
362
|
+
};
|
|
363
|
+
if (!probe.references?.length)
|
|
364
|
+
return evidence;
|
|
365
|
+
const candidates = referenceProbeCandidates(probe, ir);
|
|
366
|
+
const maximumReferenceCount = probe.maximumReferenceCount ?? profile.maximumReferenceCount;
|
|
367
|
+
const plan = planReferences({ schemaVersion: 'voce.reference-planning-input/v1alpha1', caseId: caseSpec.id, caseRevision: caseSpec.revision, contextHash: ir.contextHash, constraintIR: ir, candidates, dependencies: [], profile, budget: { maximumReferenceCount, usedReferenceCount: 0, byteLengthKnown: true, unknownByteLengthAssetIds: [] } });
|
|
368
|
+
evidence.referenceStatus = plan.status;
|
|
369
|
+
evidence.referencePlanHash = plan.planHash;
|
|
370
|
+
evidence.selectedRoles = plan.ordered.map((item) => item.role).sort(compare);
|
|
371
|
+
evidence.omittedRoles = plan.omitted.map((item) => candidates.find((candidate) => candidate.id === item.candidateId)?.role ?? item.candidateId).sort(compare);
|
|
372
|
+
evidence.blockedRoles = plan.blockedReferences.map((item) => candidates.find((candidate) => candidate.id === item.candidateId)?.role ?? item.candidateId).sort(compare);
|
|
373
|
+
evidence.selectedSourceBindingIds = [...new Set(plan.ordered.flatMap((item) => item.sourceBindingIds))].sort(compare);
|
|
374
|
+
if (ir.status !== 'ok' || plan.status !== 'ok') {
|
|
375
|
+
evidence.promptStatus = 'blocked';
|
|
376
|
+
return evidence;
|
|
377
|
+
}
|
|
378
|
+
const pipelineResult = planPipeline({ schemaVersion: 'voce.pipeline-planning-input/v1alpha1', caseId: caseSpec.id, caseRevision: caseSpec.revision, contextHash: ir.contextHash, outputContract: probeInput(probe, resolution, caseSpec).outputContract, constraintIR: ir, referencePlan: plan, profile });
|
|
379
|
+
if (!pipelineResult.pipelinePlan) {
|
|
380
|
+
evidence.promptStatus = 'blocked';
|
|
381
|
+
return evidence;
|
|
382
|
+
}
|
|
383
|
+
const outputContract = probeInput(probe, resolution, caseSpec).outputContract;
|
|
384
|
+
const prompt = compilePromptIR({ schemaVersion: 'voce.prompt-compilation-input/v1alpha1', caseId: caseSpec.id, caseRevision: caseSpec.revision, context: probeInput(probe, resolution, caseSpec).context, contextHash: ir.contextHash, constraintIR: ir, referencePlan: plan, pipelinePlan: pipelineResult.pipelinePlan, outputContract, targetAdapter: { id: profile.adapterId, version: profile.version, digest: profile.adapterDigest }, targetCapabilityProfile: { id: profile.id, version: profile.version, digest: profile.profileHash } });
|
|
385
|
+
evidence.promptStatus = 'ok';
|
|
386
|
+
evidence.promptHash = prompt.deterministicSignature;
|
|
387
|
+
evidence.promptTargetPaths = ir.constraints.filter((constraint) => prompt.constraintCoverage.some((coverage) => coverage.constraintId === constraint.id && (coverage.sectionIds.length > 0 || coverage.referenceMappingIds.length > 0 || coverage.parameterIds.length > 0))).flatMap((constraint) => constraint.targetPaths).sort(compare);
|
|
388
|
+
evidence.promptReferenceRoles = prompt.referenceMappings.map((mapping) => mapping.role).sort(compare);
|
|
389
|
+
return evidence;
|
|
390
|
+
}
|
|
391
|
+
function scenarioContributions(scenario, category) { return scenario[category].filter(isObject); }
|
|
392
|
+
function contributionArray(contributions, field) { return contributions.flatMap((contribution) => Array.isArray(contribution[field]) ? contribution[field].filter(isObject) : []); }
|
|
393
|
+
function semanticCriteriaForScenario(scenario) {
|
|
394
|
+
const criteria = contributionArray(scenarioContributions(scenario, 'reviewTemplates'), 'criteria').map((criterion) => {
|
|
395
|
+
const id = stringField(criterion, 'id', 'REVIEW_TEMPLATE_INVALID');
|
|
396
|
+
const kind = stringField(criterion, 'kind', 'REVIEW_TEMPLATE_INVALID');
|
|
397
|
+
const importance = criterion.importance;
|
|
398
|
+
if (importance !== 'hard' && importance !== 'required' && importance !== 'preferred')
|
|
399
|
+
throw new CliError('REVIEW_TEMPLATE_INVALID', 'Review criterion importance is invalid.', EXIT.contract);
|
|
400
|
+
if (criterion.targetPath !== undefined && typeof criterion.targetPath !== 'string')
|
|
401
|
+
throw new CliError('REVIEW_TEMPLATE_INVALID', 'Review criterion targetPath is invalid.', EXIT.contract);
|
|
402
|
+
if (criterion.prompt !== undefined && typeof criterion.prompt !== 'string')
|
|
403
|
+
throw new CliError('REVIEW_TEMPLATE_INVALID', 'Review criterion prompt is invalid.', EXIT.contract);
|
|
404
|
+
return { id, kind, importance, ...(criterion.targetPath === undefined ? {} : { targetPath: criterion.targetPath }), ...(criterion.prompt === undefined ? {} : { prompt: criterion.prompt }) };
|
|
405
|
+
});
|
|
406
|
+
const byId = new Map();
|
|
407
|
+
for (const criterion of criteria.sort((left, right) => compare(left.id, right.id))) {
|
|
408
|
+
const prior = byId.get(criterion.id);
|
|
409
|
+
if (prior && canonicalize(prior) !== canonicalize(criterion))
|
|
410
|
+
throw new CliError('REVIEW_TEMPLATE_ID_COLLISION', 'Review criteria with one ID disagree.', EXIT.contract);
|
|
411
|
+
byId.set(criterion.id, criterion);
|
|
412
|
+
}
|
|
413
|
+
return [...byId.values()];
|
|
414
|
+
}
|
|
415
|
+
function scenarioEvidence(scenario) {
|
|
416
|
+
const ontology = contributionArray(scenarioContributions(scenario, 'ontologyVocabulary'), 'paths');
|
|
417
|
+
const scopes = scenarioContributions(scenario, 'interpretationScopes');
|
|
418
|
+
const bindings = contributionArray(scopes, 'bindings');
|
|
419
|
+
const promptPaths = scenarioContributions(scenario, 'promptSections').flatMap((contribution) => Array.isArray(contribution.requiredPaths) ? contribution.requiredPaths.filter((item) => typeof item === 'string') : []);
|
|
420
|
+
const criteria = semanticCriteriaForScenario(scenario);
|
|
421
|
+
return {
|
|
422
|
+
ontologyPaths: ontology.map((item) => String(item.path ?? '')).filter(Boolean).sort(compare),
|
|
423
|
+
bindingPolicies: bindings.map((item) => `${String(item.assetRole ?? '')}|${String(item.relation ?? '')}|${String(item.targetPath ?? '')}|${String(item.priority ?? '')}`).sort(compare),
|
|
424
|
+
promptTargetPaths: [...new Set(promptPaths)].sort(compare),
|
|
425
|
+
reviewCriterionIds: criteria.map((item) => item.id).sort(compare),
|
|
426
|
+
reviewTargetPaths: criteria.map((item) => item.targetPath).filter((item) => typeof item === 'string').sort(compare),
|
|
351
427
|
};
|
|
352
428
|
}
|
|
353
429
|
function referenceEvidence(fixture, resolution, caseSpec) {
|
|
@@ -406,13 +482,13 @@ function profileFor(id) {
|
|
|
406
482
|
async function loadProfile(filePath) { const object = record(await readJson(path.resolve(filePath), 'PROFILE_FILE_UNSAFE'), 'PROFILE_JSON_INVALID'); return profileFor(stringField(object, 'id', 'PROFILE_INVALID')); }
|
|
407
483
|
function profilePin(profile) { return { id: profile.id, version: profile.version, digest: profile.profileHash }; }
|
|
408
484
|
function toolPin(id, version) { return { id, version, digest: sha256({ id, version }) }; }
|
|
409
|
-
function defaultCase(doc, packId) {
|
|
485
|
+
function defaultCase(doc, packId, packVersion) {
|
|
410
486
|
assertKnown(doc, ['schemaVersion', 'id', 'revision', 'fixtureId', 'mode', 'scenario', 'userIntent', 'assets', 'trustedMetadata', 'policies', 'requestedOutput'], 'CASE_UNKNOWN_FIELD');
|
|
411
487
|
const id = typeof doc.id === 'string' ? doc.id : `${packId}-case`;
|
|
412
488
|
const revision = typeof doc.revision === 'number' ? doc.revision : 1;
|
|
413
489
|
const output = isObject(doc.requestedOutput) ? doc.requestedOutput : { artifactKind: 'image', dataType: 'image', mediaTypes: ['image/png'], cardinality: { min: 1, max: 1 }, background: 'opaque', allowAlpha: false };
|
|
414
490
|
const asset = { id: 'ref-01', storeId: 'fixture-store', contentHash: sha256({ fixture: `${id}:ref-01` }), mediaType: 'image/png', byteLength: 64, role: 'reference', resolverId: 'fixture-resolver', availability: 'available', retentionClass: 'fixture', redactionPolicy: 'hash-only' };
|
|
415
|
-
return { schemaVersion: 'voce.case-spec/v1alpha1', id, revision, mode: 'manual', scenario: { root: { packId, versionRange:
|
|
491
|
+
return { schemaVersion: 'voce.case-spec/v1alpha1', id, revision, mode: 'manual', scenario: { root: { packId, versionRange: packVersion }, extensions: [] }, userIntent: typeof doc.userIntent === 'string' ? doc.userIntent : 'Offline fixture case.', assets: [asset], trustedMetadata: [], policies: { schemaVersion: 'voce.case-policies/v1alpha1', observationConfirmation: 'explicit', bindingConfirmation: 'explicit', allowDeclaredDefaults: true }, requestedOutput: output };
|
|
416
492
|
}
|
|
417
493
|
async function compileInputs(casePath, scenarioPath, profilePath) {
|
|
418
494
|
const caseDoc = record(await readJson(path.resolve(casePath), 'CASE_FILE_UNSAFE'), 'CASE_JSON_INVALID');
|
|
@@ -422,14 +498,14 @@ async function compileInputs(casePath, scenarioPath, profilePath) {
|
|
|
422
498
|
const resolution = registry.resolve({ root: { packId: loaded.descriptor.manifest.packId, versionRange: loaded.descriptor.manifest.version }, extensions: [] });
|
|
423
499
|
if (resolution.status !== 'resolved')
|
|
424
500
|
throw new CliError('PACK_RESOLUTION_BLOCKED', 'ScenarioPack resolution is blocked.', EXIT.contract);
|
|
425
|
-
const caseSpec = defaultCase(caseDoc, loaded.descriptor.manifest.packId);
|
|
501
|
+
const caseSpec = defaultCase(caseDoc, loaded.descriptor.manifest.packId, loaded.descriptor.manifest.version);
|
|
426
502
|
const fixtureId = typeof caseDoc.fixtureId === 'string' ? caseDoc.fixtureId : caseSpec.id;
|
|
427
503
|
const fixture = loaded.fixtures.find((candidate) => candidate.id === fixtureId) ?? loaded.fixtures[0] ?? { id: fixtureId, profileId: MOCK_IMAGE_PROFILE.id };
|
|
428
504
|
const profile = await loadProfile(profilePath);
|
|
429
505
|
const prompt = fixtureM5Candidate(fixtureM5PromptIR(profile));
|
|
430
506
|
const input = fixtureM5ExecutionInput(profile);
|
|
431
|
-
const coreProbes = Object.fromEntries((fixture.coreProbes ?? []).sort((left, right) => compare(left.id, right.id)).map((probe) => [probe.id, coreProbeEvidence(probe, resolution, caseSpec)]));
|
|
432
|
-
const acceptance = { resolution: { status: resolution.status, selectedCount: resolution.report.selected.length, effectiveScenarioHash: resolution.effectiveScenario.effectiveScenarioHash }, reference: referenceEvidence(fixture, resolution, caseSpec), coreProbes, compile: { constraintHash: input.constraintIR.deterministicSignature, referencePlanHash: input.referencePlan.planHash, pipelinePlanHash: input.pipelinePlan.planHash } };
|
|
507
|
+
const coreProbes = Object.fromEntries((fixture.coreProbes ?? []).sort((left, right) => compare(left.id, right.id)).map((probe) => [probe.id, coreProbeEvidence(probe, resolution, caseSpec, profile)]));
|
|
508
|
+
const acceptance = { resolution: { status: resolution.status, selectedCount: resolution.report.selected.length, effectiveScenarioHash: resolution.effectiveScenario.effectiveScenarioHash }, scenario: scenarioEvidence(resolution.effectiveScenario), reference: referenceEvidence(fixture, resolution, caseSpec), coreProbes, compile: { constraintHash: input.constraintIR.deterministicSignature, referencePlanHash: input.referencePlan.planHash, pipelinePlanHash: input.pipelinePlan.planHash } };
|
|
433
509
|
return { loaded, resolution, caseSpec, profile, fixture, input, prompt, acceptance };
|
|
434
510
|
}
|
|
435
511
|
function bundlePins(profile, scenario) { return { tool: toolPin(TOOL_ID, CLI_VERSION), core: toolPin('@voce-engine/core', CORE_VERSION), contracts: toolPin('@voce-engine/contracts', CONTRACTS_VERSION), scenario: { id: scenario.descriptor.manifest.packId, version: scenario.descriptor.manifest.version, digest: scenario.descriptor.packageDigest }, profile: profilePin(profile) }; }
|
|
@@ -546,12 +622,12 @@ async function compileCommand(args) {
|
|
|
546
622
|
const written = await writeBundle(outputPath, 'compiled', { id: result.caseSpec.id, revision: result.caseSpec.revision }, bundlePins(result.profile, result.loaded), payload);
|
|
547
623
|
return outputSummary(written.manifest, { promptGuard: guard.status, scenario: result.loaded.descriptor.manifest.packId });
|
|
548
624
|
}
|
|
549
|
-
async function semanticForRun(run, artifacts, profile) {
|
|
625
|
+
async function semanticForRun(run, artifacts, profile, criteria) {
|
|
550
626
|
const reviewer = new FixtureSemanticReviewer();
|
|
551
627
|
const inputHash = sha256({ runId: run.id, artifacts: artifacts.map((item) => item.contentHash).sort() });
|
|
552
628
|
const model = reviewer.version;
|
|
553
629
|
const adapter = { id: 'voce.fixture-semantic-reviewer-adapter', version: '1.0.0', digest: sha256({ id: 'voce.fixture-semantic-reviewer-adapter', version: '1.0.0' }) };
|
|
554
|
-
const requestBase = { schemaVersion: 'voce.semantic-review-request/v1alpha1', id: `semantic-${run.id}`, caseId: run.caseId, caseRevision: run.caseRevision, contextHash: run.contextHash, inputHash, outputArtifacts: artifacts, criteria: [{ id: 'fixture.semantic', kind: 'semantic_fidelity', importance: 'required', prompt: 'Offline fixture semantic proposal.' }], model, adapter, profile: { id: profile.id, version: profile.version, digest: profile.profileHash }, authorizationId: `semantic-auth-${run.id}`, destination: 'local', allowedEvidenceRegionIds: [], dataCategories: ['image'], budget: { schemaVersion: 'voce.budget/v1alpha1', id: `semantic-budget-${run.id}`, maximumCalls: 1, maximumRetries: 0, timeoutMs: 60_000 } };
|
|
630
|
+
const requestBase = { schemaVersion: 'voce.semantic-review-request/v1alpha1', id: `semantic-${run.id}`, caseId: run.caseId, caseRevision: run.caseRevision, contextHash: run.contextHash, inputHash, outputArtifacts: artifacts, criteria: criteria.length ? criteria : [{ id: 'fixture.semantic', kind: 'semantic_fidelity', importance: 'required', prompt: 'Offline fixture semantic proposal.' }], model, adapter, profile: { id: profile.id, version: profile.version, digest: profile.profileHash }, authorizationId: `semantic-auth-${run.id}`, destination: 'local', allowedEvidenceRegionIds: [], dataCategories: ['image'], budget: { schemaVersion: 'voce.budget/v1alpha1', id: `semantic-budget-${run.id}`, maximumCalls: 1, maximumRetries: 0, timeoutMs: 60_000 } };
|
|
555
631
|
const request = { ...requestBase, requestHash: computeSemanticReviewRequestHash(requestBase) };
|
|
556
632
|
const authorization = fixtureM6Authorization({ id: request.authorizationId, caseId: request.caseId, caseRevision: request.caseRevision, contextHash: request.contextHash, stepId: request.id, purpose: 'semantic_review', inputHash, artifactHashes: artifacts.map((item) => item.contentHash), adapter, profileDigest: request.profile.digest, destination: 'local', dataCategories: ['image'], budget: request.budget, modelId: model.id, modelVersion: model.version });
|
|
557
633
|
const execution = await executeSemanticReview(reviewer, request, authorization);
|
|
@@ -578,11 +654,13 @@ async function runCommand(args) {
|
|
|
578
654
|
const outputContract = { artifactKind: 'image', dataType: 'image', mediaTypes: ['image/png'], cardinality: { min: 1, max: 1 }, background: 'opaque', allowAlpha: false };
|
|
579
655
|
const structural = validateStructuralImage({ schemaVersion: 'voce.structural-validation-input/v1alpha1', id: `structural-${run.id}`, artifacts: [{ artifact: structuralArtifact, bytes: FIXTURE_M6_OPAQUE_PNG }], outputContract, expectedCardinality: { min: 1, max: 1 } });
|
|
580
656
|
const fixture = bundle.payload.fixture;
|
|
657
|
+
const scenario = bundle.payload.scenario?.effectiveScenario;
|
|
658
|
+
const semanticCriteria = scenario ? semanticCriteriaForScenario(scenario) : [];
|
|
581
659
|
let semanticProposal;
|
|
582
660
|
const semanticReceipts = [];
|
|
583
661
|
const reconciliation = [];
|
|
584
662
|
if (fixture?.semanticReview) {
|
|
585
|
-
const semantic = await semanticForRun(run, [structuralArtifact, ...artifacts], profileFor(String(bundle.payload.profile?.id ?? MOCK_IMAGE_PROFILE.id)));
|
|
663
|
+
const semantic = await semanticForRun(run, [structuralArtifact, ...artifacts], profileFor(String(bundle.payload.profile?.id ?? MOCK_IMAGE_PROFILE.id)), semanticCriteria);
|
|
586
664
|
semanticProposal = semantic.report;
|
|
587
665
|
semanticReceipts.push(semantic.receipt);
|
|
588
666
|
reconciliation.push(semantic.remote);
|
|
@@ -591,7 +669,7 @@ async function runCommand(args) {
|
|
|
591
669
|
const evaluation = compileEvaluationReport({ run: { id: run.id, technicalOutcome: run.technicalOutcome, state: run.state, contextHash: run.contextHash, pipelinePlanHash: run.pipelinePlanHash, promptArtifactHash: run.promptArtifactHash }, structural, semanticProposal, humanAcceptance: human, cleanup: result.cleanupReceipts, replay: { mode: 'artifact', status: 'available', code: 'REPLAY_AVAILABLE', artifactIds: artifacts.map((item) => item.id) }, artifacts: [structuralArtifact, ...artifacts], sourceHashes: { compiledBundle: bundle.manifest.semanticHash, executionRun: computeExecutionRunHash(run) } });
|
|
592
670
|
const traceModel = traceModelFromExecution({ run, receipts: [...result.receipts, ...semanticReceipts], cleanup: result.cleanupReceipts, reconciliation: [...result.remoteCallRuns, ...reconciliation], artifacts: [structuralArtifact, ...artifacts], structural, semanticProposal, humanAcceptance: human, budgets: input.pipelinePlan.steps.map((step) => step.budget), destinations: input.pipelinePlan.dataTransfers.map((item) => item.destination), constraintHash: input.constraintIR.deterministicSignature, referencePlanHash: input.referencePlan.planHash, promptHash: input.executionAuthorization.promptArtifactHash, warnings: result.reasons });
|
|
593
671
|
const acceptance = isObject(bundle.payload.acceptance) ? clone(bundle.payload.acceptance) : {};
|
|
594
|
-
const runEvidence = { executionStatus: result.status, executionCode: result.code, receiptCount: result.receipts.length + semanticReceipts.length, receiptAdapters: [...result.receipts, ...semanticReceipts].map((item) => item.adapterId).sort(compare), artifactMediaTypes: artifacts.map((item) => item.mediaType).sort(compare), artifactRoles: artifacts.map((item) => item.role).sort(compare), structuralStatus: structural.status, semanticStatus: semanticProposal?.status ?? 'absent', humanStatus: human?.status ?? 'absent', evaluationStatus: evaluation.status, traceModelPresent: true, traceModelHash: traceModel.modelHash };
|
|
672
|
+
const runEvidence = { executionStatus: result.status, executionCode: result.code, receiptCount: result.receipts.length + semanticReceipts.length, receiptAdapters: [...result.receipts, ...semanticReceipts].map((item) => item.adapterId).sort(compare), artifactMediaTypes: artifacts.map((item) => item.mediaType).sort(compare), artifactRoles: artifacts.map((item) => item.role).sort(compare), structuralStatus: structural.status, semanticStatus: semanticProposal?.status ?? 'absent', semanticCriterionIds: semanticProposal?.findings.map((item) => item.criterionId).sort(compare) ?? [], semanticFindingStatuses: semanticProposal?.findings.map((item) => item.status).sort(compare) ?? [], humanStatus: human?.status ?? 'absent', evaluationStatus: evaluation.status, traceModelPresent: true, traceModelHash: traceModel.modelHash };
|
|
595
673
|
acceptance.run = runEvidence;
|
|
596
674
|
const runAssertions = fixture ? assertFixtureAssertions(fixture, acceptance, 'run') : [];
|
|
597
675
|
acceptance.assertions = [...(Array.isArray(acceptance.assertions) ? acceptance.assertions : []), ...runAssertions].sort((left, right) => compare(String(left.id), String(right.id)));
|
|
@@ -615,15 +693,16 @@ async function packTestCommand(source) {
|
|
|
615
693
|
const resolution = registry.resolve({ root: { packId: loaded.descriptor.manifest.packId, versionRange: loaded.descriptor.manifest.version }, extensions: [] });
|
|
616
694
|
if (resolution.status !== 'resolved')
|
|
617
695
|
throw new CliError('PACK_RESOLUTION_BLOCKED', 'ScenarioPack resolution is blocked.', EXIT.contract);
|
|
696
|
+
const semanticCriteria = semanticCriteriaForScenario(resolution.effectiveScenario);
|
|
618
697
|
const results = [];
|
|
619
698
|
for (const fixture of loaded.fixtures) {
|
|
620
699
|
const profile = profileFor(fixture.profileId ?? MOCK_IMAGE_PROFILE.id);
|
|
621
|
-
const caseSpec = defaultCase({ id: fixture.id }, loaded.descriptor.manifest.packId);
|
|
700
|
+
const caseSpec = defaultCase({ id: fixture.id }, loaded.descriptor.manifest.packId, loaded.descriptor.manifest.version);
|
|
622
701
|
const input = fixtureM5ExecutionInput(profile);
|
|
623
702
|
const prompt = fixtureM5Candidate(fixtureM5PromptIR(profile));
|
|
624
703
|
const guard = guardPromptCandidate(fixtureM5GuardInput(fixtureM5PromptIR(profile), prompt));
|
|
625
|
-
const coreProbes = Object.fromEntries((fixture.coreProbes ?? []).sort((left, right) => compare(left.id, right.id)).map((probe) => [probe.id, coreProbeEvidence(probe, resolution, caseSpec)]));
|
|
626
|
-
const acceptance = { resolution: { status: resolution.status, selectedCount: resolution.report.selected.length, effectiveScenarioHash: resolution.effectiveScenario.effectiveScenarioHash }, reference: referenceEvidence(fixture, resolution, caseSpec), coreProbes, compile: { constraintHash: input.constraintIR.deterministicSignature, referencePlanHash: input.referencePlan.planHash, pipelinePlanHash: input.pipelinePlan.planHash, promptGuard: guard.status } };
|
|
704
|
+
const coreProbes = Object.fromEntries((fixture.coreProbes ?? []).sort((left, right) => compare(left.id, right.id)).map((probe) => [probe.id, coreProbeEvidence(probe, resolution, caseSpec, profile)]));
|
|
705
|
+
const acceptance = { resolution: { status: resolution.status, selectedCount: resolution.report.selected.length, effectiveScenarioHash: resolution.effectiveScenario.effectiveScenarioHash }, scenario: scenarioEvidence(resolution.effectiveScenario), reference: referenceEvidence(fixture, resolution, caseSpec), coreProbes, compile: { constraintHash: input.constraintIR.deterministicSignature, referencePlanHash: input.referencePlan.planHash, pipelinePlanHash: input.pipelinePlan.planHash, promptGuard: guard.status } };
|
|
627
706
|
const result = executeOffline(input);
|
|
628
707
|
const run = result.run ?? result.executionRun;
|
|
629
708
|
if (!run)
|
|
@@ -636,7 +715,7 @@ async function packTestCommand(source) {
|
|
|
636
715
|
const semanticReceipts = [];
|
|
637
716
|
const reconciliation = [];
|
|
638
717
|
if (fixture.semanticReview) {
|
|
639
|
-
const semantic = await semanticForRun(run, [structuralArtifact, ...artifacts], profile);
|
|
718
|
+
const semantic = await semanticForRun(run, [structuralArtifact, ...artifacts], profile, semanticCriteria);
|
|
640
719
|
semanticProposal = semantic.report;
|
|
641
720
|
semanticReceipts.push(semantic.receipt);
|
|
642
721
|
reconciliation.push(semantic.remote);
|
|
@@ -645,7 +724,7 @@ async function packTestCommand(source) {
|
|
|
645
724
|
const compiledHash = sha256({ packId: loaded.descriptor.manifest.packId, fixtureId: fixture.id });
|
|
646
725
|
const evaluation = compileEvaluationReport({ run: { id: run.id, technicalOutcome: run.technicalOutcome, state: run.state, contextHash: run.contextHash, pipelinePlanHash: run.pipelinePlanHash, promptArtifactHash: run.promptArtifactHash }, structural, semanticProposal, humanAcceptance: human, cleanup: result.cleanupReceipts, replay: { mode: 'artifact', status: 'available', code: 'REPLAY_AVAILABLE', artifactIds: artifacts.map((item) => item.id) }, artifacts: [structuralArtifact, ...artifacts], sourceHashes: { compiledBundle: compiledHash, executionRun: computeExecutionRunHash(run) } });
|
|
647
726
|
const traceModel = traceModelFromExecution({ run, receipts: [...result.receipts, ...semanticReceipts], cleanup: result.cleanupReceipts, reconciliation: [...result.remoteCallRuns, ...reconciliation], artifacts: [structuralArtifact, ...artifacts], structural, semanticProposal, humanAcceptance: human, budgets: input.pipelinePlan.steps.map((step) => step.budget), destinations: input.pipelinePlan.dataTransfers.map((item) => item.destination), constraintHash: input.constraintIR.deterministicSignature, referencePlanHash: input.referencePlan.planHash, promptHash: input.executionAuthorization.promptArtifactHash, warnings: result.reasons });
|
|
648
|
-
acceptance.run = { executionStatus: result.status, executionCode: result.code, receiptCount: result.receipts.length + semanticReceipts.length, receiptAdapters: [...result.receipts, ...semanticReceipts].map((item) => item.adapterId).sort(compare), artifactMediaTypes: artifacts.map((item) => item.mediaType).sort(compare), artifactRoles: artifacts.map((item) => item.role).sort(compare), structuralStatus: structural.status, semanticStatus: semanticProposal?.status ?? 'absent', humanStatus: human?.status ?? 'absent', evaluationStatus: evaluation.status, traceModelPresent: true, traceModelHash: traceModel.modelHash };
|
|
727
|
+
acceptance.run = { executionStatus: result.status, executionCode: result.code, receiptCount: result.receipts.length + semanticReceipts.length, receiptAdapters: [...result.receipts, ...semanticReceipts].map((item) => item.adapterId).sort(compare), artifactMediaTypes: artifacts.map((item) => item.mediaType).sort(compare), artifactRoles: artifacts.map((item) => item.role).sort(compare), structuralStatus: structural.status, semanticStatus: semanticProposal?.status ?? 'absent', semanticCriterionIds: semanticProposal?.findings.map((item) => item.criterionId).sort(compare) ?? [], semanticFindingStatuses: semanticProposal?.findings.map((item) => item.status).sort(compare) ?? [], humanStatus: human?.status ?? 'absent', evaluationStatus: evaluation.status, traceModelPresent: true, traceModelHash: traceModel.modelHash };
|
|
649
728
|
const assertions = assertFixtureAssertions(fixture, acceptance, 'all');
|
|
650
729
|
const expected = fixture.expectedStatus ?? 'completed';
|
|
651
730
|
const accepted = result.status === expected || (expected === 'needs_review' && result.status === 'completed');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voce-engine/cli",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.3",
|
|
4
4
|
"description": "Offline-first command line tools for the VOCE v0.1 release candidate.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"tag": "next"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@voce-engine/contracts": "0.1.0-rc.
|
|
40
|
-
"@voce-engine/core": "0.1.0-rc.
|
|
41
|
-
"@voce-engine/testkit": "0.1.0-rc.
|
|
39
|
+
"@voce-engine/contracts": "0.1.0-rc.3",
|
|
40
|
+
"@voce-engine/core": "0.1.0-rc.3",
|
|
41
|
+
"@voce-engine/testkit": "0.1.0-rc.3"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsc -b"
|