@reddoorla/maintenance 0.69.0 → 0.72.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/README.md +15 -14
- package/dist/airtable-U2GTDTK5.js +9 -0
- package/dist/{announce-72R3LRNT.js → announce-HJCGEVJA.js} +6 -6
- package/dist/blux-FKZYMKLF.js +2205 -0
- package/dist/blux-FKZYMKLF.js.map +1 -0
- package/dist/{bump-deps-QNM3H4GI.js → bump-deps-GZEJAUKI.js} +3 -2
- package/dist/bump-deps-GZEJAUKI.js.map +1 -0
- package/dist/chunk-7MJBTV2R.js +145 -0
- package/dist/chunk-7MJBTV2R.js.map +1 -0
- package/dist/{chunk-2DCA7FHZ.js → chunk-7P7YETHG.js} +34 -12
- package/dist/chunk-7P7YETHG.js.map +1 -0
- package/dist/{chunk-42KKVLYN.js → chunk-APTAITXZ.js} +10 -2
- package/dist/chunk-APTAITXZ.js.map +1 -0
- package/dist/{chunk-6G7BC5SN.js → chunk-BHE5CUWI.js} +392 -7
- package/dist/chunk-BHE5CUWI.js.map +1 -0
- package/dist/{chunk-XWPZ46IN.js → chunk-BJCA7O4A.js} +2 -2
- package/dist/{chunk-C3PDS623.js → chunk-BWKK2ZXS.js} +67 -8
- package/dist/chunk-BWKK2ZXS.js.map +1 -0
- package/dist/{chunk-45AUGDFR.js → chunk-D4FVAIEJ.js} +6 -20
- package/dist/chunk-D4FVAIEJ.js.map +1 -0
- package/dist/{chunk-YQMYQAJX.js → chunk-GI4M2AMO.js} +2 -2
- package/dist/{chunk-OTBA7DON.js → chunk-GYNRZCM6.js} +7 -2
- package/dist/chunk-GYNRZCM6.js.map +1 -0
- package/dist/{chunk-6MT5W6UF.js → chunk-HR5SONJC.js} +6 -3
- package/dist/chunk-HR5SONJC.js.map +1 -0
- package/dist/{chunk-6JFOAPW4.js → chunk-JCITWZQR.js} +51 -19
- package/dist/chunk-JCITWZQR.js.map +1 -0
- package/dist/{chunk-GKSXZIMX.js → chunk-JGLAWXUC.js} +77 -3
- package/dist/chunk-JGLAWXUC.js.map +1 -0
- package/dist/{chunk-E2GKKUEX.js → chunk-KLB2OLPW.js} +26 -6
- package/dist/chunk-KLB2OLPW.js.map +1 -0
- package/dist/{chunk-RINXPU3H.js → chunk-KLVMJYZZ.js} +2 -2
- package/dist/chunk-KRDLHAKK.js +17 -0
- package/dist/chunk-KRDLHAKK.js.map +1 -0
- package/dist/{chunk-AESJBEM7.js → chunk-KRHPS3R4.js} +3 -3
- package/dist/{chunk-LYCKN7ZR.js → chunk-LJPCMXR7.js} +8 -5
- package/dist/chunk-LJPCMXR7.js.map +1 -0
- package/dist/{chunk-O6G4HHMF.js → chunk-NRISG4XD.js} +308 -104
- package/dist/chunk-NRISG4XD.js.map +1 -0
- package/dist/chunk-PKVZMFEB.js +315 -0
- package/dist/chunk-PKVZMFEB.js.map +1 -0
- package/dist/chunk-SL24DCGC.js +41 -0
- package/dist/chunk-SL24DCGC.js.map +1 -0
- package/dist/{chunk-A5KYRGQA.js → chunk-SQJ53Z7R.js} +4 -4
- package/dist/cli/bin.js +63 -19
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.d.ts +1 -1
- package/dist/cli/commands/audit.js +11 -9
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/configs/playwright-a11y.d.ts +1 -1
- package/dist/configs/playwright-a11y.js +1 -3
- package/dist/{convert-to-pnpm-XH7NYRVK.js → convert-to-pnpm-SVFDLXZS.js} +3 -2
- package/dist/convert-to-pnpm-SVFDLXZS.js.map +1 -0
- package/dist/{digest-Q2TAQHXF.js → digest-VX7Q4MNF.js} +8 -8
- package/dist/{ensure-site-2PF522VL.js → ensure-site-O7G5ZJS7.js} +2 -2
- package/dist/forms/index.d.ts +5 -2
- package/dist/forms/index.js +22 -9
- package/dist/forms/index.js.map +1 -1
- package/dist/{github-signals-CLQC2IPY.js → github-signals-QVW2LB7N.js} +5 -5
- package/dist/health-endpoint-IYR5VBUT.js +54 -0
- package/dist/health-endpoint-IYR5VBUT.js.map +1 -0
- package/dist/index.d.ts +136 -20
- package/dist/index.js +207 -64
- package/dist/index.js.map +1 -1
- package/dist/{init-UA6D7GKW.js → init-CU6PVZRG.js} +9 -5
- package/dist/init-CU6PVZRG.js.map +1 -0
- package/dist/{launch-AENAS2O2.js → launch-JWXCTJRG.js} +9 -9
- package/dist/{lighthouse-airtable-UBSXKHAQ.js → lighthouse-airtable-J5TLASJC.js} +3 -3
- package/dist/{onboard-X6KJ5Z2V.js → onboard-6UQE5QIO.js} +2 -2
- package/dist/{orchestrate-GADNFGDH.js → orchestrate-ZDH24Z6Y.js} +5 -5
- package/dist/{preflight-D5RQGX4V.js → preflight-BNTMWTPG.js} +7 -7
- package/dist/probe-DJAMLVTT.js +46 -0
- package/dist/probe-DJAMLVTT.js.map +1 -0
- package/dist/recipes/sync-configs.d.ts +1 -1
- package/dist/{renovate-dispatch-LG4RJGDY.js → renovate-dispatch-C3ALLACX.js} +2 -2
- package/dist/{report-3FJ224H5.js → report-YLFSGNWR.js} +12 -12
- package/dist/run-migration-LJNNZWIV.js +205 -0
- package/dist/run-migration-LJNNZWIV.js.map +1 -0
- package/dist/{self-updating-JTTFOJ7Q.js → self-updating-64FNRQB5.js} +2 -2
- package/dist/{selftest-55OJIWEB.js → selftest-7DPNGL6R.js} +12 -9
- package/dist/selftest-7DPNGL6R.js.map +1 -0
- package/dist/smoke-suite-TWILWDSF.js +54 -0
- package/dist/smoke-suite-TWILWDSF.js.map +1 -0
- package/dist/{svelte-codemods-KJLNH6FQ.js → svelte-codemods-RVDTTXFD.js} +3 -2
- package/dist/svelte-codemods-RVDTTXFD.js.map +1 -0
- package/dist/{sync-configs-TIBO6DUJ.js → sync-configs-BUUD6L5Q.js} +3 -2
- package/dist/sync-configs-BUUD6L5Q.js.map +1 -0
- package/dist/{types-Dg4mHvyf.d.ts → types-0jreMCF5.d.ts} +2 -2
- package/dist/{upgrade-TPTE26FG.js → upgrade-HHKWYJRN.js} +3 -2
- package/dist/upgrade-HHKWYJRN.js.map +1 -0
- package/dist/{websites-6YTT5ZTO.js → websites-EH2ULELZ.js} +8 -2
- package/dist/{write-audits-to-airtable-IWOO4FFH.js → write-audits-to-airtable-LZDYTNX5.js} +4 -4
- package/package.json +4 -1
- package/dist/airtable-WGQQ3KAD.js +0 -9
- package/dist/bump-deps-QNM3H4GI.js.map +0 -1
- package/dist/chunk-2DCA7FHZ.js.map +0 -1
- package/dist/chunk-42KKVLYN.js.map +0 -1
- package/dist/chunk-45AUGDFR.js.map +0 -1
- package/dist/chunk-6G7BC5SN.js.map +0 -1
- package/dist/chunk-6JFOAPW4.js.map +0 -1
- package/dist/chunk-6MT5W6UF.js.map +0 -1
- package/dist/chunk-C3PDS623.js.map +0 -1
- package/dist/chunk-E2GKKUEX.js.map +0 -1
- package/dist/chunk-GKSXZIMX.js.map +0 -1
- package/dist/chunk-LYCKN7ZR.js.map +0 -1
- package/dist/chunk-O6G4HHMF.js.map +0 -1
- package/dist/chunk-OTBA7DON.js.map +0 -1
- package/dist/convert-to-pnpm-XH7NYRVK.js.map +0 -1
- package/dist/init-UA6D7GKW.js.map +0 -1
- package/dist/selftest-55OJIWEB.js.map +0 -1
- package/dist/svelte-codemods-KJLNH6FQ.js.map +0 -1
- package/dist/sync-configs-TIBO6DUJ.js.map +0 -1
- package/dist/upgrade-TPTE26FG.js.map +0 -1
- /package/dist/{airtable-WGQQ3KAD.js.map → airtable-U2GTDTK5.js.map} +0 -0
- /package/dist/{announce-72R3LRNT.js.map → announce-HJCGEVJA.js.map} +0 -0
- /package/dist/{chunk-XWPZ46IN.js.map → chunk-BJCA7O4A.js.map} +0 -0
- /package/dist/{chunk-YQMYQAJX.js.map → chunk-GI4M2AMO.js.map} +0 -0
- /package/dist/{chunk-RINXPU3H.js.map → chunk-KLVMJYZZ.js.map} +0 -0
- /package/dist/{chunk-AESJBEM7.js.map → chunk-KRHPS3R4.js.map} +0 -0
- /package/dist/{chunk-A5KYRGQA.js.map → chunk-SQJ53Z7R.js.map} +0 -0
- /package/dist/{digest-Q2TAQHXF.js.map → digest-VX7Q4MNF.js.map} +0 -0
- /package/dist/{ensure-site-2PF522VL.js.map → ensure-site-O7G5ZJS7.js.map} +0 -0
- /package/dist/{github-signals-CLQC2IPY.js.map → github-signals-QVW2LB7N.js.map} +0 -0
- /package/dist/{launch-AENAS2O2.js.map → launch-JWXCTJRG.js.map} +0 -0
- /package/dist/{lighthouse-airtable-UBSXKHAQ.js.map → lighthouse-airtable-J5TLASJC.js.map} +0 -0
- /package/dist/{onboard-X6KJ5Z2V.js.map → onboard-6UQE5QIO.js.map} +0 -0
- /package/dist/{orchestrate-GADNFGDH.js.map → orchestrate-ZDH24Z6Y.js.map} +0 -0
- /package/dist/{preflight-D5RQGX4V.js.map → preflight-BNTMWTPG.js.map} +0 -0
- /package/dist/{renovate-dispatch-LG4RJGDY.js.map → renovate-dispatch-C3ALLACX.js.map} +0 -0
- /package/dist/{report-3FJ224H5.js.map → report-YLFSGNWR.js.map} +0 -0
- /package/dist/{self-updating-JTTFOJ7Q.js.map → self-updating-64FNRQB5.js.map} +0 -0
- /package/dist/{websites-6YTT5ZTO.js.map → websites-EH2ULELZ.js.map} +0 -0
- /package/dist/{write-audits-to-airtable-IWOO4FFH.js.map → write-audits-to-airtable-LZDYTNX5.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as AuditResult, S as Site, A as AuditName, b as RecipeResult, R as RecipeName, I as InventoryProvider } from './types-
|
|
2
|
-
export { C as ConfigName } from './types-
|
|
1
|
+
import { a as AuditResult, S as Site, A as AuditName, b as RecipeResult, R as RecipeName, I as InventoryProvider } from './types-0jreMCF5.js';
|
|
2
|
+
export { C as ConfigName } from './types-0jreMCF5.js';
|
|
3
3
|
import * as airtable_lib_airtable_base_js from 'airtable/lib/airtable_base.js';
|
|
4
4
|
import { F as FormType } from './types-RXY-vY-5.js';
|
|
5
5
|
export { SyncConfigsOptions, syncConfigs } from './recipes/sync-configs.js';
|
|
@@ -41,7 +41,9 @@ type DiscoverDeps = {
|
|
|
41
41
|
fetchText: (url: string) => Promise<string | null>;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
/** One route probed across desktop engines + mobile devices, plus the internal links found on it
|
|
44
|
+
/** One route probed across desktop engines + mobile devices, plus the internal links found on it,
|
|
45
|
+
* plus the chromium-derived reachability + SEO signals (captured on the page chromium already
|
|
46
|
+
* opened — no extra navigation). */
|
|
45
47
|
type RouteResult = {
|
|
46
48
|
url: string;
|
|
47
49
|
/** Per desktop engine (chromium/firefox/webkit): loaded with no JS error + a visible main landmark. */
|
|
@@ -56,6 +58,12 @@ type RouteResult = {
|
|
|
56
58
|
}>;
|
|
57
59
|
/** Same-origin links discovered on the page (absolute URLs), for the Links check. */
|
|
58
60
|
links: string[];
|
|
61
|
+
/** HTTP status of the chromium navigation (2xx/3xx = reachable). null = the nav failed/threw. */
|
|
62
|
+
status: number | null;
|
|
63
|
+
/** The chromium `<title>` (trimmed by the reducer), or null when not captured. */
|
|
64
|
+
title: string | null;
|
|
65
|
+
/** The chromium `meta[name="description"]` content, or null when absent/not captured. */
|
|
66
|
+
metaDescription: string | null;
|
|
59
67
|
};
|
|
60
68
|
type LinkResult = {
|
|
61
69
|
url: string;
|
|
@@ -68,6 +76,29 @@ type BrowserRunner = {
|
|
|
68
76
|
close?: () => Promise<void>;
|
|
69
77
|
};
|
|
70
78
|
|
|
79
|
+
/** Outcome of driving one site's contact form. `formPresent:false` ⇒ n/a
|
|
80
|
+
* (persisted). `testModeUndeclared` ⇒ the site's /health does not declare
|
|
81
|
+
* `forms.testMode`, so the probe refused to submit — a plain skip, prior
|
|
82
|
+
* verdict preserved. */
|
|
83
|
+
type FormSubmitOutcome = {
|
|
84
|
+
formPresent: false;
|
|
85
|
+
} | {
|
|
86
|
+
formPresent: true;
|
|
87
|
+
success: boolean;
|
|
88
|
+
detail?: string;
|
|
89
|
+
} | {
|
|
90
|
+
testModeUndeclared: true;
|
|
91
|
+
};
|
|
92
|
+
/** Injected browser IO. The real impl drives Playwright; tests pass a fake. */
|
|
93
|
+
type FormRunner = {
|
|
94
|
+
submit: (opts: {
|
|
95
|
+
baseUrl: string;
|
|
96
|
+
testMode: boolean;
|
|
97
|
+
testSitekey: string;
|
|
98
|
+
}) => Promise<FormSubmitOutcome>;
|
|
99
|
+
close?: () => Promise<void>;
|
|
100
|
+
};
|
|
101
|
+
|
|
71
102
|
/** Result of probing a site's latest PRODUCTION Netlify deploy. Every field is
|
|
72
103
|
* nullable: a site with no production deploy yet degrades to all-nulls (a real
|
|
73
104
|
* "none" verdict). A read FAILURE is NOT represented here — it surfaces as
|
|
@@ -109,6 +140,38 @@ type NetlifyDeployDeps = {
|
|
|
109
140
|
now: Date;
|
|
110
141
|
};
|
|
111
142
|
|
|
143
|
+
/** The parts of the deployed `/health` body this audit reads. `ok` is the endpoint's self-rollup
|
|
144
|
+
* (`functionRan && prismic !== "error"`); `prismic` is the server-side CMS probe status; `forms`
|
|
145
|
+
* are booleans recorded for the dashboard only. A public endpoint can return anything, so every
|
|
146
|
+
* field is validated/coerced by `parseHealthBody`. */
|
|
147
|
+
type HealthBody = {
|
|
148
|
+
ok: boolean;
|
|
149
|
+
prismic: "ok" | "error" | "skipped" | null;
|
|
150
|
+
forms: {
|
|
151
|
+
ingestUrl: boolean;
|
|
152
|
+
ingestToken: boolean;
|
|
153
|
+
turnstile: boolean;
|
|
154
|
+
} | null;
|
|
155
|
+
};
|
|
156
|
+
/** Outcome of fetching `{deployedUrl}/health`, distinguishing "no usable report" (`present:false`
|
|
157
|
+
* → self-skip, the writer preserves the prior verdict) from "read a body" (`present:true`
|
|
158
|
+
* → a real pass/fail). `present:true` with a real `HealthBody` is a 200 JSON response (`ok`
|
|
159
|
+
* drives pass/fail); the fetch layer also synthesizes an all-`ok:false` body for "deployed but
|
|
160
|
+
* erroring" responses (a non-404 non-2xx, or a 200 that isn't valid JSON) so those fail loudly
|
|
161
|
+
* instead of silently skipping. Mirrors `netlify-deploy`'s `NetlifyDeployFetch` read/no-read split. */
|
|
162
|
+
type HealthFetch = {
|
|
163
|
+
present: false;
|
|
164
|
+
} | {
|
|
165
|
+
present: true;
|
|
166
|
+
body: HealthBody;
|
|
167
|
+
};
|
|
168
|
+
/** Injected IO so the audit is unit-testable without a network. `fetchHealth` returns a
|
|
169
|
+
* `HealthFetch`; `now` is the clock for the checked-at stamp. */
|
|
170
|
+
type FunctionHealthDeps = {
|
|
171
|
+
fetchHealth: (deployedUrl: string) => Promise<HealthFetch>;
|
|
172
|
+
now: Date;
|
|
173
|
+
};
|
|
174
|
+
|
|
112
175
|
/** One GitHub Dependabot alert, mapped to the fields the security audit needs. */
|
|
113
176
|
type DependabotAlert = {
|
|
114
177
|
/** The vulnerable package name (`dependency.package.name`). */
|
|
@@ -147,8 +210,12 @@ type AuditContext = {
|
|
|
147
210
|
discoverDeps?: DiscoverDeps;
|
|
148
211
|
/** Playwright runner injection for the browser audit (tests). Defaults to real Playwright. */
|
|
149
212
|
browserRunner?: BrowserRunner;
|
|
213
|
+
/** Playwright runner injection for the form-e2e audit (tests). Defaults to real Playwright. */
|
|
214
|
+
formRunner?: FormRunner;
|
|
150
215
|
/** Netlify API injection for the netlify-deploy audit (tests). Defaults to a real API call. */
|
|
151
216
|
netlifyDeployDeps?: NetlifyDeployDeps;
|
|
217
|
+
/** `/health` fetch injection for the function-health audit (tests). Defaults to a real GET. */
|
|
218
|
+
functionHealthDeps?: FunctionHealthDeps;
|
|
152
219
|
/** GitHub Dependabot fetch injection for the security audit (tests). Defaults to a real client
|
|
153
220
|
* from GITHUB_TOKEN; absent token or no site.gitRepo → the pnpm/npm audit fallback. */
|
|
154
221
|
dependabotDeps?: DependabotDeps;
|
|
@@ -250,10 +317,11 @@ type InitOptions = {
|
|
|
250
317
|
steps?: InitStep[];
|
|
251
318
|
};
|
|
252
319
|
/** convert-to-pnpm → onboard → sync-configs → svelte-codemods →
|
|
253
|
-
* a11y-fixtures-page → audit. Order is
|
|
254
|
-
* the prior one's output (pnpm before
|
|
255
|
-
* before sync-configs writes lighthouserc,
|
|
256
|
-
* actually has a route to hit
|
|
320
|
+
* a11y-fixtures-page → health-endpoint → smoke-suite → audit. Order is
|
|
321
|
+
* deliberate — every step depends on the prior one's output (pnpm before
|
|
322
|
+
* onboard's installs, onboard's deps before sync-configs writes lighthouserc,
|
|
323
|
+
* fixtures page before audit actually has a route to hit; smoke-suite's
|
|
324
|
+
* `pnpm install` lands before the closing audit). */
|
|
257
325
|
declare const DEFAULT_INIT_STEPS: InitStep[];
|
|
258
326
|
/**
|
|
259
327
|
* One-shot guided onboarding. Runs the default step sequence against a
|
|
@@ -296,11 +364,15 @@ type AirtableInventoryOptions = {
|
|
|
296
364
|
/**
|
|
297
365
|
* Read sites from the Airtable Websites table as an InventoryProvider.
|
|
298
366
|
* Each row becomes one Site; `path` is computed as `{workdir}/{slug}`.
|
|
299
|
-
* Only `maintenance`
|
|
300
|
-
* (
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
367
|
+
* Only LIVE `maintenance` sites that have a `url` are included — pre-launch
|
|
368
|
+
* stages ("launch period" / "in development", via isPreLaunch) are excluded so a
|
|
369
|
+
* not-yet-live site is never audited as production (its deploy/domain/uptime/CMS
|
|
370
|
+
* audits would fail against nothing and red its Airtable row) nor swept by other
|
|
371
|
+
* `--fleet airtable` ops; it re-enters the fleet when a Launch report flips its
|
|
372
|
+
* Status to "maintenance". The production URL is exposed as `Site.deployedUrl` so
|
|
373
|
+
* the lighthouse audit can run against it with no checkout. `repoUrl` is
|
|
374
|
+
* intentionally NOT set from `url` — a clone source must come from `gitRepo`
|
|
375
|
+
* (`owner/repo`), never the production URL.
|
|
304
376
|
*/
|
|
305
377
|
declare function fromAirtableBase(base: AirtableBase, opts?: AirtableInventoryOptions): InventoryProvider;
|
|
306
378
|
|
|
@@ -334,9 +406,10 @@ type WebsiteRow = {
|
|
|
334
406
|
maintenanceFreq: Frequency;
|
|
335
407
|
testingFreq: Frequency;
|
|
336
408
|
/** The literal Airtable cell values behind the coerced frequencies. `toFrequency`
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
409
|
+
* trims whitespace ("Monthly " reads as Monthly), then maps any still-unrecognized
|
|
410
|
+
* value ("Quaterly") to "None" with a LOUD console.warn so nothing bogus reaches a
|
|
411
|
+
* client email and the drop is never invisible. Preflight validates THESE to surface
|
|
412
|
+
* the same failure as a structured finding. Null = blank cell. */
|
|
340
413
|
maintenanceFreqRaw: string | null;
|
|
341
414
|
testingFreqRaw: string | null;
|
|
342
415
|
/** Last manually-recorded maintenance day (used as fallback when no Reports row exists). */
|
|
@@ -418,6 +491,22 @@ type WebsiteRow = {
|
|
|
418
491
|
deployStatus: string | null;
|
|
419
492
|
lastDeployAt: string | null;
|
|
420
493
|
deployLogUrl: string | null;
|
|
494
|
+
/** When the `netlify-deploy` audit last RAN (freshness stamp for `deployStatus`). The audit
|
|
495
|
+
* already writes "Deploy checked at"; this read-back is the Plan-2 fix so `deployEvidence`
|
|
496
|
+
* (Plan 4) can gate on check time — NOT on `lastDeployAt`, which is deploy time, not check time. */
|
|
497
|
+
deployCheckedAt: string | null;
|
|
498
|
+
/** Function-health verdict (the `function-health` audit): the deployed `/health` function
|
|
499
|
+
* answered `ok:true` (pass) or `ok:false` (fail). Single-select `pass`/`fail`; null = never ran
|
|
500
|
+
* / unreachable (→ Plan 4 maps to unknown/amber). Kept SEPARATE from `deployStatus` so
|
|
501
|
+
* `isFailedDeployStatus` keeps meaning "the build failed". */
|
|
502
|
+
functionHealth: "pass" | "fail" | null;
|
|
503
|
+
/** CMS reachability (server-side), derived from the same `/health` body's `details.prismic ===
|
|
504
|
+
* "ok"`. Single-select `pass`/`fail`; null = never ran. No per-site Prismic token or identity
|
|
505
|
+
* column is ever built — this rides `/health`. */
|
|
506
|
+
cmsReachable: "pass" | "fail" | null;
|
|
507
|
+
/** When the `function-health` audit last ran — the freshness gate for BOTH `functionHealth` and
|
|
508
|
+
* `cmsReachable`. Null = never ran. */
|
|
509
|
+
functionHealthCheckedAt: string | null;
|
|
421
510
|
/** Deployed-URL browser probe (the `browser` audit): cross-engine render OK, mobile render OK,
|
|
422
511
|
* internal-links OK + broken count, and when it last ran (one timestamp gates all three). */
|
|
423
512
|
crossbrowserOk: boolean | null;
|
|
@@ -425,6 +514,13 @@ type WebsiteRow = {
|
|
|
425
514
|
linksOk: boolean | null;
|
|
426
515
|
brokenLinks: number | null;
|
|
427
516
|
browserCheckedAt: string | null;
|
|
517
|
+
/** Uptime-reachable verdict (browser audit): every sampled route returned 2xx/3xx. Single-select
|
|
518
|
+
* `pass`/`fail`; null = never ran. Point-in-time. Freshness-gated by `browserCheckedAt`. */
|
|
519
|
+
reachableOk: "pass" | "fail" | null;
|
|
520
|
+
/** Titles & meta verdict (browser audit, chromium): every sampled route has a non-empty `<title>`
|
|
521
|
+
* ≤ 70 chars + a non-empty meta description, and no duplicate titles across the sample.
|
|
522
|
+
* Single-select `pass`/`fail`; null = never ran. Freshness-gated by `browserCheckedAt`. */
|
|
523
|
+
titleMetaOk: "pass" | "fail" | null;
|
|
428
524
|
/** Per-site copy overrides (M6a). Blank → null → the DEFAULT_COPY value. */
|
|
429
525
|
copyIntro: string | null;
|
|
430
526
|
copyContact: string | null;
|
|
@@ -447,6 +543,16 @@ type WebsiteRow = {
|
|
|
447
543
|
defaultBranchCi: string | null;
|
|
448
544
|
lastCommitAt: string | null;
|
|
449
545
|
githubSignalsAt: string | null;
|
|
546
|
+
/** Per-site smoke-suite verdict (the `smoke` audit runs `pnpm test:smoke`).
|
|
547
|
+
* Single-select pass/fail; null = never ran. `lastSmokeAt` gates freshness. */
|
|
548
|
+
smokeOk: "pass" | "fail" | null;
|
|
549
|
+
lastSmokeAt: string | null;
|
|
550
|
+
/** Synthetic form end-to-end verdict (the `form-e2e` audit submits the real prod
|
|
551
|
+
* contact form in test-mode). Single-select pass/fail; null = never ran OR (with
|
|
552
|
+
* a fresh `formE2eCheckedAt`) no contact form → n/a. `formE2eCheckedAt` gates
|
|
553
|
+
* freshness AND encodes the n/a-vs-never-ran distinction. */
|
|
554
|
+
formE2eOk: "pass" | "fail" | null;
|
|
555
|
+
formE2eCheckedAt: string | null;
|
|
450
556
|
notifyRouting: NotifyRouting | null;
|
|
451
557
|
};
|
|
452
558
|
type Severity = "low" | "moderate" | "high" | "critical";
|
|
@@ -559,7 +665,7 @@ type ReportData = {
|
|
|
559
665
|
};
|
|
560
666
|
|
|
561
667
|
/** A single auto-check outcome. `pass` + fresh ⇒ the caller ticks the box. */
|
|
562
|
-
type EvidenceResult = "pass" | "fail" | "unknown";
|
|
668
|
+
type EvidenceResult = "pass" | "fail" | "unknown" | "n/a";
|
|
563
669
|
type EvidenceRecord = {
|
|
564
670
|
result: EvidenceResult;
|
|
565
671
|
checkedAt: string | null;
|
|
@@ -602,9 +708,17 @@ type ReportRow = {
|
|
|
602
708
|
* subset (see src/reports/checklist.ts). */
|
|
603
709
|
checklist: Record<string, boolean>;
|
|
604
710
|
/** Snapshot of the auto-tick evidence at draft time, keyed by checklist field → evidence
|
|
605
|
-
* record. Null when the report predates auto-tick or carried no auto-checked items.
|
|
606
|
-
*
|
|
711
|
+
* record. Null when the report predates auto-tick or carried no auto-checked items. This is the
|
|
712
|
+
* health gate's source of truth: `isHealthGateClear`/`gatingHealth` (src/reports/checklist.ts)
|
|
713
|
+
* read these evidence records, NOT the checklist booleans — and also drive the dashboard badges. */
|
|
607
714
|
autoEvidence: Record<string, EvidenceRecord> | null;
|
|
715
|
+
/** Logged send-anyway override (Phase 10). When `sendOverride` is true AND `overrideReason` is
|
|
716
|
+
* non-empty, the health gate is bypassed for THIS report; `overrideBy`/`overrideAt` are the
|
|
717
|
+
* audit trail (parallel to approvedBy/approvedAt). Missing cells read false/null. */
|
|
718
|
+
sendOverride: boolean;
|
|
719
|
+
overrideReason: string | null;
|
|
720
|
+
overrideBy: string | null;
|
|
721
|
+
overrideAt: string | null;
|
|
608
722
|
};
|
|
609
723
|
|
|
610
724
|
type DraftOptions = {
|
|
@@ -833,9 +947,9 @@ type AttentionItem = {
|
|
|
833
947
|
autoFixExhausted?: boolean;
|
|
834
948
|
};
|
|
835
949
|
|
|
836
|
-
type FleetEventType = "pr_automerged" | "vuln_cleared" | "ci_recovered" | "site_launched" | "fleet_swept" | "cert_renewed";
|
|
950
|
+
type FleetEventType = "pr_automerged" | "vuln_cleared" | "ci_recovered" | "site_launched" | "fleet_swept" | "cert_renewed" | "report_sent_with_override";
|
|
837
951
|
|
|
838
|
-
type Tier = "attention" | "watch" | "healthy";
|
|
952
|
+
type Tier = "attention" | "watch" | "healthy" | "pre-launch";
|
|
839
953
|
type SiteCard = {
|
|
840
954
|
site: WebsiteRow;
|
|
841
955
|
tier: Tier;
|
|
@@ -871,6 +985,8 @@ type CockpitSummary = {
|
|
|
871
985
|
attention: number;
|
|
872
986
|
watch: number;
|
|
873
987
|
healthy: number;
|
|
988
|
+
/** Count of pre-live "launch period" sites — muted, never counted as broken. */
|
|
989
|
+
preLaunch: number;
|
|
874
990
|
criticalHighVulns: number;
|
|
875
991
|
lighthouseBelowFloor: number;
|
|
876
992
|
deliveryFailures: number;
|