ccqa 1.21.0 → 1.22.0
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/bin/ccqa.mjs +73 -9
- package/dist/hub-client/index.d.mts +8 -0
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/bin/ccqa.mjs
CHANGED
|
@@ -6842,10 +6842,26 @@ const SpecLedgerEntrySchema = z.object({
|
|
|
6842
6842
|
deployedSha: z.string().nullable().optional(),
|
|
6843
6843
|
deployedShaAmbiguous: z.boolean().optional()
|
|
6844
6844
|
});
|
|
6845
|
+
/**
|
|
6846
|
+
* A red-bucket entry: where the failure happened, plus what it was. The cause
|
|
6847
|
+
* is copied off the run report's `analysis` so a reader learns why a spec is
|
|
6848
|
+
* red without fetching the report of every red spec.
|
|
6849
|
+
*
|
|
6850
|
+
* Only the red bucket carries it. A pass has no cause, so putting these on
|
|
6851
|
+
* `SpecLedgerEntry` would invite writing them where they cannot exist.
|
|
6852
|
+
*
|
|
6853
|
+
* Both fields are optional and mean the same thing by their absence — nothing
|
|
6854
|
+
* is on record. Failure analysis is opt-in (`--on-fail-explain`), and entries
|
|
6855
|
+
* written before this release have neither field.
|
|
6856
|
+
*/
|
|
6857
|
+
const SpecRedLedgerEntrySchema = SpecLedgerEntrySchema.extend({
|
|
6858
|
+
label: PredictedLabelSchema.optional(),
|
|
6859
|
+
headline: z.string().optional()
|
|
6860
|
+
});
|
|
6845
6861
|
z.object({
|
|
6846
6862
|
green: z.record(z.string(), SpecLedgerEntrySchema).default({}),
|
|
6847
6863
|
run: z.record(z.string(), SpecLedgerEntrySchema).default({}),
|
|
6848
|
-
red: z.record(z.string(),
|
|
6864
|
+
red: z.record(z.string(), SpecRedLedgerEntrySchema).default({})
|
|
6849
6865
|
});
|
|
6850
6866
|
/** One deploy, as the consumer's deploy job reported it (ADR-0010). */
|
|
6851
6867
|
const DeployEntrySchema = z.object({
|
|
@@ -7025,7 +7041,7 @@ const SpecRerunSchema = z.object({
|
|
|
7025
7041
|
heldBy: SpecLockSchema.nullable(),
|
|
7026
7042
|
lastRun: SpecLedgerEntrySchema.nullable(),
|
|
7027
7043
|
lastGreen: SpecLedgerEntrySchema.nullable(),
|
|
7028
|
-
lastRed:
|
|
7044
|
+
lastRed: SpecRedLedgerEntrySchema.nullable(),
|
|
7029
7045
|
touchedBy: z.array(z.string()).optional(),
|
|
7030
7046
|
touchedByDeploy: DeployRefSchema.nullable().optional()
|
|
7031
7047
|
});
|
|
@@ -7075,7 +7091,7 @@ z.object({
|
|
|
7075
7091
|
z.object({
|
|
7076
7092
|
entries: z.record(z.string(), SpecLedgerEntrySchema),
|
|
7077
7093
|
lastRun: z.record(z.string(), SpecLedgerEntrySchema).default({}),
|
|
7078
|
-
lastRed: z.record(z.string(),
|
|
7094
|
+
lastRed: z.record(z.string(), SpecRedLedgerEntrySchema).default({})
|
|
7079
7095
|
});
|
|
7080
7096
|
/**
|
|
7081
7097
|
* One spec's last drift audit, as recorded by `ccqa audit --report-to-hub`. Unlike the
|
|
@@ -16755,12 +16771,17 @@ function toLedger(raw) {
|
|
|
16755
16771
|
}
|
|
16756
16772
|
/** Fold `from` into `into` in place, per bucket and key, newest `at` winning. */
|
|
16757
16773
|
function mergeLedgerInto(into, from) {
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
}
|
|
16774
|
+
mergeBucket(into.green, from.green);
|
|
16775
|
+
mergeBucket(into.run, from.run);
|
|
16776
|
+
mergeBucket(into.red, from.red);
|
|
16762
16777
|
return into;
|
|
16763
16778
|
}
|
|
16779
|
+
function mergeBucket(into, from) {
|
|
16780
|
+
for (const [key, entry] of Object.entries(from)) {
|
|
16781
|
+
const prev = into[key];
|
|
16782
|
+
if (!prev || prev.at <= entry.at) into[key] = entry;
|
|
16783
|
+
}
|
|
16784
|
+
}
|
|
16764
16785
|
//#endregion
|
|
16765
16786
|
//#region src/hub/api/validate.ts
|
|
16766
16787
|
/**
|
|
@@ -16971,7 +16992,7 @@ async function updateSpecLedger(storage, run, results) {
|
|
|
16971
16992
|
const key = `${row.feature}/${row.spec}`;
|
|
16972
16993
|
ledger.run[key] = entry;
|
|
16973
16994
|
if (row.status === "passed") ledger.green[key] = entry;
|
|
16974
|
-
else ledger.red[key] = entry;
|
|
16995
|
+
else ledger.red[key] = redEntry(entry, row);
|
|
16975
16996
|
}
|
|
16976
16997
|
if (Object.keys(ledger.run).length === 0) return;
|
|
16977
16998
|
try {
|
|
@@ -16981,6 +17002,23 @@ async function updateSpecLedger(storage, run, results) {
|
|
|
16981
17002
|
}
|
|
16982
17003
|
}
|
|
16983
17004
|
/**
|
|
17005
|
+
* The red bucket's entry: the coordinate every bucket carries, plus what the
|
|
17006
|
+
* failure analysis concluded, so a reader of the ledger learns why a spec is
|
|
17007
|
+
* red without fetching its report.
|
|
17008
|
+
*
|
|
17009
|
+
* A field with nothing behind it is left out rather than written empty:
|
|
17010
|
+
* `analysis` is null when the run did not ask for one (`--on-fail-explain` is
|
|
17011
|
+
* opt-in), and a model that answered with no headline leaves `headline` "".
|
|
17012
|
+
*/
|
|
17013
|
+
function redEntry(entry, row) {
|
|
17014
|
+
if (!row.analysis) return entry;
|
|
17015
|
+
return {
|
|
17016
|
+
...entry,
|
|
17017
|
+
label: row.analysis.label,
|
|
17018
|
+
...row.analysis.headline ? { headline: row.analysis.headline } : {}
|
|
17019
|
+
};
|
|
17020
|
+
}
|
|
17021
|
+
/**
|
|
16984
17022
|
* Advance the drift ledger from a terminal `kind: "drift"` run: each row's
|
|
16985
17023
|
* `analysis` (the diagnosis `driftResultsToReport` put there) becomes that
|
|
16986
17024
|
* spec's newest audit entry. No profile — drift asks whether the spec still
|
|
@@ -22205,6 +22243,17 @@ const CLIENT_JS = `
|
|
|
22205
22243
|
badge.appendChild(document.createTextNode(" " + t("perspectives.run.state." + runState)));
|
|
22206
22244
|
td.appendChild(badge);
|
|
22207
22245
|
|
|
22246
|
+
// What the failure was, as the run's analysis called it — the same place
|
|
22247
|
+
// the audit column names its drift label. Absent on a red entry the run
|
|
22248
|
+
// never analyzed, and on entries written before the ledger carried it.
|
|
22249
|
+
if (runState === "failed" && rr.lastRed && rr.lastRed.label) {
|
|
22250
|
+
var cause = el("span", "cellsub", labelText(rr.lastRed.label));
|
|
22251
|
+
// The one-line conclusion, for a pointer. The detail panel shows it in
|
|
22252
|
+
// full, so nothing here depends on finding it.
|
|
22253
|
+
if (rr.lastRed.headline) cause.title = rr.lastRed.headline;
|
|
22254
|
+
td.appendChild(cause);
|
|
22255
|
+
}
|
|
22256
|
+
|
|
22208
22257
|
// The sub-line is the coordinate of the result being reported — the same
|
|
22209
22258
|
// "when is this from" evidence the audit column carries above, so the two
|
|
22210
22259
|
// axes read as siblings. Why the currency matters belongs to the verdict
|
|
@@ -22423,6 +22472,21 @@ const CLIENT_JS = `
|
|
|
22423
22472
|
return wrap;
|
|
22424
22473
|
}
|
|
22425
22474
|
|
|
22475
|
+
// The failure: which run it was, then what the analysis concluded. The
|
|
22476
|
+
// headline is model output, already localized server-side, so it is shown as
|
|
22477
|
+
// written. A run made without failure analysis carries neither field, and the
|
|
22478
|
+
// row is then the coordinate alone — what it has always been.
|
|
22479
|
+
function rerunFailureValue(entry) {
|
|
22480
|
+
var wrap = el("div");
|
|
22481
|
+
wrap.appendChild(ledgerLine(entry));
|
|
22482
|
+
if (entry.label) {
|
|
22483
|
+
var line = el("div", "d-prose", labelText(entry.label));
|
|
22484
|
+
if (entry.headline) line.appendChild(document.createTextNode(" · " + entry.headline));
|
|
22485
|
+
wrap.appendChild(line);
|
|
22486
|
+
}
|
|
22487
|
+
return wrap;
|
|
22488
|
+
}
|
|
22489
|
+
|
|
22426
22490
|
// Detail row: a definition list of the case's fields plus the note editor.
|
|
22427
22491
|
// Built with createElement/textContent throughout — every field here is
|
|
22428
22492
|
// API-derived, so none of it may go through innerHTML.
|
|
@@ -22456,7 +22520,7 @@ const CLIENT_JS = `
|
|
|
22456
22520
|
var rr = ledgerEntryFor(perspState.rerun, feature, spec);
|
|
22457
22521
|
if (rr) {
|
|
22458
22522
|
row(rerunEvidenceLabelKey(rr), rerunEvidenceValue(rr));
|
|
22459
|
-
if (rerunHasFailure(rr)) row("perspectives.d.lastRed",
|
|
22523
|
+
if (rerunHasFailure(rr)) row("perspectives.d.lastRed", rerunFailureValue(rr.lastRed));
|
|
22460
22524
|
}
|
|
22461
22525
|
frag.appendChild(dl);
|
|
22462
22526
|
|
|
@@ -314,6 +314,14 @@ declare const RerunReportSchema: z.ZodObject<{
|
|
|
314
314
|
at: z.ZodString;
|
|
315
315
|
deployedSha: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
316
316
|
deployedShaAmbiguous: z.ZodOptional<z.ZodBoolean>;
|
|
317
|
+
label: z.ZodOptional<z.ZodEnum<{
|
|
318
|
+
TEST_DRIFT: "TEST_DRIFT";
|
|
319
|
+
SPEC_CHANGE: "SPEC_CHANGE";
|
|
320
|
+
PRODUCT_BUG: "PRODUCT_BUG";
|
|
321
|
+
ENVIRONMENT: "ENVIRONMENT";
|
|
322
|
+
UNKNOWN: "UNKNOWN";
|
|
323
|
+
}>>;
|
|
324
|
+
headline: z.ZodOptional<z.ZodString>;
|
|
317
325
|
}, z.core.$strip>>;
|
|
318
326
|
touchedBy: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
319
327
|
touchedByDeploy: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
package/dist/package.json
CHANGED