@plune-ai/cli 0.17.0 → 0.17.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/dist/index.cjs CHANGED
@@ -35,19 +35,22 @@ __export(src_exports, {
35
35
  SyncFileError: () => SyncFileError,
36
36
  SyncHttpError: () => SyncHttpError,
37
37
  SyncNetworkError: () => SyncNetworkError,
38
+ TEST_CASE_SCHEMA_VERSION: () => TEST_CASE_SCHEMA_VERSION,
38
39
  TokenRejectedError: () => TokenRejectedError,
39
40
  assertionConfigSchema: () => assertionConfigSchema,
40
- assertionResultRecordSchema: () => assertionResultRecordSchema,
41
+ assertionResultRecordSchema: () => assertionResultRecordSchema2,
41
42
  binaryVerdictSchema: () => binaryVerdictSchema,
42
43
  formatIngestResult: () => formatIngestResult,
43
44
  ingest: () => handleIngest,
44
45
  parseRunResult: () => parseRunResult,
46
+ parseTestCase: () => parseTestCase,
45
47
  readCairnRun: () => readCairnRun,
46
48
  reportIngestFailure: () => reportIngestFailure,
47
49
  reportSyncFailure: () => reportSyncFailure,
48
50
  run: () => handleRun,
49
51
  runResultSchema: () => runResultSchema,
50
- sync: () => handleSync
52
+ sync: () => handleSync,
53
+ testCaseSchema: () => testCaseSchema
51
54
  });
52
55
  module.exports = __toCommonJS(src_exports);
53
56
 
@@ -1552,59 +1555,116 @@ var fs6 = __toESM(require("fs"), 1);
1552
1555
  var path5 = __toESM(require("path"), 1);
1553
1556
 
1554
1557
  // src/types/run-result-schema.ts
1558
+ var import_zod3 = require("zod");
1559
+
1560
+ // src/types/test-case-schema.ts
1555
1561
  var import_zod2 = require("zod");
