@tokenoftrust/cli 2.4.16 → 2.4.17
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/package.json +1 -1
- package/src/commands/report.mjs +5 -1
- package/src/go-live-report.mjs +54 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/cli",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.17",
|
|
4
4
|
"description": "Token of Trust developer CLI — clone a tenant store, run it locally with save→reload, and submit it for preview. Installs the `tot` command.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Token of Trust",
|
package/src/commands/report.mjs
CHANGED
|
@@ -222,6 +222,9 @@ export function readStoreState(statePath) {
|
|
|
222
222
|
lifecycle: state?.lifecycle ?? "hot-standby",
|
|
223
223
|
commerceSync: state?.commerceSync ?? {},
|
|
224
224
|
goLive: state?.goLive ?? {},
|
|
225
|
+
// Absent/empty reads as "no open requests recorded", never as "nothing needed" — see
|
|
226
|
+
// newMigrationState() in agency-kit/tools/lib/migration-state-template.mjs.
|
|
227
|
+
merchantRequests: Array.isArray(state?.merchantRequests) ? state.merchantRequests : [],
|
|
225
228
|
};
|
|
226
229
|
}
|
|
227
230
|
|
|
@@ -295,7 +298,7 @@ export function run(argv, ctx, io = {}) {
|
|
|
295
298
|
}
|
|
296
299
|
|
|
297
300
|
const baseline = readJson(args.baseline ? resolve(args.baseline) : join(store, ".tot", "lighthouse-source-baseline.json"));
|
|
298
|
-
const { addOns, lifecycle, commerceSync, goLive } = readStoreState(
|
|
301
|
+
const { addOns, lifecycle, commerceSync, goLive, merchantRequests } = readStoreState(
|
|
299
302
|
args.state ? resolve(args.state) : join(store, ".tot", "migration-state.json"),
|
|
300
303
|
);
|
|
301
304
|
const generatedAt = evidence.generatedAt ?? now();
|
|
@@ -313,6 +316,7 @@ export function run(argv, ctx, io = {}) {
|
|
|
313
316
|
baselineCapturedAt: baseline?.capturedAt ?? null,
|
|
314
317
|
commerceSync,
|
|
315
318
|
goLive,
|
|
319
|
+
merchantRequests,
|
|
316
320
|
});
|
|
317
321
|
const outPath = resolve(args.out ?? join(pagesDir, "go-live-report.md"));
|
|
318
322
|
mkdirSync(dirname(outPath), { recursive: true });
|
package/src/go-live-report.mjs
CHANGED
|
@@ -511,6 +511,20 @@ export function summariseByProfile(pages) {
|
|
|
511
511
|
}).filter((p) => p.dimensions.length > 0);
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Open merchant requests, split into the ones that block go-live and everything else. A request
|
|
516
|
+
* is "open" while its status is `open` or `requested` — `received`/`declined`/`not-needed` are
|
|
517
|
+
* settled and drop out of both lists. Pure, so the report's go/no-go language stays testable.
|
|
518
|
+
* @param {{ id: string, ask: string, why: string, blocks?: string[], sensitive?: boolean, channel?: string, status: string }[]} requests
|
|
519
|
+
*/
|
|
520
|
+
export function openMerchantRequests(requests = []) {
|
|
521
|
+
const open = requests.filter((r) => r.status === "open" || r.status === "requested");
|
|
522
|
+
return {
|
|
523
|
+
open,
|
|
524
|
+
blockingGoLive: open.filter((r) => (r.blocks ?? []).includes("go-live")),
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
514
528
|
/** The whole report. Pure: every input is data, so the output is testable byte-for-byte. */
|
|
515
529
|
export function buildGoLiveReport(input) {
|
|
516
530
|
const {
|
|
@@ -524,7 +538,12 @@ export function buildGoLiveReport(input) {
|
|
|
524
538
|
commerceSync = {},
|
|
525
539
|
// Recorded go-live checklist confirmations, keyed by GO_LIVE_CHECKLIST.key.
|
|
526
540
|
goLive = {},
|
|
541
|
+
// Things we are waiting on the MERCHANT for (a credential, a decision, a fix to their own
|
|
542
|
+
// content) — the other direction from `checks`, which is what WE have open. Absent/empty
|
|
543
|
+
// reads as "no open requests recorded", never as "nothing needed".
|
|
544
|
+
merchantRequests = [],
|
|
527
545
|
} = input;
|
|
546
|
+
const { open: openMerchant, blockingGoLive } = openMerchantRequests(merchantRequests);
|
|
528
547
|
|
|
529
548
|
const parity = summariseParity(pages);
|
|
530
549
|
const { confirmed, risks, hotStandby } = classifyChecks(checks, { lifecycle });
|
|
@@ -828,7 +847,17 @@ export function buildGoLiveReport(input) {
|
|
|
828
847
|
|
|
829
848
|
out.push("### Blocks Storefront go-live");
|
|
830
849
|
out.push("");
|
|
831
|
-
|
|
850
|
+
// An open merchant request that names "go-live" in its `blocks` list is a go-live blocker by
|
|
851
|
+
// the same rule as any other open item here — recording it anywhere else (only in "Waiting on
|
|
852
|
+
// the merchant") would let the verdict read READY while something is still outstanding.
|
|
853
|
+
const merchantGoLiveRows = blockingGoLive.map((r) => [
|
|
854
|
+
r.ask,
|
|
855
|
+
r.why,
|
|
856
|
+
r.sensitive
|
|
857
|
+
? `Needs you — have the merchant send it via ${r.channel ?? "(no channel recorded)"}.`
|
|
858
|
+
: "Needs you — see **Waiting on the merchant** below.",
|
|
859
|
+
]);
|
|
860
|
+
if (goLiveRisks.length === 0 && merchantGoLiveRows.length === 0) {
|
|
832
861
|
out.push("**Nothing.** Every go-live check passed.");
|
|
833
862
|
} else {
|
|
834
863
|
out.push(hotStandby
|
|
@@ -838,12 +867,35 @@ export function buildGoLiveReport(input) {
|
|
|
838
867
|
: "_These must clear before the domain moves._");
|
|
839
868
|
out.push("");
|
|
840
869
|
out.push(table(
|
|
841
|
-
goLiveRisks.map((c) => [c.area, whyItMatters(c), whoCloses(c)]),
|
|
870
|
+
[...goLiveRisks.map((c) => [c.area, whyItMatters(c), whoCloses(c)]), ...merchantGoLiveRows],
|
|
842
871
|
["Area", "Why it matters", "What closes it"],
|
|
843
872
|
));
|
|
844
873
|
}
|
|
845
874
|
out.push("");
|
|
846
875
|
|
|
876
|
+
// ---- What we are waiting on the MERCHANT for — the other direction from everything above,
|
|
877
|
+
// which is work WE have open. Printed even when empty-but-for-blockers would read clean, since
|
|
878
|
+
// a non-blocking open ask (an analytics id, a review-access email) is still something the
|
|
879
|
+
// merchant needs to see asked for in plain language, not buried in an internal tracker.
|
|
880
|
+
if (openMerchant.length > 0) {
|
|
881
|
+
out.push("## Waiting on the merchant");
|
|
882
|
+
out.push("");
|
|
883
|
+
out.push("_These need something from you, not from us — a credential, a decision, or a fix "
|
|
884
|
+
+ "to your own content. Nothing below is stored as a secret: a sensitive item records only "
|
|
885
|
+
+ "that we asked and that we received it._");
|
|
886
|
+
out.push("");
|
|
887
|
+
out.push(table(
|
|
888
|
+
openMerchant.map((r) => [
|
|
889
|
+
r.ask,
|
|
890
|
+
r.why,
|
|
891
|
+
r.sensitive ? `Send via ${r.channel ?? "(no channel recorded)"}` : (r.channel ? `Via ${r.channel}` : "Let us know"),
|
|
892
|
+
(r.blocks ?? []).includes("go-live") ? "**go-live**" : ((r.blocks ?? []).join(", ") || "—"),
|
|
893
|
+
]),
|
|
894
|
+
["What we need", "Why", "How to send it", "Blocks"],
|
|
895
|
+
));
|
|
896
|
+
out.push("");
|
|
897
|
+
}
|
|
898
|
+
|
|
847
899
|
// COMMERCE READINESS IS PART OF GO-LIVE, not a section of its own. It was a separate heading
|
|
848
900
|
// listing the same kind of thing — work that must be closed before the store can open — so a
|
|
849
901
|
// reader had to hold two lists and de-duplicate them mentally. One list, one place.
|