@cleocode/contracts 2026.5.111 → 2026.5.113
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/dist/__tests__/cli-meta-suggested-next.test.d.ts +21 -0
- package/dist/__tests__/cli-meta-suggested-next.test.d.ts.map +1 -0
- package/dist/__tests__/cli-meta-suggested-next.test.js +70 -0
- package/dist/__tests__/cli-meta-suggested-next.test.js.map +1 -0
- package/dist/__tests__/evidence-atom-schema.test.d.ts +16 -0
- package/dist/__tests__/evidence-atom-schema.test.d.ts.map +1 -0
- package/dist/__tests__/evidence-atom-schema.test.js +394 -0
- package/dist/__tests__/evidence-atom-schema.test.js.map +1 -0
- package/dist/config/__tests__/manifest.test.d.ts +13 -0
- package/dist/config/__tests__/manifest.test.d.ts.map +1 -0
- package/dist/config/__tests__/manifest.test.js +143 -0
- package/dist/config/__tests__/manifest.test.js.map +1 -0
- package/dist/config/manifest.d.ts +158 -0
- package/dist/config/manifest.d.ts.map +1 -0
- package/dist/config/manifest.js +123 -0
- package/dist/config/manifest.js.map +1 -0
- package/dist/docs/__tests__/provenance.test.d.ts +14 -0
- package/dist/docs/__tests__/provenance.test.d.ts.map +1 -0
- package/dist/docs/__tests__/provenance.test.js +579 -0
- package/dist/docs/__tests__/provenance.test.js.map +1 -0
- package/dist/docs/provenance.d.ts +731 -0
- package/dist/docs/provenance.d.ts.map +1 -0
- package/dist/docs/provenance.js +258 -0
- package/dist/docs/provenance.js.map +1 -0
- package/dist/docs-taxonomy.d.ts +24 -0
- package/dist/docs-taxonomy.d.ts.map +1 -1
- package/dist/docs-taxonomy.js +27 -0
- package/dist/docs-taxonomy.js.map +1 -1
- package/dist/doctor.d.ts +101 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/errors.d.ts +4 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +4 -0
- package/dist/errors.js.map +1 -1
- package/dist/evidence-atom-schema.d.ts +407 -0
- package/dist/evidence-atom-schema.d.ts.map +1 -0
- package/dist/evidence-atom-schema.js +505 -0
- package/dist/evidence-atom-schema.js.map +1 -0
- package/dist/exit-codes.d.ts +37 -0
- package/dist/exit-codes.d.ts.map +1 -1
- package/dist/exit-codes.js +37 -0
- package/dist/exit-codes.js.map +1 -1
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/invariants/__tests__/adr-056-release.test.d.ts +16 -0
- package/dist/invariants/__tests__/adr-056-release.test.d.ts.map +1 -0
- package/dist/invariants/__tests__/adr-056-release.test.js +88 -0
- package/dist/invariants/__tests__/adr-056-release.test.js.map +1 -0
- package/dist/invariants/__tests__/adr-070-orchestration.test.d.ts +22 -0
- package/dist/invariants/__tests__/adr-070-orchestration.test.d.ts.map +1 -0
- package/dist/invariants/__tests__/adr-070-orchestration.test.js +151 -0
- package/dist/invariants/__tests__/adr-070-orchestration.test.js.map +1 -0
- package/dist/invariants/__tests__/registry.test.d.ts +14 -0
- package/dist/invariants/__tests__/registry.test.d.ts.map +1 -0
- package/dist/invariants/__tests__/registry.test.js +113 -0
- package/dist/invariants/__tests__/registry.test.js.map +1 -0
- package/dist/invariants/adr-056-release.d.ts +42 -0
- package/dist/invariants/adr-056-release.d.ts.map +1 -0
- package/dist/invariants/adr-056-release.js +143 -0
- package/dist/invariants/adr-056-release.js.map +1 -0
- package/dist/invariants/adr-070-orchestration.d.ts +73 -0
- package/dist/invariants/adr-070-orchestration.d.ts.map +1 -0
- package/dist/invariants/adr-070-orchestration.js +290 -0
- package/dist/invariants/adr-070-orchestration.js.map +1 -0
- package/dist/invariants/adr-073-saga.d.ts +32 -0
- package/dist/invariants/adr-073-saga.d.ts.map +1 -0
- package/dist/invariants/adr-073-saga.js +155 -0
- package/dist/invariants/adr-073-saga.js.map +1 -0
- package/dist/invariants/index.d.ts +162 -0
- package/dist/invariants/index.d.ts.map +1 -0
- package/dist/invariants/index.js +118 -0
- package/dist/invariants/index.js.map +1 -0
- package/dist/operations/__tests__/input-contract.test.d.ts +20 -0
- package/dist/operations/__tests__/input-contract.test.d.ts.map +1 -0
- package/dist/operations/__tests__/input-contract.test.js +158 -0
- package/dist/operations/__tests__/input-contract.test.js.map +1 -0
- package/dist/operations/docs.d.ts +16 -0
- package/dist/operations/docs.d.ts.map +1 -1
- package/dist/operations/input-contract.d.ts +267 -0
- package/dist/operations/input-contract.d.ts.map +1 -0
- package/dist/operations/input-contract.js +29 -0
- package/dist/operations/input-contract.js.map +1 -0
- package/dist/templates/__tests__/manifest.test.d.ts +18 -0
- package/dist/templates/__tests__/manifest.test.d.ts.map +1 -0
- package/dist/templates/__tests__/manifest.test.js +123 -0
- package/dist/templates/__tests__/manifest.test.js.map +1 -0
- package/dist/templates/manifest.d.ts +186 -0
- package/dist/templates/manifest.d.ts.map +1 -0
- package/dist/templates/manifest.js +165 -0
- package/dist/templates/manifest.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/cli-meta-suggested-next.test.ts +76 -0
- package/src/__tests__/evidence-atom-schema.test.ts +499 -0
- package/src/config/__tests__/manifest.test.ts +176 -0
- package/src/config/manifest.ts +218 -0
- package/src/docs/__tests__/__snapshots__/provenance.test.ts.snap +252 -0
- package/src/docs/__tests__/provenance.test.ts +648 -0
- package/src/docs/provenance.ts +601 -0
- package/src/docs-taxonomy.ts +55 -0
- package/src/doctor.ts +111 -0
- package/src/errors.ts +4 -0
- package/src/evidence-atom-schema.ts +628 -0
- package/src/exit-codes.ts +39 -0
- package/src/index.ts +129 -0
- package/src/invariants/__tests__/adr-056-release.test.ts +102 -0
- package/src/invariants/__tests__/adr-070-orchestration.test.ts +186 -0
- package/src/invariants/__tests__/registry.test.ts +136 -0
- package/src/invariants/adr-056-release.ts +154 -0
- package/src/invariants/adr-070-orchestration.ts +317 -0
- package/src/invariants/adr-073-saga.ts +167 -0
- package/src/invariants/index.ts +222 -0
- package/src/operations/__tests__/input-contract.test.ts +188 -0
- package/src/operations/docs.ts +16 -0
- package/src/operations/input-contract.ts +301 -0
- package/src/templates/__tests__/manifest.test.ts +140 -0
- package/src/templates/manifest.ts +208 -0
package/src/index.ts
CHANGED
|
@@ -224,6 +224,21 @@ export type {
|
|
|
224
224
|
ConduitTopicSubscribeOptions,
|
|
225
225
|
ConduitUnsubscribe,
|
|
226
226
|
} from './conduit.js';
|
|
227
|
+
// === Config Manifest (T9876 / Saga T9855) ===
|
|
228
|
+
export type {
|
|
229
|
+
ConfigManifestEntry,
|
|
230
|
+
ConfigManifestScope,
|
|
231
|
+
ConfigScope,
|
|
232
|
+
DriftDetection,
|
|
233
|
+
} from './config/manifest.js';
|
|
234
|
+
export {
|
|
235
|
+
CLEO_CONFIG_MANIFEST,
|
|
236
|
+
CONFIG_MANIFEST_ENTRIES,
|
|
237
|
+
configManifestEntrySchema,
|
|
238
|
+
GLOBAL_CLEO_CONFIG_MANIFEST,
|
|
239
|
+
PROJECT_CONTEXT_MANIFEST,
|
|
240
|
+
PROJECT_INFO_MANIFEST,
|
|
241
|
+
} from './config/manifest.js';
|
|
227
242
|
// === Configuration Types ===
|
|
228
243
|
export type {
|
|
229
244
|
BackupConfig,
|
|
@@ -312,6 +327,42 @@ export { CANONICAL_DOMAINS } from './dispatch/identity.js';
|
|
|
312
327
|
export type { OperationDef, Resolution } from './dispatch/operation-def.js';
|
|
313
328
|
// === Dispatch OPERATIONS data + builder helpers (T10061 — T9833b / E-CLI-BOUNDARY / SG-ARCH-SOLID) ===
|
|
314
329
|
export { defineDomain, defineOp, OPERATIONS } from './dispatch/operations-registry.js';
|
|
330
|
+
// === Docs Provenance Graph (T10166 / Saga T9855 / E12) ===
|
|
331
|
+
export type {
|
|
332
|
+
DocLifecycleStatus,
|
|
333
|
+
DocProvenanceResponse,
|
|
334
|
+
ProvenanceDecisionNode,
|
|
335
|
+
ProvenanceDocNode,
|
|
336
|
+
ProvenanceEdge,
|
|
337
|
+
ProvenanceEdgeRelation,
|
|
338
|
+
ProvenanceMemoryNode,
|
|
339
|
+
ProvenanceNode,
|
|
340
|
+
ProvenanceNodeKind,
|
|
341
|
+
ProvenanceSessionNode,
|
|
342
|
+
ProvenanceTaskNode,
|
|
343
|
+
} from './docs/provenance.js';
|
|
344
|
+
export {
|
|
345
|
+
DOC_LIFECYCLE_STATUSES,
|
|
346
|
+
docLifecycleStatusSchema,
|
|
347
|
+
docProvenanceResponseSchema,
|
|
348
|
+
isDocProvenanceResponse,
|
|
349
|
+
isProvenanceDecisionNode,
|
|
350
|
+
isProvenanceDocNode,
|
|
351
|
+
isProvenanceMemoryNode,
|
|
352
|
+
isProvenanceSessionNode,
|
|
353
|
+
isProvenanceTaskNode,
|
|
354
|
+
PROVENANCE_EDGE_RELATIONS,
|
|
355
|
+
PROVENANCE_NODE_KINDS,
|
|
356
|
+
provenanceDecisionNodeSchema,
|
|
357
|
+
provenanceDocNodeSchema,
|
|
358
|
+
provenanceEdgeRelationSchema,
|
|
359
|
+
provenanceEdgeSchema,
|
|
360
|
+
provenanceMemoryNodeSchema,
|
|
361
|
+
provenanceNodeKindSchema,
|
|
362
|
+
provenanceNodeSchema,
|
|
363
|
+
provenanceSessionNodeSchema,
|
|
364
|
+
provenanceTaskNodeSchema,
|
|
365
|
+
} from './docs/provenance.js';
|
|
315
366
|
// === DocsAccessor Contracts (T9063) ===
|
|
316
367
|
export type {
|
|
317
368
|
DocExportFormat,
|
|
@@ -342,6 +393,7 @@ export {
|
|
|
342
393
|
// === Doctor: DB-Substrate Survey (T10307 — Saga T10281 / Epic T10282) ===
|
|
343
394
|
// === Doctor: Legacy-Backup Walker (T10309 — Saga T10281 / Epic T10282) ===
|
|
344
395
|
// === Doctor: Cross-DB Invariants (T10323 — Saga T10281 / Epic T10285) ===
|
|
396
|
+
// === Doctor: Invariant Registry Audit (T10340 — Saga T10326 / Epic T10327) ===
|
|
345
397
|
export type {
|
|
346
398
|
ComprehensiveAuditResult,
|
|
347
399
|
DbCrossDbInvariantId,
|
|
@@ -356,6 +408,10 @@ export type {
|
|
|
356
408
|
DbSubstrateSurveyOptions,
|
|
357
409
|
DbSubstrateWarning,
|
|
358
410
|
DbSubstrateWarningKind,
|
|
411
|
+
InvariantAuditEntry,
|
|
412
|
+
InvariantAuditResult,
|
|
413
|
+
InvariantAuditStatus,
|
|
414
|
+
InvariantAuditViolation,
|
|
359
415
|
LegacyBackupEntry,
|
|
360
416
|
LegacyBackupOriginHint,
|
|
361
417
|
LegacyBackupRecommendation,
|
|
@@ -415,6 +471,31 @@ export {
|
|
|
415
471
|
normalizeError,
|
|
416
472
|
ThinAgentViolationError,
|
|
417
473
|
} from './errors.js';
|
|
474
|
+
// === ADR-051 Evidence Atom Grammar (T10337 — Saga T10326) ===
|
|
475
|
+
export type {
|
|
476
|
+
EvidenceAtom as EvidenceAtomInput,
|
|
477
|
+
EvidenceAtomKind,
|
|
478
|
+
EvidenceValidationResult,
|
|
479
|
+
GateEvidenceRequirement,
|
|
480
|
+
} from './evidence-atom-schema.js';
|
|
481
|
+
export {
|
|
482
|
+
callsiteCoverageAtomSchema,
|
|
483
|
+
commitAtomSchema,
|
|
484
|
+
decisionAtomSchema,
|
|
485
|
+
EvidenceAtomSchema,
|
|
486
|
+
EvidenceParseError,
|
|
487
|
+
filesAtomSchema,
|
|
488
|
+
formatGateRequirement,
|
|
489
|
+
GATE_EVIDENCE_REQUIREMENTS,
|
|
490
|
+
locDropAtomSchema,
|
|
491
|
+
noteAtomSchema,
|
|
492
|
+
parseEvidenceString,
|
|
493
|
+
prAtomSchema,
|
|
494
|
+
testRunAtomSchema,
|
|
495
|
+
toolAtomSchema,
|
|
496
|
+
urlAtomSchema,
|
|
497
|
+
validateEvidenceForGate,
|
|
498
|
+
} from './evidence-atom-schema.js';
|
|
418
499
|
// === Evidence Record Types (IVTR typed proof artifacts) ===
|
|
419
500
|
export type {
|
|
420
501
|
CommandOutputRecord,
|
|
@@ -455,6 +536,9 @@ export {
|
|
|
455
536
|
E_EVIDENCE_INSUFFICIENT,
|
|
456
537
|
// SPEC-T9345 release pipeline v2 error code names (T9530)
|
|
457
538
|
E_GH_NOT_AUTHENTICATED,
|
|
539
|
+
// T10341 — typed CLI-layer validation for --severity + --pipeline-stage
|
|
540
|
+
E_INVALID_PIPELINE_STAGE,
|
|
541
|
+
E_INVALID_SEVERITY_VALUE,
|
|
458
542
|
E_INVALID_STATE,
|
|
459
543
|
E_PLAN_NOT_FOUND,
|
|
460
544
|
E_RELEASE_PLAN_INVALID,
|
|
@@ -529,6 +613,21 @@ export {
|
|
|
529
613
|
} from './graph.js';
|
|
530
614
|
export type { AdapterHookProvider } from './hooks.js';
|
|
531
615
|
export type { AdapterInstallProvider, InstallOptions, InstallResult } from './install.js';
|
|
616
|
+
// === Invariants Registry (Saga T10326 / Epic T10327 / Task T10335 — SG-SUBSTRATE-RECONCILIATION) ===
|
|
617
|
+
export type {
|
|
618
|
+
InvariantDoctorAudit,
|
|
619
|
+
InvariantLintRule,
|
|
620
|
+
InvariantRuntimeGate,
|
|
621
|
+
InvariantSeverity,
|
|
622
|
+
RegisteredInvariant,
|
|
623
|
+
} from './invariants/index.js';
|
|
624
|
+
export {
|
|
625
|
+
ADR_056_INVARIANTS,
|
|
626
|
+
ADR_073_INVARIANTS,
|
|
627
|
+
getInvariant,
|
|
628
|
+
getInvariantsByAdr,
|
|
629
|
+
INVARIANTS_REGISTRY,
|
|
630
|
+
} from './invariants/index.js';
|
|
532
631
|
// === Background Job Status (T9955 — promoted from core/store/tasks-schema.ts) ===
|
|
533
632
|
export type { BackgroundJobStatus } from './jobs.js';
|
|
534
633
|
export type {
|
|
@@ -816,6 +915,17 @@ export type {
|
|
|
816
915
|
} from './operations/dialectic.js';
|
|
817
916
|
// === Operations Types (API wire format, namespaced to avoid collision with domain types) ===
|
|
818
917
|
export * as ops from './operations/index.js';
|
|
918
|
+
// === Operation Input Contracts (T9914 / Saga T9855 / E7) ===
|
|
919
|
+
// Re-exported at top level so SDK consumers (validator T9915, mutate DX
|
|
920
|
+
// surface, generated docs) can import without the `ops.` namespace hop.
|
|
921
|
+
export type {
|
|
922
|
+
JsonSchema,
|
|
923
|
+
OperationInputContract,
|
|
924
|
+
OperationInputContractRegistry,
|
|
925
|
+
OperationInputExample,
|
|
926
|
+
ValidationError,
|
|
927
|
+
ValidationResult,
|
|
928
|
+
} from './operations/input-contract.js';
|
|
819
929
|
// === Lifecycle Operation Types (T1455 — ADR-057 D1 Core normalization) ===
|
|
820
930
|
// Re-exported at top level so @cleocode/core/lifecycle can import without the `ops.` namespace hop.
|
|
821
931
|
// Note: Gate is included here — GateStatus conflict resolved (T1694): lifecycle.ts now re-exports
|
|
@@ -1805,6 +1915,25 @@ export type {
|
|
|
1805
1915
|
TaskViewNextAction,
|
|
1806
1916
|
TaskViewPipelineStage,
|
|
1807
1917
|
} from './tasks.js';
|
|
1918
|
+
// === Template Manifest (T9875 / Saga T9855) ===
|
|
1919
|
+
export type {
|
|
1920
|
+
PlaceholderSource,
|
|
1921
|
+
PlaceholderSpec,
|
|
1922
|
+
PlaceholderSpecInput,
|
|
1923
|
+
TemplateKind,
|
|
1924
|
+
TemplateManifestEntry,
|
|
1925
|
+
TemplateManifestEntryInput,
|
|
1926
|
+
TemplateSubstitution,
|
|
1927
|
+
UpdateStrategy,
|
|
1928
|
+
} from './templates/manifest.js';
|
|
1929
|
+
export {
|
|
1930
|
+
PLACEHOLDER_SOURCES,
|
|
1931
|
+
PlaceholderSpecSchema,
|
|
1932
|
+
TEMPLATE_KINDS,
|
|
1933
|
+
TEMPLATE_SUBSTITUTIONS,
|
|
1934
|
+
TEMPLATE_UPDATE_STRATEGIES,
|
|
1935
|
+
TemplateManifestEntrySchema,
|
|
1936
|
+
} from './templates/manifest.js';
|
|
1808
1937
|
// === Tessera Types ===
|
|
1809
1938
|
export type {
|
|
1810
1939
|
TesseraInstantiationInput,
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the ADR-056 D1-D6 entries in the central invariants
|
|
3
|
+
* registry (T10339 — R5).
|
|
4
|
+
*
|
|
5
|
+
* The release-side executable subsystem at
|
|
6
|
+
* `packages/core/src/release/invariants/registry.ts` consumes these
|
|
7
|
+
* metadata entries via `getInvariantsByAdr('ADR-056')`. The tests below
|
|
8
|
+
* assert the metadata shape downstream consumers (R4 CI gate, R6 doctor
|
|
9
|
+
* audit, R8 docs renderer) rely on.
|
|
10
|
+
*
|
|
11
|
+
* @epic T10327 — E-INVARIANT-REGISTRY-SSOT
|
|
12
|
+
* @saga T10326 — SG-SUBSTRATE-RECONCILIATION
|
|
13
|
+
* @task T10339 — R5: release-registry consumes central substrate
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { describe, expect, it } from 'vitest';
|
|
17
|
+
import {
|
|
18
|
+
ADR_056_INVARIANTS,
|
|
19
|
+
getInvariant,
|
|
20
|
+
getInvariantsByAdr,
|
|
21
|
+
INVARIANTS_REGISTRY,
|
|
22
|
+
} from '../index.js';
|
|
23
|
+
|
|
24
|
+
describe('ADR-056 invariants — central registry entries', () => {
|
|
25
|
+
it('registers all six ADR-056 decisions D1-D6 under predictable keys', () => {
|
|
26
|
+
for (let i = 1; i <= 6; i++) {
|
|
27
|
+
const key = `ADR-056.D${i}`;
|
|
28
|
+
expect(INVARIANTS_REGISTRY[key]).toBeDefined();
|
|
29
|
+
expect(INVARIANTS_REGISTRY[key]?.adr).toBe('ADR-056');
|
|
30
|
+
expect(INVARIANTS_REGISTRY[key]?.code).toBe(`D${i}`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('getInvariantsByAdr("ADR-056") returns D1..D6 in declaration order', () => {
|
|
35
|
+
const adr056 = getInvariantsByAdr('ADR-056');
|
|
36
|
+
expect(adr056).toHaveLength(6);
|
|
37
|
+
expect(adr056.map((e) => e.code)).toEqual(['D1', 'D2', 'D3', 'D4', 'D5', 'D6']);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('ADR_056_INVARIANTS convenience binding matches getInvariantsByAdr output', () => {
|
|
41
|
+
expect(ADR_056_INVARIANTS).toHaveLength(6);
|
|
42
|
+
const enumerated = getInvariantsByAdr('ADR-056');
|
|
43
|
+
expect(enumerated).toHaveLength(ADR_056_INVARIANTS.length);
|
|
44
|
+
for (let i = 0; i < ADR_056_INVARIANTS.length; i++) {
|
|
45
|
+
expect(enumerated[i]?.code).toBe(ADR_056_INVARIANTS[i]?.code);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('every entry carries a non-empty name and description', () => {
|
|
50
|
+
for (const entry of ADR_056_INVARIANTS) {
|
|
51
|
+
expect(entry.name.length).toBeGreaterThan(0);
|
|
52
|
+
expect(entry.description.length).toBeGreaterThan(0);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('D4 is the archive-reason runtime gate (severity:error)', () => {
|
|
57
|
+
const d4 = getInvariant('ADR-056.D4');
|
|
58
|
+
expect(d4).toBeDefined();
|
|
59
|
+
expect(d4?.severity).toBe('error');
|
|
60
|
+
expect(d4?.runtimeGate).not.toBeNull();
|
|
61
|
+
expect(d4?.runtimeGate?.functionName).toBe('assertArchiveReason');
|
|
62
|
+
expect(d4?.runtimeGate?.module).toBe('packages/contracts/src/tasks/archive.ts');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('D5 points at the release-invariants registry runtime gate', () => {
|
|
66
|
+
const d5 = getInvariant('ADR-056.D5');
|
|
67
|
+
expect(d5).toBeDefined();
|
|
68
|
+
expect(d5?.severity).toBe('warning');
|
|
69
|
+
expect(d5?.runtimeGate).not.toBeNull();
|
|
70
|
+
expect(d5?.runtimeGate?.functionName).toBe('runInvariants');
|
|
71
|
+
expect(d5?.runtimeGate?.module).toBe('packages/core/src/release/invariants/registry.ts');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('D6 carries a lintRule pointer to the commit-msg hook (info severity)', () => {
|
|
75
|
+
const d6 = getInvariant('ADR-056.D6');
|
|
76
|
+
expect(d6).toBeDefined();
|
|
77
|
+
expect(d6?.severity).toBe('info');
|
|
78
|
+
expect(d6?.runtimeGate).toBeNull();
|
|
79
|
+
expect(d6?.lintRule?.lintScript).toBe('scripts/hooks/commit-msg-release-lint.mjs');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('D1, D2, D3 are info-tier topology/convention decisions with no runtime gate', () => {
|
|
83
|
+
for (const code of ['D1', 'D2', 'D3'] as const) {
|
|
84
|
+
const entry = getInvariant(`ADR-056.${code}`);
|
|
85
|
+
expect(entry).toBeDefined();
|
|
86
|
+
expect(entry?.severity).toBe('info');
|
|
87
|
+
expect(entry?.runtimeGate).toBeNull();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('every severity:"error" ADR-056 entry has a non-null runtimeGate', () => {
|
|
92
|
+
const errorTier = ADR_056_INVARIANTS.filter((e) => e.severity === 'error');
|
|
93
|
+
expect(errorTier.length).toBeGreaterThan(0);
|
|
94
|
+
for (const entry of errorTier) {
|
|
95
|
+
expect(entry.runtimeGate).not.toBeNull();
|
|
96
|
+
if (entry.runtimeGate !== null) {
|
|
97
|
+
expect(entry.runtimeGate.module.length).toBeGreaterThan(0);
|
|
98
|
+
expect(entry.runtimeGate.functionName.length).toBeGreaterThan(0);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the ADR-070 ORC-### orchestration invariants (T10336).
|
|
3
|
+
*
|
|
4
|
+
* The ORC codes are the Orchestrator / Lead / Worker behavioural contract
|
|
5
|
+
* surfaced through the central INVARIANTS_REGISTRY. The tests below assert:
|
|
6
|
+
*
|
|
7
|
+
* 1. At least 10 ORC-### entries are registered (we ship 14).
|
|
8
|
+
* 2. ORC-012 (the only ORC rule with a hard-enforced dispatch gate today)
|
|
9
|
+
* points at the `enforceThinAgent` function in
|
|
10
|
+
* `packages/core/src/orchestration/thin-agent.ts`.
|
|
11
|
+
* 3. Every `severity:'warning'` entry with `runtimeGate: null` carries
|
|
12
|
+
* explanatory `description` text — the gap MUST be documented, not
|
|
13
|
+
* silent.
|
|
14
|
+
* 4. ORC keys are emitted under the `ADR-070.` prefix in declaration
|
|
15
|
+
* order and are merged into the central registry.
|
|
16
|
+
*
|
|
17
|
+
* @epic T10327 — E-INVARIANT-REGISTRY-SSOT
|
|
18
|
+
* @saga T10326 — SG-SUBSTRATE-RECONCILIATION
|
|
19
|
+
* @task T10336 — R2: enumerate ADR-070 ORC codes + register
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { describe, expect, it } from 'vitest';
|
|
23
|
+
import {
|
|
24
|
+
ADR_070_INVARIANT_COUNT,
|
|
25
|
+
ADR_070_INVARIANTS,
|
|
26
|
+
ADR_070_MIN_ENTRIES,
|
|
27
|
+
} from '../adr-070-orchestration.js';
|
|
28
|
+
import {
|
|
29
|
+
getInvariant,
|
|
30
|
+
getInvariantsByAdr,
|
|
31
|
+
INVARIANTS_REGISTRY,
|
|
32
|
+
type RegisteredInvariant,
|
|
33
|
+
} from '../index.js';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Minimum ORC-### entry count required by AC1 — "Inventory ~ORC-001
|
|
37
|
+
* through ~ORC-020". We ship 14 today; the floor is 10 so future
|
|
38
|
+
* removals trip the gate before silently dropping coverage.
|
|
39
|
+
*/
|
|
40
|
+
const MIN_ORC_ENTRIES = 10;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The ORC entry that has a hard-enforced dispatch-time guard today.
|
|
44
|
+
* Other entries either prompt-time (skill text) or filed-but-unshipped
|
|
45
|
+
* (ORC-010 / ORC-011 → T10278 / T10279).
|
|
46
|
+
*/
|
|
47
|
+
const HARD_ENFORCED_ORC_CODE = 'ORC-012';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Expected runtime-gate module + function for ORC-012. Asserting both
|
|
51
|
+
* fields prevents silent drift if the thin-agent module is renamed or
|
|
52
|
+
* the export is shadowed.
|
|
53
|
+
*/
|
|
54
|
+
const ORC_012_RUNTIME_GATE = {
|
|
55
|
+
module: 'packages/core/src/orchestration/thin-agent.ts',
|
|
56
|
+
functionName: 'enforceThinAgent',
|
|
57
|
+
} as const;
|
|
58
|
+
|
|
59
|
+
describe('ADR_070_INVARIANTS — enumeration shape', () => {
|
|
60
|
+
it('exposes at least 10 ORC-### entries', () => {
|
|
61
|
+
expect(ADR_070_INVARIANTS.length).toBeGreaterThanOrEqual(MIN_ORC_ENTRIES);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('keeps ADR_070_INVARIANT_COUNT in sync with the array length', () => {
|
|
65
|
+
expect(ADR_070_INVARIANT_COUNT).toBe(ADR_070_INVARIANTS.length);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('declares ADR_070_MIN_ENTRIES at or above the AC1 floor', () => {
|
|
69
|
+
expect(ADR_070_MIN_ENTRIES).toBeGreaterThanOrEqual(MIN_ORC_ENTRIES);
|
|
70
|
+
expect(ADR_070_MIN_ENTRIES).toBeLessThanOrEqual(ADR_070_INVARIANTS.length);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('every entry sets adr="ADR-070" and a non-empty ORC-#### code', () => {
|
|
74
|
+
for (const entry of ADR_070_INVARIANTS) {
|
|
75
|
+
expect(entry.adr).toBe('ADR-070');
|
|
76
|
+
expect(entry.code).toMatch(/^ORC-\d{3}$/);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('every entry carries a non-empty name and description', () => {
|
|
81
|
+
for (const entry of ADR_070_INVARIANTS) {
|
|
82
|
+
expect(entry.name.length).toBeGreaterThan(0);
|
|
83
|
+
expect(entry.description.length).toBeGreaterThan(0);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('codes are unique across the ADR-070 enumeration', () => {
|
|
88
|
+
const codes = ADR_070_INVARIANTS.map((e) => e.code);
|
|
89
|
+
const uniqueCodes = new Set(codes);
|
|
90
|
+
expect(uniqueCodes.size).toBe(codes.length);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('ADR-070 ORC-012 — thin-agent dispatch gate (hard-enforced)', () => {
|
|
95
|
+
it('points at enforceThinAgent in packages/core/src/orchestration/thin-agent.ts', () => {
|
|
96
|
+
const entry = ADR_070_INVARIANTS.find((e) => e.code === HARD_ENFORCED_ORC_CODE);
|
|
97
|
+
expect(entry).toBeDefined();
|
|
98
|
+
expect(entry?.severity).toBe('error');
|
|
99
|
+
expect(entry?.runtimeGate).not.toBeNull();
|
|
100
|
+
expect(entry?.runtimeGate?.module).toBe(ORC_012_RUNTIME_GATE.module);
|
|
101
|
+
expect(entry?.runtimeGate?.functionName).toBe(ORC_012_RUNTIME_GATE.functionName);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('is reachable via INVARIANTS_REGISTRY["ADR-070.ORC-012"]', () => {
|
|
105
|
+
const fromRegistry = INVARIANTS_REGISTRY['ADR-070.ORC-012'];
|
|
106
|
+
expect(fromRegistry).toBeDefined();
|
|
107
|
+
expect(fromRegistry?.runtimeGate?.functionName).toBe(ORC_012_RUNTIME_GATE.functionName);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('ADR-070 gap documentation — warning + runtimeGate:null entries', () => {
|
|
112
|
+
it('every warning entry with runtimeGate:null carries explanatory description text', () => {
|
|
113
|
+
const gaps: RegisteredInvariant[] = ADR_070_INVARIANTS.filter(
|
|
114
|
+
(e) => e.severity === 'warning' && e.runtimeGate === null,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// We expect at least the prompt-only ORC entries (ORC-001..003, 008, 009)
|
|
118
|
+
// plus the filed-but-unshipped depth/lead entries (ORC-010 / ORC-011).
|
|
119
|
+
expect(gaps.length).toBeGreaterThanOrEqual(5);
|
|
120
|
+
|
|
121
|
+
// Each gap MUST explain WHY no runtime gate exists. We probe for the
|
|
122
|
+
// documented surface markers ("UNENFORCED", "Prompt-time",
|
|
123
|
+
// "FILED but UNSHIPPED" — and the related verb forms). At least one of
|
|
124
|
+
// these phrases is required so the R6 doctor audit can rely on the
|
|
125
|
+
// description as a human-readable gap explanation.
|
|
126
|
+
const gapMarkers = ['UNENFORCED', 'prompt-time', 'Prompt-time', 'UNSHIPPED', 'unshipped'];
|
|
127
|
+
for (const entry of gaps) {
|
|
128
|
+
const hasMarker = gapMarkers.some((m) => entry.description.includes(m));
|
|
129
|
+
expect(hasMarker, `Entry ${entry.code} description is missing a gap marker`).toBe(true);
|
|
130
|
+
// Sanity check: description is substantive, not a stub.
|
|
131
|
+
expect(entry.description.length).toBeGreaterThanOrEqual(80);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('filed-but-unshipped ORC-010 / ORC-011 reference their tracking tasks', () => {
|
|
136
|
+
const orc010 = ADR_070_INVARIANTS.find((e) => e.code === 'ORC-010');
|
|
137
|
+
const orc011 = ADR_070_INVARIANTS.find((e) => e.code === 'ORC-011');
|
|
138
|
+
expect(orc010?.description).toContain('T10278');
|
|
139
|
+
expect(orc011?.description).toContain('T10279');
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('central registry — ADR-070 entries merged via index.ts', () => {
|
|
144
|
+
it('every ADR-070 entry is reachable via getInvariant("ADR-070.<code>")', () => {
|
|
145
|
+
for (const entry of ADR_070_INVARIANTS) {
|
|
146
|
+
const key = `ADR-070.${entry.code}`;
|
|
147
|
+
const fromRegistry = getInvariant(key);
|
|
148
|
+
expect(fromRegistry, `Missing registry entry for ${key}`).toBeDefined();
|
|
149
|
+
expect(fromRegistry?.code).toBe(entry.code);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('getInvariantsByAdr("ADR-070") returns every entry in declaration order', () => {
|
|
154
|
+
const adr070 = getInvariantsByAdr('ADR-070');
|
|
155
|
+
expect(adr070).toHaveLength(ADR_070_INVARIANTS.length);
|
|
156
|
+
for (let i = 0; i < ADR_070_INVARIANTS.length; i++) {
|
|
157
|
+
expect(adr070[i]?.code).toBe(ADR_070_INVARIANTS[i]?.code);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('does not collide with ADR-073 entries under the merged key space', () => {
|
|
162
|
+
const adr070Keys = ADR_070_INVARIANTS.map((e) => `ADR-070.${e.code}`);
|
|
163
|
+
const adr073Keys = getInvariantsByAdr('ADR-073').map((e) => `ADR-073.${e.code}`);
|
|
164
|
+
const intersection = adr070Keys.filter((k) => adr073Keys.includes(k));
|
|
165
|
+
expect(intersection).toEqual([]);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('ADR-070 severity:"error" entries — runtime gate invariant', () => {
|
|
170
|
+
it('every error-tier entry has a non-null runtimeGate (R4 T10338 strict gate)', () => {
|
|
171
|
+
const errorTier: RegisteredInvariant[] = ADR_070_INVARIANTS.filter(
|
|
172
|
+
(e) => e.severity === 'error',
|
|
173
|
+
);
|
|
174
|
+
expect(errorTier.length).toBeGreaterThan(0);
|
|
175
|
+
for (const entry of errorTier) {
|
|
176
|
+
expect(
|
|
177
|
+
entry.runtimeGate,
|
|
178
|
+
`Error-tier entry ${entry.code} missing runtimeGate`,
|
|
179
|
+
).not.toBeNull();
|
|
180
|
+
if (entry.runtimeGate !== null) {
|
|
181
|
+
expect(entry.runtimeGate.module.length).toBeGreaterThan(0);
|
|
182
|
+
expect(entry.runtimeGate.functionName.length).toBeGreaterThan(0);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the central invariants registry (T10335).
|
|
3
|
+
*
|
|
4
|
+
* The registry is the SSoT for system-wide invariants surfaced via the
|
|
5
|
+
* SG-SUBSTRATE-RECONCILIATION saga. Downstream R-tasks (R2 ORC codes,
|
|
6
|
+
* R4 CI gate, R5 release refactor, R6 doctor audit, R8 docs renderer)
|
|
7
|
+
* all key off the metadata shape asserted below.
|
|
8
|
+
*
|
|
9
|
+
* @epic T10327 — E-INVARIANT-REGISTRY-SSOT
|
|
10
|
+
* @saga T10326 — SG-SUBSTRATE-RECONCILIATION
|
|
11
|
+
* @task T10335 — R1: registry + ADR-073 I1-I8
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, expect, it } from 'vitest';
|
|
15
|
+
import {
|
|
16
|
+
E_SAGA_INVARIANT_VIOLATION_I3,
|
|
17
|
+
E_SAGA_INVARIANT_VIOLATION_I5,
|
|
18
|
+
E_SAGA_INVARIANT_VIOLATION_I7,
|
|
19
|
+
} from '../../errors.js';
|
|
20
|
+
import {
|
|
21
|
+
ADR_073_INVARIANTS,
|
|
22
|
+
getInvariant,
|
|
23
|
+
getInvariantsByAdr,
|
|
24
|
+
INVARIANTS_REGISTRY,
|
|
25
|
+
type RegisteredInvariant,
|
|
26
|
+
} from '../index.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Map from ADR-073 invariant code → expected LAFS error code in
|
|
30
|
+
* `packages/contracts/src/errors.ts`. R2/R4 will extend this mapping with
|
|
31
|
+
* ADR-070 ORC codes once they land — for now the registry only knows
|
|
32
|
+
* about the three saga-runtime guards.
|
|
33
|
+
*
|
|
34
|
+
* NOTE: I4 / I6 / I8 deliberately have no error code today — they are
|
|
35
|
+
* UNENFORCED warnings. The R4 CI gate (T10338) is the right home for the
|
|
36
|
+
* strict "every error has an error code" assertion; this test only
|
|
37
|
+
* validates the subset we already have wired.
|
|
38
|
+
*/
|
|
39
|
+
const ADR_073_ERROR_CODE_MAP: Record<string, string> = {
|
|
40
|
+
I3: E_SAGA_INVARIANT_VIOLATION_I3,
|
|
41
|
+
I5: E_SAGA_INVARIANT_VIOLATION_I5,
|
|
42
|
+
I7: E_SAGA_INVARIANT_VIOLATION_I7,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
describe('INVARIANTS_REGISTRY — central registry shape', () => {
|
|
46
|
+
it('exposes at least 8 entries (ADR-073 I1-I8 baseline)', () => {
|
|
47
|
+
const entries = Object.values(INVARIANTS_REGISTRY);
|
|
48
|
+
expect(entries.length).toBeGreaterThanOrEqual(8);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('registers all eight ADR-073 invariants under predictable keys', () => {
|
|
52
|
+
for (let i = 1; i <= 8; i++) {
|
|
53
|
+
const key = `ADR-073.I${i}`;
|
|
54
|
+
expect(INVARIANTS_REGISTRY[key]).toBeDefined();
|
|
55
|
+
expect(INVARIANTS_REGISTRY[key]?.adr).toBe('ADR-073');
|
|
56
|
+
expect(INVARIANTS_REGISTRY[key]?.code).toBe(`I${i}`);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('every entry carries a non-empty name and description', () => {
|
|
61
|
+
for (const entry of Object.values(INVARIANTS_REGISTRY)) {
|
|
62
|
+
expect(entry.name.length).toBeGreaterThan(0);
|
|
63
|
+
expect(entry.description.length).toBeGreaterThan(0);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('every severity:"error" invariant has a non-null runtimeGate', () => {
|
|
68
|
+
const errorTier: RegisteredInvariant[] = Object.values(INVARIANTS_REGISTRY).filter(
|
|
69
|
+
(e) => e.severity === 'error',
|
|
70
|
+
);
|
|
71
|
+
expect(errorTier.length).toBeGreaterThan(0);
|
|
72
|
+
for (const entry of errorTier) {
|
|
73
|
+
expect(entry.runtimeGate).not.toBeNull();
|
|
74
|
+
// Triple is fully populated when present.
|
|
75
|
+
if (entry.runtimeGate !== null) {
|
|
76
|
+
expect(entry.runtimeGate.module.length).toBeGreaterThan(0);
|
|
77
|
+
expect(entry.runtimeGate.functionName.length).toBeGreaterThan(0);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('getInvariant — lookup helper', () => {
|
|
84
|
+
it('returns the ADR-073.I3 entry with the expected runtime guard', () => {
|
|
85
|
+
const i3 = getInvariant('ADR-073.I3');
|
|
86
|
+
expect(i3).toBeDefined();
|
|
87
|
+
expect(i3?.adr).toBe('ADR-073');
|
|
88
|
+
expect(i3?.code).toBe('I3');
|
|
89
|
+
expect(i3?.severity).toBe('error');
|
|
90
|
+
expect(i3?.runtimeGate?.functionName).toBe('assertSagaInvariantI3');
|
|
91
|
+
expect(i3?.runtimeGate?.module).toBe('packages/core/src/sagas/enforcement.ts');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('returns undefined for an unregistered key', () => {
|
|
95
|
+
expect(getInvariant('ADR-999.X1')).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('getInvariantsByAdr — per-ADR enumeration', () => {
|
|
100
|
+
it('returns all eight ADR-073 invariants in declaration order', () => {
|
|
101
|
+
const adr073 = getInvariantsByAdr('ADR-073');
|
|
102
|
+
expect(adr073).toHaveLength(8);
|
|
103
|
+
expect(adr073.map((e) => e.code)).toEqual(['I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8']);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('returns an empty array for an unknown ADR', () => {
|
|
107
|
+
expect(getInvariantsByAdr('ADR-DOES-NOT-EXIST')).toEqual([]);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('ADR_073_INVARIANTS — exported convenience binding', () => {
|
|
112
|
+
it('matches the entries surfaced via getInvariantsByAdr', () => {
|
|
113
|
+
expect(ADR_073_INVARIANTS).toHaveLength(8);
|
|
114
|
+
const enumerated = getInvariantsByAdr('ADR-073');
|
|
115
|
+
expect(enumerated).toHaveLength(ADR_073_INVARIANTS.length);
|
|
116
|
+
for (let i = 0; i < ADR_073_INVARIANTS.length; i++) {
|
|
117
|
+
expect(enumerated[i]?.code).toBe(ADR_073_INVARIANTS[i]?.code);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('error-code cross-reference (subset — R4 T10338 owns full strict gate)', () => {
|
|
123
|
+
it('every ADR-073 invariant with a runtimeGate has a known LAFS error code', () => {
|
|
124
|
+
// TODO(T10338 / R4): replace this targeted subset with a strict registry-wide
|
|
125
|
+
// assertion that walks every severity:"error" entry and confirms a matching
|
|
126
|
+
// LAFS error code (E_<ADR>_INVARIANT_VIOLATION_<CODE>) exists in errors.ts.
|
|
127
|
+
const adr073 = getInvariantsByAdr('ADR-073');
|
|
128
|
+
for (const entry of adr073) {
|
|
129
|
+
if (entry.runtimeGate !== null) {
|
|
130
|
+
const expected = ADR_073_ERROR_CODE_MAP[entry.code];
|
|
131
|
+
expect(expected).toBeDefined();
|
|
132
|
+
expect(typeof expected).toBe('string');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|