1556
- var RUN_RESULT_SCHEMA_VERSION = 1;
1557
- var binaryVerdictSchema = import_zod2.z.object({
1558
- question: import_zod2.z.string().min(1),
1559
- passed: import_zod2.z.boolean()
1562
+ var TEST_CASE_SCHEMA_VERSION = 2;
1563
+ var externalKeySchema = import_zod2.z.object({
1564
+ kind: import_zod2.z.enum(["playwright-id", "path-title", "allure-history", "cairn-stable", "eval-id", "qase", "testrail"]),
1565
+ value: import_zod2.z.string().min(1)
1566
+ });
1567
+ var manualStepSchema = import_zod2.z.object({
1568
+ action: import_zod2.z.string().min(1),
1569
+ expected: import_zod2.z.string().min(1).optional()
1560
1570
  });
1561
1571
  var assertionResultRecordSchema = import_zod2.z.object({
1562
- type: import_zod2.z.string(),
1572
+ type: import_zod2.z.string().min(1),
1563
1573
  passed: import_zod2.z.boolean(),
1564
1574
  score: import_zod2.z.number().optional(),
1565
- reason: import_zod2.z.string().optional(),
1566
- binaryVerdicts: import_zod2.z.array(binaryVerdictSchema).optional()
1575
+ reason: import_zod2.z.string().optional()
1576
+ });
1577
+ var manualCaseSchema = import_zod2.z.object({
1578
+ type: import_zod2.z.literal("manual"),
1579
+ steps: import_zod2.z.array(manualStepSchema).min(1),
1580
+ expected: import_zod2.z.string().min(1).optional()
1581
+ });
1582
+ var automatedCaseSchema = import_zod2.z.object({
1583
+ type: import_zod2.z.literal("automated"),
1584
+ specRef: import_zod2.z.string().min(1)
1585
+ });
1586
+ var evalCaseSchema = import_zod2.z.object({
1587
+ type: import_zod2.z.literal("eval"),
1588
+ prompt: import_zod2.z.string().min(1),
1589
+ goldenSetId: import_zod2.z.string().min(1).optional(),
1590
+ assertions: import_zod2.z.array(assertionResultRecordSchema).min(1)
1591
+ });
1592
+ var testCaseBaseSchema = import_zod2.z.object({
1593
+ schemaVersion: import_zod2.z.literal(TEST_CASE_SCHEMA_VERSION),
1594
+ id: import_zod2.z.string().min(1),
1595
+ externalKeys: import_zod2.z.array(externalKeySchema).optional(),
1596
+ /** ADR 0045 / plune#1246 — optional, purely additive; schemaVersion stays 2. */
1597
+ is_flaky: import_zod2.z.boolean().optional(),
1598
+ /** ADR 0045 / plune#1246 — optional, purely additive; schemaVersion stays 2. */
1599
+ is_muted: import_zod2.z.boolean().optional()
1600
+ });
1601
+ var testCaseSchema = import_zod2.z.discriminatedUnion("type", [
1602
+ testCaseBaseSchema.merge(manualCaseSchema),
1603
+ testCaseBaseSchema.merge(automatedCaseSchema),
1604
+ testCaseBaseSchema.merge(evalCaseSchema)
1605
+ ]);
1606
+ function parseTestCase(value) {
1607
+ return testCaseSchema.parse(value);
1608
+ }
1609
+
1610
+ // src/types/results.ts
1611
+ var ROW_INCONCLUSIVE = ["blocked", "skipped"];
1612
+
1613
+ // src/types/run-result-schema.ts
1614
+ var RUN_RESULT_SCHEMA_VERSION = 1;
1615
+ var binaryVerdictSchema = import_zod3.z.object({
1616
+ question: import_zod3.z.string().min(1),
1617
+ passed: import_zod3.z.boolean()
1618
+ });
1619
+ var assertionResultRecordSchema2 = import_zod3.z.object({
1620
+ type: import_zod3.z.string(),
1621
+ passed: import_zod3.z.boolean(),
1622
+ score: import_zod3.z.number().optional(),
1623
+ reason: import_zod3.z.string().optional(),
1624
+ binaryVerdicts: import_zod3.z.array(binaryVerdictSchema).optional()
1567
1625
  });
1568
- var usageSchema = import_zod2.z.object({
1569
- input_tokens: import_zod2.z.number(),
1570
- output_tokens: import_zod2.z.number(),
1571
- cost_usd: import_zod2.z.number()
1626
+ var usageSchema = import_zod3.z.object({
1627
+ input_tokens: import_zod3.z.number(),
1628
+ output_tokens: import_zod3.z.number(),
1629
+ cost_usd: import_zod3.z.number()
1572
1630
  });
1573
- var runErrorSchema = import_zod2.z.object({
1574
- code: import_zod2.z.string(),
1575
- message: import_zod2.z.string()
1631
+ var runErrorSchema = import_zod3.z.object({
1632
+ code: import_zod3.z.string(),
1633
+ message: import_zod3.z.string()
1576
1634
  });
1577
- var rowResultSchema = import_zod2.z.object({
1578
- vars: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()),
1579
- output: import_zod2.z.string().nullable(),
1580
- cached: import_zod2.z.boolean(),
1635
+ var rowResultSchema = import_zod3.z.object({
1636
+ vars: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()),
1637
+ output: import_zod3.z.string().nullable(),
1638
+ cached: import_zod3.z.boolean(),
1581
1639
  usage: usageSchema.optional(),
1582
- latency_ms: import_zod2.z.number().optional(),
1640
+ latency_ms: import_zod3.z.number().optional(),
1583
1641
  error: runErrorSchema.optional(),
1584
- assertions: import_zod2.z.array(assertionResultRecordSchema)
1642
+ assertions: import_zod3.z.array(assertionResultRecordSchema2),
1643
+ /** ADR 0045. Optional and additive — the same enum the platform validates on `POST /v1/runs`. */
1644
+ inconclusive: import_zod3.z.enum(ROW_INCONCLUSIVE).optional()
1585
1645
  });
1586
- var summarySchema = import_zod2.z.object({
1587
- total: import_zod2.z.number(),
1588
- passed: import_zod2.z.number(),
1589
- failed: import_zod2.z.number(),
1590
- errored: import_zod2.z.number(),
1591
- cost_usd: import_zod2.z.number(),
1592
- duration_ms: import_zod2.z.number()
1646
+ var summarySchema = import_zod3.z.object({
1647
+ total: import_zod3.z.number(),
1648
+ passed: import_zod3.z.number(),
1649
+ failed: import_zod3.z.number(),
1650
+ errored: import_zod3.z.number(),
1651
+ cost_usd: import_zod3.z.number(),
1652
+ duration_ms: import_zod3.z.number()
1593
1653
  });
1594
- var evalResultSchema = import_zod2.z.object({
1595
- id: import_zod2.z.string(),
1596
- tags: import_zod2.z.array(import_zod2.z.string()),
1597
- rows: import_zod2.z.array(rowResultSchema),
1598
- passed: import_zod2.z.boolean()
1654
+ var evalResultSchema = import_zod3.z.object({
1655
+ id: import_zod3.z.string(),
1656
+ tags: import_zod3.z.array(import_zod3.z.string()),
1657
+ rows: import_zod3.z.array(rowResultSchema),
1658
+ passed: import_zod3.z.boolean()
1599
1659
  });
1600
- var runResultSchema = import_zod2.z.object({
1601
- schemaVersion: import_zod2.z.literal(RUN_RESULT_SCHEMA_VERSION),
1602
- plune_version: import_zod2.z.string(),
1603
- started_at: import_zod2.z.string(),
1604
- finished_at: import_zod2.z.string(),
1605
- config_hash: import_zod2.z.string(),
1660
+ var runResultSchema = import_zod3.z.object({
1661
+ schemaVersion: import_zod3.z.literal(RUN_RESULT_SCHEMA_VERSION),
1662
+ plune_version: import_zod3.z.string(),
1663
+ started_at: import_zod3.z.string(),
1664
+ finished_at: import_zod3.z.string(),
1665
+ config_hash: import_zod3.z.string(),
1606
1666
  summary: summarySchema,
1607
- evals: import_zod2.z.array(evalResultSchema)
1667
+ evals: import_zod3.z.array(evalResultSchema)
1608
1668
  });
1609
1669
  function parseRunResult(value) {
1610
1670
  return runResultSchema.parse(value);
@@ -1988,6 +2048,7 @@ function formatIngestResult(r) {
1988
2048
  SyncFileError,
1989
2049
  SyncHttpError,
1990
2050
  SyncNetworkError,
2051
+ TEST_CASE_SCHEMA_VERSION,
1991
2052
  TokenRejectedError,
1992
2053
  assertionConfigSchema,
1993
2054
  assertionResultRecordSchema,
@@ -1995,10 +2056,12 @@ function formatIngestResult(r) {
1995
2056
  formatIngestResult,
1996
2057
  ingest,
1997
2058
  parseRunResult,
2059
+ parseTestCase,
1998
2060
  readCairnRun,
1999
2061
  reportIngestFailure,
2000
2062
  reportSyncFailure,
2001
2063
  run,
2002
2064
  runResultSchema,
2003
- sync
2065
+ sync,
2066
+ testCaseSchema
2004
2067
  });
package/dist/index.d.cts CHANGED
@@ -23,6 +23,54 @@ interface RunError {
23
23
  code: string;
24
24
  message: string;
25
25
  }
26
+ interface ManualStep {
27
+ action: string;
28
+ expected?: string;
29
+ }
30
+ interface ExternalKey {
31
+ kind: 'playwright-id' | 'path-title' | 'allure-history' | 'cairn-stable' | 'eval-id' | 'qase' | 'testrail';
32
+ value: string;
33
+ }
34
+ type ManualCase = {
35
+ type: 'manual';
36
+ steps: {
37
+ action: string;
38
+ expected?: string;
39
+ }[];
40
+ expected?: string;
41
+ };
42
+ type AutomatedCase = {
43
+ type: 'automated';
44
+ specRef: string;
45
+ };
46
+ type EvalCase = {
47
+ type: 'eval';
48
+ prompt: string;
49
+ goldenSetId?: string;
50
+ assertions: AssertionResultRecord[];
51
+ };
52
+ interface TestCaseBase {
53
+ schemaVersion: 2;
54
+ id: string;
55
+ externalKeys?: ExternalKey[];
56
+ is_flaky?: boolean;
57
+ is_muted?: boolean;
58
+ }
59
+ type TestCase = TestCaseBase & (ManualCase | AutomatedCase | EvalCase);
60
+ /**
61
+ * The two words a row may use to say the product was never judged (ADR 0045).
62
+ *
63
+ * Both are already statuses this system has — they are `RESULT_STATUSES` entries — and neither was
64
+ * reachable through this contract: a row could only report `passed`, `failed` or `broken`. So a
65
+ * runner whose row was stopped by something outside the test had exactly one word left, `failed`,
66
+ * and the word was wrong. A red build because a dependency fell over reads identically to a red
67
+ * build because the code is broken, and those are two different pieces of work.
68
+ *
69
+ * `invalid` is deliberately absent: Qase's `invalid` is our `broken`, and a second word for one
70
+ * idea would fork the contract at both ends.
71
+ */
72
+ declare const ROW_INCONCLUSIVE: readonly ["blocked", "skipped"];
73
+ type RowInconclusive = (typeof ROW_INCONCLUSIVE)[number];
26
74
  interface RowResult {
27
75
  vars: Record<string, unknown>;
28
76
  output: string | null;
@@ -31,6 +79,14 @@ interface RowResult {
31
79
  latency_ms?: number;
32
80
  error?: RunError;
33
81
  assertions: AssertionResultRecord[];
82
+ /**
83
+ * ADR 0045. Say it when the test was never judged, rather than letting `failed` stand for both
84
+ * "the environment broke" and "the code is wrong".
85
+ *
86
+ * Optional and purely additive: a producer that does not send it validates exactly as before,
87
+ * which is why `schemaVersion` stays 1.
88
+ */
89
+ inconclusive?: RowInconclusive;
34
90
  }
35
91
  interface EvalResult {
36
92
  id: string;
@@ -404,6 +460,10 @@ declare const runResultSchema: z.ZodObject<{
404
460
  passed: z.ZodBoolean;
405
461
  }, z.core.$strip>>>;
406
462
  }, z.core.$strip>>;
463
+ inconclusive: z.ZodOptional<z.ZodEnum<{
464
+ blocked: "blocked";
465
+ skipped: "skipped";
466
+ }>>;
407
467
  }, z.core.$strip>>;
408
468
  passed: z.ZodBoolean;
409
469
  }, z.core.$strip>>;
@@ -417,6 +477,133 @@ type BinaryVerdict = z.infer<typeof binaryVerdictSchema>;
417
477
  /** Parse + validate an unknown value as a RunResult. Throws ZodError on failure. */
418
478
  declare function parseRunResult(value: unknown): ParsedRunResult;
419
479
 
480
+ /**
481
+ * Runtime validation for the TestCase contract — the JSON that `plune run import` emits
482
+ * or that the platform accepts on `POST /v1/test-cases`.
483
+ *
484
+ * The canonical TypeScript shape is owned by `./results.ts` (`TEST_CASE_SCHEMA_VERSION: 2`).
485
+ * This module is its zod mirror: the validator for anything that has to *ingest* that
486
+ * output rather than produce it. `plune sync` validates the local case file with it
487
+ * before uploading, and the Plune platform validates the same body on
488
+ * `POST /v1/test-cases` — one schema, both ends.
489
+ */
490
+ declare const TEST_CASE_SCHEMA_VERSION: TestCase['schemaVersion'];
491
+ declare const testCaseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
492
+ schemaVersion: z.ZodLiteral<2>;
493
+ id: z.ZodString;
494
+ externalKeys: z.ZodOptional<z.ZodArray<z.ZodObject<{
495
+ kind: z.ZodEnum<{
496
+ "playwright-id": "playwright-id";
497
+ "path-title": "path-title";
498
+ "allure-history": "allure-history";
499
+ "cairn-stable": "cairn-stable";
500
+ "eval-id": "eval-id";
501
+ qase: "qase";
502
+ testrail: "testrail";
503
+ }>;
504
+ value: z.ZodString;
505
+ }, z.core.$strip>>>;
506
+ is_flaky: z.ZodOptional<z.ZodBoolean>;
507
+ is_muted: z.ZodOptional<z.ZodBoolean>;
508
+ type: z.ZodLiteral<"manual">;
509
+ steps: z.ZodArray<z.ZodObject<{
510
+ action: z.ZodString;
511
+ expected: z.ZodOptional<z.ZodString>;
512
+ }, z.core.$strip>>;
513
+ expected: z.ZodOptional<z.ZodString>;
514
+ }, z.core.$strip>, z.ZodObject<{
515
+ schemaVersion: z.ZodLiteral<2>;
516
+ id: z.ZodString;
517
+ externalKeys: z.ZodOptional<z.ZodArray<z.ZodObject<{
518
+ kind: z.ZodEnum<{
519
+ "playwright-id": "playwright-id";
520
+ "path-title": "path-title";
521
+ "allure-history": "allure-history";
522
+ "cairn-stable": "cairn-stable";
523
+ "eval-id": "eval-id";
524
+ qase: "qase";
525
+ testrail: "testrail";
526
+ }>;
527
+ value: z.ZodString;
528
+ }, z.core.$strip>>>;
529
+ is_flaky: z.ZodOptional<z.ZodBoolean>;
530
+ is_muted: z.ZodOptional<z.ZodBoolean>;
531
+ type: z.ZodLiteral<"automated">;
532
+ specRef: z.ZodString;
533
+ }, z.core.$strip>, z.ZodObject<{
534
+ schemaVersion: z.ZodLiteral<2>;
535
+ id: z.ZodString;
536
+ externalKeys: z.ZodOptional<z.ZodArray<z.ZodObject<{
537
+ kind: z.ZodEnum<{
538
+ "playwright-id": "playwright-id";
539
+ "path-title": "path-title";
540
+ "allure-history": "allure-history";
541
+ "cairn-stable": "cairn-stable";
542
+ "eval-id": "eval-id";
543
+ qase: "qase";
544
+ testrail: "testrail";
545
+ }>;
546
+ value: z.ZodString;
547
+ }, z.core.$strip>>>;
548
+ is_flaky: z.ZodOptional<z.ZodBoolean>;
549
+ is_muted: z.ZodOptional<z.ZodBoolean>;
550
+ type: z.ZodLiteral<"eval">;
551
+ prompt: z.ZodString;
552
+ goldenSetId: z.ZodOptional<z.ZodString>;
553
+ assertions: z.ZodArray<z.ZodObject<{
554
+ type: z.ZodString;
555
+ passed: z.ZodBoolean;
556
+ score: z.ZodOptional<z.ZodNumber>;
557
+ reason: z.ZodOptional<z.ZodString>;
558
+ }, z.core.$strip>>;
559
+ }, z.core.$strip>], "type">;
560
+ /** Parse + validate an unknown value as a TestCase. Throws ZodError on failure. */
561
+ declare function parseTestCase(value: unknown): {
562
+ schemaVersion: 2;
563
+ id: string;
564
+ type: "manual";
565
+ steps: {
566
+ action: string;
567
+ expected?: string | undefined;
568
+ }[];
569
+ externalKeys?: {
570
+ kind: "playwright-id" | "path-title" | "allure-history" | "cairn-stable" | "eval-id" | "qase" | "testrail";
571
+ value: string;
572
+ }[] | undefined;
573
+ is_flaky?: boolean | undefined;
574
+ is_muted?: boolean | undefined;
575
+ expected?: string | undefined;
576
+ } | {
577
+ schemaVersion: 2;
578
+ id: string;
579
+ type: "automated";
580
+ specRef: string;
581
+ externalKeys?: {
582
+ kind: "playwright-id" | "path-title" | "allure-history" | "cairn-stable" | "eval-id" | "qase" | "testrail";
583
+ value: string;
584
+ }[] | undefined;
585
+ is_flaky?: boolean | undefined;
586
+ is_muted?: boolean | undefined;
587
+ } | {
588
+ schemaVersion: 2;
589
+ id: string;
590
+ type: "eval";
591
+ prompt: string;
592
+ assertions: {
593
+ type: string;
594
+ passed: boolean;
595
+ score?: number | undefined;
596
+ reason?: string | undefined;
597
+ }[];
598
+ externalKeys?: {
599
+ kind: "playwright-id" | "path-title" | "allure-history" | "cairn-stable" | "eval-id" | "qase" | "testrail";
600
+ value: string;
601
+ }[] | undefined;
602
+ is_flaky?: boolean | undefined;
603
+ is_muted?: boolean | undefined;
604
+ goldenSetId?: string | undefined;
605
+ };
606
+
420
607
  interface IngestDeps {
421
608
  /** The Cairn run directory to read. Omit it and the newest run under `runsDir` is used. */
422
609
  dir?: string;
@@ -485,4 +672,4 @@ interface ReadCairnRunDeps {
485
672
  */
486
673
  declare function readCairnRun(dir: string, deps?: ReadCairnRunDeps): Promise<CairnIngestPayload>;
487
674
 
488
- export { type AssertionResultRecord, type BinaryVerdict, type CairnIngestCase, type CairnIngestPayload, type Config, type EvalResult, type IngestDeps, type IngestResult, NotLoggedInError, type ParsedRunResult, RUN_RESULT_SCHEMA_VERSION, type RowResult, type RunError, type RunOptions, type RunResult, type Summary, type SyncDeps, SyncFileError, SyncHttpError, SyncNetworkError, type SyncResult, TokenRejectedError, type Usage, assertionConfigSchema, assertionResultRecordSchema, binaryVerdictSchema, formatIngestResult, handleIngest as ingest, parseRunResult, readCairnRun, reportIngestFailure, reportSyncFailure, handleRun as run, runResultSchema, handleSync as sync };
675
+ export { type AssertionResultRecord, type BinaryVerdict, type CairnIngestCase, type CairnIngestPayload, type Config, type EvalResult, type ExternalKey, type IngestDeps, type IngestResult, type ManualStep, NotLoggedInError, type ParsedRunResult, RUN_RESULT_SCHEMA_VERSION, type RowResult, type RunError, type RunOptions, type RunResult, type Summary, type SyncDeps, SyncFileError, SyncHttpError, SyncNetworkError, type SyncResult, TEST_CASE_SCHEMA_VERSION, type TestCase, TokenRejectedError, type Usage, assertionConfigSchema, assertionResultRecordSchema, binaryVerdictSchema, formatIngestResult, handleIngest as ingest, parseRunResult, parseTestCase, readCairnRun, reportIngestFailure, reportSyncFailure, handleRun as run, runResultSchema, handleSync as sync, testCaseSchema };
package/dist/index.d.ts CHANGED
@@ -23,6 +23,54 @@ interface RunError {
23
23
  code: string;
24
24
  message: string;
25
25
  }
26
+ interface ManualStep {
27
+ action: string;
28
+ expected?: string;
29
+ }
30
+ interface ExternalKey {
31
+ kind: 'playwright-id' | 'path-title' | 'allure-history' | 'cairn-stable' | 'eval-id' | 'qase' | 'testrail';
32
+ value: string;
33
+ }
34
+ type ManualCase = {
35
+ type: 'manual';
36
+ steps: {
37
+ action: string;
38
+ expected?: string;
39
+ }[];
40
+ expected?: string;
41
+ };
42
+ type AutomatedCase = {
43
+ type: 'automated';
44
+ specRef: string;
45
+ };
46
+ type EvalCase = {
47
+ type: 'eval';
48
+ prompt: string;
49
+ goldenSetId?: string;
50
+ assertions: AssertionResultRecord[];
51
+ };
52
+ interface TestCaseBase {
53
+ schemaVersion: 2;
54
+ id: string;
55
+ externalKeys?: ExternalKey[];
56
+ is_flaky?: boolean;
57
+ is_muted?: boolean;
58
+ }
59
+ type TestCase = TestCaseBase & (ManualCase | AutomatedCase | EvalCase);
60
+ /**
61
+ * The two words a row may use to say the product was never judged (ADR 0045).
62
+ *
63
+ * Both are already statuses this system has — they are `RESULT_STATUSES` entries — and neither was
64
+ * reachable through this contract: a row could only report `passed`, `failed` or `broken`. So a
65
+ * runner whose row was stopped by something outside the test had exactly one word left, `failed`,
66
+ * and the word was wrong. A red build because a dependency fell over reads identically to a red
67
+ * build because the code is broken, and those are two different pieces of work.
68
+ *
69
+ * `invalid` is deliberately absent: Qase's `invalid` is our `broken`, and a second word for one
70
+ * idea would fork the contract at both ends.
71
+ */
72
+ declare const ROW_INCONCLUSIVE: readonly ["blocked", "skipped"];
73
+ type RowInconclusive = (typeof ROW_INCONCLUSIVE)[number];
26
74
  interface RowResult {
27
75
  vars: Record<string, unknown>;
28
76
  output: string | null;
@@ -31,6 +79,14 @@ interface RowResult {
31
79
  latency_ms?: number;
32
80
  error?: RunError;
33
81
  assertions: AssertionResultRecord[];
82
+ /**
83
+ * ADR 0045. Say it when the test was never judged, rather than letting `failed` stand for both
84
+ * "the environment broke" and "the code is wrong".
85
+ *
86
+ * Optional and purely additive: a producer that does not send it validates exactly as before,
87
+ * which is why `schemaVersion` stays 1.
88
+ */
89
+ inconclusive?: RowInconclusive;
34
90
  }
35
91
  interface EvalResult {
36
92
  id: string;
@@ -404,6 +460,10 @@ declare const runResultSchema: z.ZodObject<{
404
460
  passed: z.ZodBoolean;
405
461
  }, z.core.$strip>>>;
406
462
  }, z.core.$strip>>;
463
+ inconclusive: z.ZodOptional<z.ZodEnum<{
464
+ blocked: "blocked";
465
+ skipped: "skipped";
466
+ }>>;
407
467
  }, z.core.$strip>>;
408
468
  passed: z.ZodBoolean;
409
469
  }, z.core.$strip>>;
@@ -417,6 +477,133 @@ type BinaryVerdict = z.infer<typeof binaryVerdictSchema>;
417
477
  /** Parse + validate an unknown value as a RunResult. Throws ZodError on failure. */
418
478
  declare function parseRunResult(value: unknown): ParsedRunResult;
419
479
 
480
+ /**
481
+ * Runtime validation for the TestCase contract — the JSON that `plune run import` emits
482
+ * or that the platform accepts on `POST /v1/test-cases`.
483
+ *
484
+ * The canonical TypeScript shape is owned by `./results.ts` (`TEST_CASE_SCHEMA_VERSION: 2`).
485
+ * This module is its zod mirror: the validator for anything that has to *ingest* that
486
+ * output rather than produce it. `plune sync` validates the local case file with it
487
+ * before uploading, and the Plune platform validates the same body on
488
+ * `POST /v1/test-cases` — one schema, both ends.
489
+ */
490
+ declare const TEST_CASE_SCHEMA_VERSION: TestCase['schemaVersion'];
491
+ declare const testCaseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
492
+ schemaVersion: z.ZodLiteral<2>;
493
+ id: z.ZodString;
494
+ externalKeys: z.ZodOptional<z.ZodArray<z.ZodObject<{
495
+ kind: z.ZodEnum<{
496
+ "playwright-id": "playwright-id";
497
+ "path-title": "path-title";
498
+ "allure-history": "allure-history";
499
+ "cairn-stable": "cairn-stable";
500
+ "eval-id": "eval-id";
501
+ qase: "qase";
502
+ testrail: "testrail";
503
+ }>;
504
+ value: z.ZodString;
505
+ }, z.core.$strip>>>;
506
+ is_flaky: z.ZodOptional<z.ZodBoolean>;
507
+ is_muted: z.ZodOptional<z.ZodBoolean>;
508
+ type: z.ZodLiteral<"manual">;
509
+ steps: z.ZodArray<z.ZodObject<{
510
+ action: z.ZodString;
511
+ expected: z.ZodOptional<z.ZodString>;
512
+ }, z.core.$strip>>;
513
+ expected: z.ZodOptional<z.ZodString>;
514
+ }, z.core.$strip>, z.ZodObject<{
515
+ schemaVersion: z.ZodLiteral<2>;
516
+ id: z.ZodString;
517
+ externalKeys: z.ZodOptional<z.ZodArray<z.ZodObject<{
518
+ kind: z.ZodEnum<{
519
+ "playwright-id": "playwright-id";
520
+ "path-title": "path-title";
521
+ "allure-history": "allure-history";
522
+ "cairn-stable": "cairn-stable";
523
+ "eval-id": "eval-id";
524
+ qase: "qase";
525
+ testrail: "testrail";
526
+ }>;
527
+ value: z.ZodString;
528
+ }, z.core.$strip>>>;
529
+ is_flaky: z.ZodOptional<z.ZodBoolean>;
530
+ is_muted: z.ZodOptional<z.ZodBoolean>;
531
+ type: z.ZodLiteral<"automated">;
532
+ specRef: z.ZodString;
533
+ }, z.core.$strip>, z.ZodObject<{
534
+ schemaVersion: z.ZodLiteral<2>;
535
+ id: z.ZodString;
536
+ externalKeys: z.ZodOptional<z.ZodArray<z.ZodObject<{
537
+ kind: z.ZodEnum<{
538
+ "playwright-id": "playwright-id";
539
+ "path-title": "path-title";
540
+ "allure-history": "allure-history";
541
+ "cairn-stable": "cairn-stable";
542
+ "eval-id": "eval-id";
543
+ qase: "qase";
544
+ testrail: "testrail";
545
+ }>;
546
+ value: z.ZodString;
547
+ }, z.core.$strip>>>;
548
+ is_flaky: z.ZodOptional<z.ZodBoolean>;
549
+ is_muted: z.ZodOptional<z.ZodBoolean>;
550
+ type: z.ZodLiteral<"eval">;
551
+ prompt: z.ZodString;
552
+ goldenSetId: z.ZodOptional<z.ZodString>;
553
+ assertions: z.ZodArray<z.ZodObject<{
554
+ type: z.ZodString;
555
+ passed: z.ZodBoolean;
556
+ score: z.ZodOptional<z.ZodNumber>;
557
+ reason: z.ZodOptional<z.ZodString>;
558
+ }, z.core.$strip>>;
559
+ }, z.core.$strip>], "type">;
560
+ /** Parse + validate an unknown value as a TestCase. Throws ZodError on failure. */
561
+ declare function parseTestCase(value: unknown): {
562
+ schemaVersion: 2;
563
+ id: string;
564
+ type: "manual";
565
+ steps: {
566
+ action: string;
567
+ expected?: string | undefined;
568
+ }[];
569
+ externalKeys?: {
570
+ kind: "playwright-id" | "path-title" | "allure-history" | "cairn-stable" | "eval-id" | "qase" | "testrail";
571
+ value: string;
572
+ }[] | undefined;
573
+ is_flaky?: boolean | undefined;
574
+ is_muted?: boolean | undefined;
575
+ expected?: string | undefined;
576
+ } | {
577
+ schemaVersion: 2;
578
+ id: string;
579
+ type: "automated";
580
+ specRef: string;
581
+ externalKeys?: {
582
+ kind: "playwright-id" | "path-title" | "allure-history" | "cairn-stable" | "eval-id" | "qase" | "testrail";
583
+ value: string;
584
+ }[] | undefined;
585
+ is_flaky?: boolean | undefined;
586
+ is_muted?: boolean | undefined;
587
+ } | {
588
+ schemaVersion: 2;
589
+ id: string;
590
+ type: "eval";
591
+ prompt: string;
592
+ assertions: {
593
+ type: string;
594
+ passed: boolean;
595
+ score?: number | undefined;
596
+ reason?: string | undefined;
597
+ }[];
598
+ externalKeys?: {
599
+ kind: "playwright-id" | "path-title" | "allure-history" | "cairn-stable" | "eval-id" | "qase" | "testrail";
600
+ value: string;
601
+ }[] | undefined;
602
+ is_flaky?: boolean | undefined;
603
+ is_muted?: boolean | undefined;
604
+ goldenSetId?: string | undefined;
605
+ };
606
+
420
607
  interface IngestDeps {
421
608
  /** The Cairn run directory to read. Omit it and the newest run under `runsDir` is used. */
422
609
  dir?: string;
@@ -485,4 +672,4 @@ interface ReadCairnRunDeps {
485
672
  */
486
673
  declare function readCairnRun(dir: string, deps?: ReadCairnRunDeps): Promise<CairnIngestPayload>;
487
674
 
488
- export { type AssertionResultRecord, type BinaryVerdict, type CairnIngestCase, type CairnIngestPayload, type Config, type EvalResult, type IngestDeps, type IngestResult, NotLoggedInError, type ParsedRunResult, RUN_RESULT_SCHEMA_VERSION, type RowResult, type RunError, type RunOptions, type RunResult, type Summary, type SyncDeps, SyncFileError, SyncHttpError, SyncNetworkError, type SyncResult, TokenRejectedError, type Usage, assertionConfigSchema, assertionResultRecordSchema, binaryVerdictSchema, formatIngestResult, handleIngest as ingest, parseRunResult, readCairnRun, reportIngestFailure, reportSyncFailure, handleRun as run, runResultSchema, handleSync as sync };
675
+ export { type AssertionResultRecord, type BinaryVerdict, type CairnIngestCase, type CairnIngestPayload, type Config, type EvalResult, type ExternalKey, type IngestDeps, type IngestResult, type ManualStep, NotLoggedInError, type ParsedRunResult, RUN_RESULT_SCHEMA_VERSION, type RowResult, type RunError, type RunOptions, type RunResult, type Summary, type SyncDeps, SyncFileError, SyncHttpError, SyncNetworkError, type SyncResult, TEST_CASE_SCHEMA_VERSION, type TestCase, TokenRejectedError, type Usage, assertionConfigSchema, assertionResultRecordSchema, binaryVerdictSchema, formatIngestResult, handleIngest as ingest, parseRunResult, parseTestCase, readCairnRun, reportIngestFailure, reportSyncFailure, handleRun as run, runResultSchema, handleSync as sync, testCaseSchema };