@codyswann/lisa 2.272.0 → 2.274.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/cli/doctor-readiness-blockers.d.ts +154 -0
- package/dist/cli/doctor-readiness-blockers.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-blockers.js +280 -0
- package/dist/cli/doctor-readiness-blockers.js.map +1 -0
- package/dist/cli/doctor-readiness-journey-freshness.d.ts +36 -0
- package/dist/cli/doctor-readiness-journey-freshness.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-journey-freshness.js +166 -0
- package/dist/cli/doctor-readiness-journey-freshness.js.map +1 -0
- package/dist/cli/doctor-readiness-journey.d.ts +110 -0
- package/dist/cli/doctor-readiness-journey.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-journey.js +233 -0
- package/dist/cli/doctor-readiness-journey.js.map +1 -0
- package/dist/cli/doctor-readiness.d.ts +9 -5
- package/dist/cli/doctor-readiness.d.ts.map +1 -1
- package/dist/cli/doctor-readiness.js +40 -27
- package/dist/cli/doctor-readiness.js.map +1 -1
- package/dist/cli/doctor-worker-epoch.d.ts +5 -0
- package/dist/cli/doctor-worker-epoch.d.ts.map +1 -1
- package/dist/cli/doctor-worker-epoch.js +10 -134
- package/dist/cli/doctor-worker-epoch.js.map +1 -1
- package/dist/cli/doctor-worker-journey.d.ts +118 -0
- package/dist/cli/doctor-worker-journey.d.ts.map +1 -0
- package/dist/cli/doctor-worker-journey.js +222 -0
- package/dist/cli/doctor-worker-journey.js.map +1 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +17 -0
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The seven-blocker gate and narrowed claim for repository readiness (RRR-5,
|
|
3
|
+
* #1857).
|
|
4
|
+
*
|
|
5
|
+
* RRR-3 (#1855) produces the eight readiness dimensions and persists the report;
|
|
6
|
+
* this module turns their findings into the thing that decides what the
|
|
7
|
+
* repository may be *claimed* to be. It is a pure mapping from dimension
|
|
8
|
+
* findings to the closed set of seven ship blockers (B1..B7 per the
|
|
9
|
+
* `readiness-rubric` rule, RRR-1 #1853), a verdict flip to `NOT_READY` when any
|
|
10
|
+
* blocker stands, and the required operator-language narrowed claim. Blocker 7
|
|
11
|
+
* ("no way to prove the claimed user-visible outcome") is expressed in PRD
|
|
12
|
+
* #1738's claim→evidence shape (`claim-evidence-mapping`) so there is exactly
|
|
13
|
+
* one definition of what establishes a claim across both PRDs.
|
|
14
|
+
*
|
|
15
|
+
* It gates a *claim*, not a *process*: per intake decision O1 nothing here
|
|
16
|
+
* hard-blocks. The verdict ladder is the shipped one — no new enum (F2). The
|
|
17
|
+
* blocker set is closed in v1 and extended only by editing this module and the
|
|
18
|
+
* rule (intake decision O4).
|
|
19
|
+
* @module cli/doctor-readiness-blockers
|
|
20
|
+
*/
|
|
21
|
+
/** Verdict ladder reused from the shipped doctor surface (readiness-rubric). */
|
|
22
|
+
export type ReadinessVerdict = "READY" | "READY_WITH_WARNINGS" | "NOT_READY";
|
|
23
|
+
/**
|
|
24
|
+
* The closed v1 set of seven ship blockers (readiness-rubric, RRR-1 #1853).
|
|
25
|
+
* Extending it is a deliberate rule edit, never a configuration surface (intake
|
|
26
|
+
* decision O4). A standing blocker makes the claim "an unattended fleet may run
|
|
27
|
+
* here" false and flips the verdict to `NOT_READY`.
|
|
28
|
+
*/
|
|
29
|
+
export declare const SHIP_BLOCKER_IDS: readonly ["B1", "B2", "B3", "B4", "B5", "B6", "B7"];
|
|
30
|
+
/** One of the seven closed-set ship blocker ids. */
|
|
31
|
+
export type ShipBlockerId = (typeof SHIP_BLOCKER_IDS)[number];
|
|
32
|
+
/**
|
|
33
|
+
* The reason blocker 7 renders `SKIP` when PRD #1738's claim→evidence contract
|
|
34
|
+
* is unavailable — a stated reason, never a guessed provability verdict
|
|
35
|
+
* (RRR-5 technical approach point 4).
|
|
36
|
+
*/
|
|
37
|
+
export declare const CLAIM_EVIDENCE_UNAVAILABLE_REASON = "claim-evidence contract not yet available";
|
|
38
|
+
/**
|
|
39
|
+
* PRD #1738's claim→evidence shape (`claim-evidence-mapping`), consumed — never
|
|
40
|
+
* redefined — by blocker 7. A claim binds to one boundary and is established
|
|
41
|
+
* only by evidence of a kind that reaches it; a non-empty `not_established`
|
|
42
|
+
* means the user-visible outcome is not provable.
|
|
43
|
+
*/
|
|
44
|
+
interface ClaimEvidence {
|
|
45
|
+
readonly claim_id?: string;
|
|
46
|
+
readonly boundary?: string;
|
|
47
|
+
readonly required_evidence_kinds?: readonly string[];
|
|
48
|
+
readonly not_established?: readonly string[];
|
|
49
|
+
readonly not_established_reviewed?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A finding attached to a readiness dimension. Loosely typed because findings
|
|
53
|
+
* arrive from the persisted `.lisa/readiness.json` (or a fixture) as JSON. A
|
|
54
|
+
* finding evidences a blocker only when it names one and carries evidence.
|
|
55
|
+
*/
|
|
56
|
+
interface ReadinessFinding {
|
|
57
|
+
readonly blocker?: string;
|
|
58
|
+
readonly severity?: string;
|
|
59
|
+
readonly blocking?: boolean;
|
|
60
|
+
readonly invariant_violated?: string;
|
|
61
|
+
readonly evidence?: string;
|
|
62
|
+
readonly claim_evidence?: ClaimEvidence;
|
|
63
|
+
readonly why_proof_missed?: string;
|
|
64
|
+
readonly root_correction?: string;
|
|
65
|
+
readonly machinery_to_remove?: readonly string[];
|
|
66
|
+
}
|
|
67
|
+
/** The minimal dimension shape blocker detection reads (record or fixture). */
|
|
68
|
+
export interface ReadinessDimensionInput {
|
|
69
|
+
readonly id: string;
|
|
70
|
+
readonly status: string;
|
|
71
|
+
readonly findings: readonly unknown[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A standing ship blocker plus the finding that evidences it. A blocker is
|
|
75
|
+
* never emitted without an evidencing finding — the same discipline
|
|
76
|
+
* `convergent-review` applies to blocking findings without a failure scenario.
|
|
77
|
+
*/
|
|
78
|
+
export interface DetectedBlocker {
|
|
79
|
+
readonly id: ShipBlockerId;
|
|
80
|
+
readonly label: string;
|
|
81
|
+
readonly owning_dimensions: readonly string[];
|
|
82
|
+
readonly dimension_id: string;
|
|
83
|
+
readonly invariant_violated: string;
|
|
84
|
+
readonly evidence: string;
|
|
85
|
+
readonly claim_evidence?: ClaimEvidence;
|
|
86
|
+
}
|
|
87
|
+
/** Options shared by the blocker-detection surfaces. */
|
|
88
|
+
export interface BlockerDetectionOptions {
|
|
89
|
+
/**
|
|
90
|
+
* Whether PRD #1738's claim→evidence contract is available. When `false`,
|
|
91
|
+
* blocker 7 degrades to `SKIP` with a stated reason instead of guessing.
|
|
92
|
+
* Defaults to `true` — #1738 has landed.
|
|
93
|
+
*/
|
|
94
|
+
readonly claimEvidenceContractAvailable?: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** The provability (blocker 7) sub-assessment for the execution/proof dimension. */
|
|
97
|
+
export interface ProvabilityAssessment {
|
|
98
|
+
readonly status: "STANDS" | "CLEAR" | "SKIP";
|
|
99
|
+
readonly reason?: string;
|
|
100
|
+
readonly finding?: ReadinessFinding;
|
|
101
|
+
}
|
|
102
|
+
/** The blocker-gate assessment `checkRepositoryReadiness` persists. */
|
|
103
|
+
export interface ReadinessAssessment {
|
|
104
|
+
readonly verdict: ReadinessVerdict;
|
|
105
|
+
readonly blockers: readonly DetectedBlocker[];
|
|
106
|
+
readonly narrowed_claim: string | null;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Gate the unattended-operation claim on the seven ship blockers and, when any
|
|
110
|
+
* stands, emit the narrowed claim. This is RRR-5's pure core: it consumes the
|
|
111
|
+
* dimension findings, maps them to blockers (blocker 7 via PRD #1738's evidence
|
|
112
|
+
* shape), flips the verdict to `NOT_READY` when a blocker stands, and produces
|
|
113
|
+
* the operator-language narrowed claim. It gates a *claim*, not a *process* —
|
|
114
|
+
* intake decision O1 keeps every Lisa surface warn-only.
|
|
115
|
+
* @param dimensions - Per-dimension records (from the report or a fixture)
|
|
116
|
+
* @param options - Blocker-detection options (claim→evidence availability)
|
|
117
|
+
* @returns The verdict, standing blockers, and narrowed claim
|
|
118
|
+
*/
|
|
119
|
+
export declare function assessReadiness(dimensions: readonly ReadinessDimensionInput[], options?: BlockerDetectionOptions): ReadinessAssessment;
|
|
120
|
+
/**
|
|
121
|
+
* Assess blocker 7 — "no way to prove the claimed user-visible outcome" — from
|
|
122
|
+
* the execution/proof dimension, expressed in PRD #1738's claim→evidence shape.
|
|
123
|
+
* The outcome is unprovable (the blocker STANDS) when a claim's
|
|
124
|
+
* `not_established` list is non-empty; it is CLEAR when that list is empty. If
|
|
125
|
+
* #1738's contract is unavailable, or a blocker-7 finding is not expressed in
|
|
126
|
+
* its shape, the assessment is `SKIP` with a stated reason rather than a guess.
|
|
127
|
+
* @param dimension - The execution/proof dimension record, if present
|
|
128
|
+
* @param options - Blocker-detection options (claim→evidence availability)
|
|
129
|
+
* @returns The provability sub-assessment
|
|
130
|
+
*/
|
|
131
|
+
export declare function assessProvabilityBlocker(dimension: ReadinessDimensionInput | undefined, options?: BlockerDetectionOptions): ProvabilityAssessment;
|
|
132
|
+
/**
|
|
133
|
+
* Detect the standing ship blockers from dimension findings — a pure mapping
|
|
134
|
+
* from findings to the closed set B1..B7. Blockers 1-6 stand on an evidencing
|
|
135
|
+
* finding that names them; blocker 7 stands only via {@link assessProvabilityBlocker}
|
|
136
|
+
* over PRD #1738's evidence shape. Emitted in fixed id order for a deterministic
|
|
137
|
+
* report; a blocker with no evidencing finding is absent.
|
|
138
|
+
* @param dimensions - Per-dimension records (from the report or a fixture)
|
|
139
|
+
* @param options - Blocker-detection options (claim→evidence availability)
|
|
140
|
+
* @returns The standing blockers, ordered by id
|
|
141
|
+
*/
|
|
142
|
+
export declare function detectShipBlockers(dimensions: readonly ReadinessDimensionInput[], options?: BlockerDetectionOptions): readonly DetectedBlocker[];
|
|
143
|
+
/**
|
|
144
|
+
* Produce the narrowed claim: the required, operator-language statement of what
|
|
145
|
+
* the repository is NOT ready for AND what it IS ready for whenever a blocker
|
|
146
|
+
* stands. Returns `null` when no blocker stands (a `READY`/`READY_WITH_WARNINGS`
|
|
147
|
+
* report carries no narrowed claim). Governed by the `factory-model` rule —
|
|
148
|
+
* written outward for a non-technical operator at the gate.
|
|
149
|
+
* @param blockers - Standing ship blockers
|
|
150
|
+
* @returns The narrowed claim, or null when nothing stands
|
|
151
|
+
*/
|
|
152
|
+
export declare function computeNarrowedClaim(blockers: readonly DetectedBlocker[]): string | null;
|
|
153
|
+
export {};
|
|
154
|
+
//# sourceMappingURL=doctor-readiness-blockers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-blockers.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-blockers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The seven-blocker gate and narrowed claim for repository readiness (RRR-5,
|
|
3
|
+
* #1857).
|
|
4
|
+
*
|
|
5
|
+
* RRR-3 (#1855) produces the eight readiness dimensions and persists the report;
|
|
6
|
+
* this module turns their findings into the thing that decides what the
|
|
7
|
+
* repository may be *claimed* to be. It is a pure mapping from dimension
|
|
8
|
+
* findings to the closed set of seven ship blockers (B1..B7 per the
|
|
9
|
+
* `readiness-rubric` rule, RRR-1 #1853), a verdict flip to `NOT_READY` when any
|
|
10
|
+
* blocker stands, and the required operator-language narrowed claim. Blocker 7
|
|
11
|
+
* ("no way to prove the claimed user-visible outcome") is expressed in PRD
|
|
12
|
+
* #1738's claim→evidence shape (`claim-evidence-mapping`) so there is exactly
|
|
13
|
+
* one definition of what establishes a claim across both PRDs.
|
|
14
|
+
*
|
|
15
|
+
* It gates a *claim*, not a *process*: per intake decision O1 nothing here
|
|
16
|
+
* hard-blocks. The verdict ladder is the shipped one — no new enum (F2). The
|
|
17
|
+
* blocker set is closed in v1 and extended only by editing this module and the
|
|
18
|
+
* rule (intake decision O4).
|
|
19
|
+
* @module cli/doctor-readiness-blockers
|
|
20
|
+
*/
|
|
21
|
+
/** Dimension ids owned by one or more blockers (readiness-rubric table). */
|
|
22
|
+
const DIMENSION_CONTEXT_ROUTING = "context-routing";
|
|
23
|
+
const DIMENSION_DOMAIN_OWNERSHIP = "domain-ownership";
|
|
24
|
+
const DIMENSION_EXECUTION_PROOF = "execution-proof";
|
|
25
|
+
const DIMENSION_FEEDBACK_GUARDRAILS = "feedback-guardrails";
|
|
26
|
+
const DIMENSION_DEPENDENCIES_SUPPLY_CHAIN = "dependencies-supply-chain";
|
|
27
|
+
const DIMENSION_DELIVERY_AUTHORITY = "delivery-authority";
|
|
28
|
+
/**
|
|
29
|
+
* The closed v1 set of seven ship blockers (readiness-rubric, RRR-1 #1853).
|
|
30
|
+
* Extending it is a deliberate rule edit, never a configuration surface (intake
|
|
31
|
+
* decision O4). A standing blocker makes the claim "an unattended fleet may run
|
|
32
|
+
* here" false and flips the verdict to `NOT_READY`.
|
|
33
|
+
*/
|
|
34
|
+
export const SHIP_BLOCKER_IDS = [
|
|
35
|
+
"B1",
|
|
36
|
+
"B2",
|
|
37
|
+
"B3",
|
|
38
|
+
"B4",
|
|
39
|
+
"B5",
|
|
40
|
+
"B6",
|
|
41
|
+
"B7",
|
|
42
|
+
];
|
|
43
|
+
/** The blocker-7 id, named once so the provability path stays legible. */
|
|
44
|
+
const PROVABILITY_BLOCKER_ID = "B7";
|
|
45
|
+
/**
|
|
46
|
+
* The reason blocker 7 renders `SKIP` when PRD #1738's claim→evidence contract
|
|
47
|
+
* is unavailable — a stated reason, never a guessed provability verdict
|
|
48
|
+
* (RRR-5 technical approach point 4).
|
|
49
|
+
*/
|
|
50
|
+
export const CLAIM_EVIDENCE_UNAVAILABLE_REASON = "claim-evidence contract not yet available";
|
|
51
|
+
/**
|
|
52
|
+
* Blocker → owning-dimension mapping, cited verbatim from the `readiness-rubric`
|
|
53
|
+
* seven-blocker table (RRR-1). This module consumes that table; it does not
|
|
54
|
+
* redefine the vocabulary.
|
|
55
|
+
*/
|
|
56
|
+
const SHIP_BLOCKERS = {
|
|
57
|
+
B1: {
|
|
58
|
+
label: "A realistic path causes silent data loss",
|
|
59
|
+
owning_dimensions: [DIMENSION_DOMAIN_OWNERSHIP],
|
|
60
|
+
},
|
|
61
|
+
B2: {
|
|
62
|
+
label: "A release path bypasses the validated artifact",
|
|
63
|
+
owning_dimensions: [DIMENSION_DELIVERY_AUTHORITY],
|
|
64
|
+
},
|
|
65
|
+
B3: {
|
|
66
|
+
label: "Credentials carry material unintended authority",
|
|
67
|
+
owning_dimensions: [DIMENSION_DELIVERY_AUTHORITY],
|
|
68
|
+
},
|
|
69
|
+
B4: {
|
|
70
|
+
label: "A consequential operation has no gate and no recovery",
|
|
71
|
+
owning_dimensions: [
|
|
72
|
+
DIMENSION_DOMAIN_OWNERSHIP,
|
|
73
|
+
DIMENSION_FEEDBACK_GUARDRAILS,
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
B5: {
|
|
77
|
+
label: "An owned compatibility or security surface has no confidence model",
|
|
78
|
+
owning_dimensions: [DIMENSION_DEPENDENCIES_SUPPLY_CHAIN],
|
|
79
|
+
},
|
|
80
|
+
B6: {
|
|
81
|
+
label: "Documentation overstates enforced guarantees",
|
|
82
|
+
owning_dimensions: [DIMENSION_CONTEXT_ROUTING],
|
|
83
|
+
},
|
|
84
|
+
B7: {
|
|
85
|
+
label: "There is no way to prove the claimed user-visible outcome",
|
|
86
|
+
owning_dimensions: [DIMENSION_EXECUTION_PROOF],
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Gate the unattended-operation claim on the seven ship blockers and, when any
|
|
91
|
+
* stands, emit the narrowed claim. This is RRR-5's pure core: it consumes the
|
|
92
|
+
* dimension findings, maps them to blockers (blocker 7 via PRD #1738's evidence
|
|
93
|
+
* shape), flips the verdict to `NOT_READY` when a blocker stands, and produces
|
|
94
|
+
* the operator-language narrowed claim. It gates a *claim*, not a *process* —
|
|
95
|
+
* intake decision O1 keeps every Lisa surface warn-only.
|
|
96
|
+
* @param dimensions - Per-dimension records (from the report or a fixture)
|
|
97
|
+
* @param options - Blocker-detection options (claim→evidence availability)
|
|
98
|
+
* @returns The verdict, standing blockers, and narrowed claim
|
|
99
|
+
*/
|
|
100
|
+
export function assessReadiness(dimensions, options = {}) {
|
|
101
|
+
const blockers = detectShipBlockers(dimensions, options);
|
|
102
|
+
return {
|
|
103
|
+
verdict: computeReadinessVerdict(dimensions, blockers),
|
|
104
|
+
blockers,
|
|
105
|
+
narrowed_claim: computeNarrowedClaim(blockers),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Reduce dimensions and standing blockers to the shipped verdict ladder. A
|
|
110
|
+
* standing ship blocker is the only thing that yields `NOT_READY` (the rubric's
|
|
111
|
+
* definition); otherwise any non-clean dimension is `READY_WITH_WARNINGS`, and
|
|
112
|
+
* an all-clean report is `READY`. No new verdict enum (F2).
|
|
113
|
+
* @param dimensions - Per-dimension records
|
|
114
|
+
* @param blockers - Standing ship blockers
|
|
115
|
+
* @returns Overall verdict
|
|
116
|
+
*/
|
|
117
|
+
function computeReadinessVerdict(dimensions, blockers) {
|
|
118
|
+
if (blockers.length > 0) {
|
|
119
|
+
return "NOT_READY";
|
|
120
|
+
}
|
|
121
|
+
if (dimensions.some(dimension => dimension.status === "FAIL" || dimension.status === "WARN")) {
|
|
122
|
+
return "READY_WITH_WARNINGS";
|
|
123
|
+
}
|
|
124
|
+
return "READY";
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Coerce an untyped persisted finding into the {@link ReadinessFinding} shape.
|
|
128
|
+
* @param value - A raw finding value from JSON
|
|
129
|
+
* @returns The finding as a typed object, or an empty object when not one
|
|
130
|
+
*/
|
|
131
|
+
function coerceFinding(value) {
|
|
132
|
+
return typeof value === "object" && value !== null
|
|
133
|
+
? value
|
|
134
|
+
: {};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Whether a finding carries the evidence a blocker needs to be emitted. A
|
|
138
|
+
* finding that names a blocker but carries no evidence is malformed and must be
|
|
139
|
+
* dropped, never emitted bare.
|
|
140
|
+
* @param finding - The finding to check
|
|
141
|
+
* @returns True when the finding has non-empty evidence text
|
|
142
|
+
*/
|
|
143
|
+
function hasEvidence(finding) {
|
|
144
|
+
return typeof finding.evidence === "string" && finding.evidence.trim() !== "";
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Locate the first finding across all dimensions that evidences a blocker id.
|
|
148
|
+
* @param dimensions - Per-dimension records
|
|
149
|
+
* @param blockerId - The ship blocker id to evidence
|
|
150
|
+
* @returns The evidencing finding and its dimension id, or undefined
|
|
151
|
+
*/
|
|
152
|
+
function locateEvidencingFinding(dimensions, blockerId) {
|
|
153
|
+
for (const dimension of dimensions) {
|
|
154
|
+
for (const raw of dimension.findings) {
|
|
155
|
+
const finding = coerceFinding(raw);
|
|
156
|
+
if (finding.blocker === blockerId && hasEvidence(finding)) {
|
|
157
|
+
return { dimensionId: dimension.id, finding };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Assess blocker 7 — "no way to prove the claimed user-visible outcome" — from
|
|
165
|
+
* the execution/proof dimension, expressed in PRD #1738's claim→evidence shape.
|
|
166
|
+
* The outcome is unprovable (the blocker STANDS) when a claim's
|
|
167
|
+
* `not_established` list is non-empty; it is CLEAR when that list is empty. If
|
|
168
|
+
* #1738's contract is unavailable, or a blocker-7 finding is not expressed in
|
|
169
|
+
* its shape, the assessment is `SKIP` with a stated reason rather than a guess.
|
|
170
|
+
* @param dimension - The execution/proof dimension record, if present
|
|
171
|
+
* @param options - Blocker-detection options (claim→evidence availability)
|
|
172
|
+
* @returns The provability sub-assessment
|
|
173
|
+
*/
|
|
174
|
+
export function assessProvabilityBlocker(dimension, options = {}) {
|
|
175
|
+
if (options.claimEvidenceContractAvailable === false) {
|
|
176
|
+
return { status: "SKIP", reason: CLAIM_EVIDENCE_UNAVAILABLE_REASON };
|
|
177
|
+
}
|
|
178
|
+
const finding = (dimension?.findings ?? [])
|
|
179
|
+
.map(coerceFinding)
|
|
180
|
+
.find(candidate => candidate.blocker === PROVABILITY_BLOCKER_ID);
|
|
181
|
+
if (!finding) {
|
|
182
|
+
return { status: "CLEAR" };
|
|
183
|
+
}
|
|
184
|
+
const claimEvidence = finding.claim_evidence;
|
|
185
|
+
if (!claimEvidence || !Array.isArray(claimEvidence.required_evidence_kinds)) {
|
|
186
|
+
// A blocker-7 finding not expressed in #1738's shape cannot be assessed:
|
|
187
|
+
// degrade to SKIP with a stated reason instead of inventing a stand-in.
|
|
188
|
+
return { status: "SKIP", reason: CLAIM_EVIDENCE_UNAVAILABLE_REASON };
|
|
189
|
+
}
|
|
190
|
+
const notEstablished = Array.isArray(claimEvidence.not_established)
|
|
191
|
+
? claimEvidence.not_established
|
|
192
|
+
: [];
|
|
193
|
+
return notEstablished.length > 0
|
|
194
|
+
? { status: "STANDS", finding }
|
|
195
|
+
: { status: "CLEAR" };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Build a {@link DetectedBlocker} from an evidencing finding, stamping the
|
|
199
|
+
* cited label and owning dimensions from the readiness-rubric table.
|
|
200
|
+
* @param id - The ship blocker id
|
|
201
|
+
* @param dimensionId - The dimension the evidencing finding was found in
|
|
202
|
+
* @param finding - The evidencing finding
|
|
203
|
+
* @returns The detected blocker
|
|
204
|
+
*/
|
|
205
|
+
function buildDetectedBlocker(id, dimensionId, finding) {
|
|
206
|
+
const spec = SHIP_BLOCKERS[id];
|
|
207
|
+
return {
|
|
208
|
+
id,
|
|
209
|
+
label: spec.label,
|
|
210
|
+
owning_dimensions: spec.owning_dimensions,
|
|
211
|
+
dimension_id: dimensionId,
|
|
212
|
+
invariant_violated: typeof finding.invariant_violated === "string"
|
|
213
|
+
? finding.invariant_violated
|
|
214
|
+
: "",
|
|
215
|
+
evidence: typeof finding.evidence === "string" ? finding.evidence : "",
|
|
216
|
+
...(finding.claim_evidence
|
|
217
|
+
? { claim_evidence: finding.claim_evidence }
|
|
218
|
+
: {}),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Resolve the standing blocker (if any) for a single blocker id. Blocker 7
|
|
223
|
+
* routes through {@link assessProvabilityBlocker}; blockers 1-6 stand on the
|
|
224
|
+
* first evidencing finding that names them.
|
|
225
|
+
* @param dimensions - Per-dimension records
|
|
226
|
+
* @param id - The ship blocker id to resolve
|
|
227
|
+
* @param options - Blocker-detection options (claim→evidence availability)
|
|
228
|
+
* @returns A single-element array with the standing blocker, or an empty array
|
|
229
|
+
*/
|
|
230
|
+
function resolveBlocker(dimensions, id, options) {
|
|
231
|
+
if (id === PROVABILITY_BLOCKER_ID) {
|
|
232
|
+
const provability = assessProvabilityBlocker(dimensions.find(dimension => dimension.id === DIMENSION_EXECUTION_PROOF), options);
|
|
233
|
+
return provability.status === "STANDS" && provability.finding
|
|
234
|
+
? [
|
|
235
|
+
buildDetectedBlocker(id, DIMENSION_EXECUTION_PROOF, provability.finding),
|
|
236
|
+
]
|
|
237
|
+
: [];
|
|
238
|
+
}
|
|
239
|
+
const located = locateEvidencingFinding(dimensions, id);
|
|
240
|
+
return located
|
|
241
|
+
? [buildDetectedBlocker(id, located.dimensionId, located.finding)]
|
|
242
|
+
: [];
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Detect the standing ship blockers from dimension findings — a pure mapping
|
|
246
|
+
* from findings to the closed set B1..B7. Blockers 1-6 stand on an evidencing
|
|
247
|
+
* finding that names them; blocker 7 stands only via {@link assessProvabilityBlocker}
|
|
248
|
+
* over PRD #1738's evidence shape. Emitted in fixed id order for a deterministic
|
|
249
|
+
* report; a blocker with no evidencing finding is absent.
|
|
250
|
+
* @param dimensions - Per-dimension records (from the report or a fixture)
|
|
251
|
+
* @param options - Blocker-detection options (claim→evidence availability)
|
|
252
|
+
* @returns The standing blockers, ordered by id
|
|
253
|
+
*/
|
|
254
|
+
export function detectShipBlockers(dimensions, options = {}) {
|
|
255
|
+
return SHIP_BLOCKER_IDS.flatMap(id => resolveBlocker(dimensions, id, options));
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Produce the narrowed claim: the required, operator-language statement of what
|
|
259
|
+
* the repository is NOT ready for AND what it IS ready for whenever a blocker
|
|
260
|
+
* stands. Returns `null` when no blocker stands (a `READY`/`READY_WITH_WARNINGS`
|
|
261
|
+
* report carries no narrowed claim). Governed by the `factory-model` rule —
|
|
262
|
+
* written outward for a non-technical operator at the gate.
|
|
263
|
+
* @param blockers - Standing ship blockers
|
|
264
|
+
* @returns The narrowed claim, or null when nothing stands
|
|
265
|
+
*/
|
|
266
|
+
export function computeNarrowedClaim(blockers) {
|
|
267
|
+
if (blockers.length === 0) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
const list = blockers
|
|
271
|
+
.map(blocker => `${blocker.id} — ${blocker.label}`)
|
|
272
|
+
.join("; ");
|
|
273
|
+
const standing = blockers.length === 1
|
|
274
|
+
? "1 ship blocker stands"
|
|
275
|
+
: `${blockers.length} ship blockers stand`;
|
|
276
|
+
return (`This repository is NOT ready for unattended fleet operation because ` +
|
|
277
|
+
`${standing}: ${list}. It IS ready for supervised, single-ticket agent ` +
|
|
278
|
+
`work with a human reviewing and approving each change before it ships.`);
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=doctor-readiness-blockers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-blockers.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-blockers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { WorkerJourneyEvidence } from "./doctor-worker-journey.js";
|
|
2
|
+
/** The per-environment mutation policy from `.lisa.config.json` `exploration`. */
|
|
3
|
+
export type MutationPolicy = "forbidden" | "read-only" | "full";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the per-environment mutation policy from an already-parsed config,
|
|
6
|
+
* mirroring `lisa-use-the-product`'s gate: default `read-only`; a production-
|
|
7
|
+
* named env defaults to `forbidden` and may only be raised to `full` with a
|
|
8
|
+
* written `prodMutationAck`.
|
|
9
|
+
* @param config - Parsed `.lisa.config.json` contents
|
|
10
|
+
* @returns The resolved mutation policy
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveMutationPolicy(config: unknown): MutationPolicy;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the mutation policy for a path by reading `.lisa.config.json`.
|
|
15
|
+
* @param targetPath - Project path to read config from
|
|
16
|
+
* @returns The resolved mutation policy (read-only when unreadable)
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveMutationPolicyForPath(targetPath: string): Promise<MutationPolicy>;
|
|
19
|
+
/**
|
|
20
|
+
* Determine whether recorded qualification evidence is fresh enough to reuse:
|
|
21
|
+
* the epoch is in sync (no drift), evidence is present, and it is newer than the
|
|
22
|
+
* current artifact head. When the artifact head cannot be resolved, freshness
|
|
23
|
+
* falls back to "no drift and evidence present" (the shipped #1742 notion).
|
|
24
|
+
* @param evidence - Resolved worker journey evidence
|
|
25
|
+
* @param targetPath - Project path (for git artifact-head resolution)
|
|
26
|
+
* @param artifactHeadOverride - Injected artifact head (skips git resolution)
|
|
27
|
+
* @returns True when the evidence may be reused without a new journey
|
|
28
|
+
*/
|
|
29
|
+
export declare function isQualificationEvidenceFresh(evidence: WorkerJourneyEvidence, targetPath: string, artifactHeadOverride?: Date | null): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Narrow unknown JSON values to plain records.
|
|
32
|
+
* @param value - Value to inspect
|
|
33
|
+
* @returns True for plain object records
|
|
34
|
+
*/
|
|
35
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
36
|
+
//# sourceMappingURL=doctor-readiness-journey-freshness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-journey-freshness.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-journey-freshness.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAIxE,kFAAkF;AAClF,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC;AAEhE;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAsBrE;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,CAChD,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,cAAc,CAAC,CAYzB;AAED;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,qBAAqB,EAC/B,UAAU,EAAE,MAAM,EAClB,oBAAoB,CAAC,EAAE,IAAI,GAAG,IAAI,GACjC,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Freshness and mutation-policy helpers for the readiness journey wiring
|
|
3
|
+
* (RRR-6, #1858).
|
|
4
|
+
*
|
|
5
|
+
* Split out of `doctor-readiness-journey.ts` for file-size hygiene: this module
|
|
6
|
+
* owns the two gates that decide *whether* a representative journey runs — the
|
|
7
|
+
* per-environment mutation policy read from `.lisa.config.json` (mirroring
|
|
8
|
+
* `lisa-use-the-product`'s gate, which readiness never overrides) and the
|
|
9
|
+
* freshness contract that decides when recorded qualification evidence may be
|
|
10
|
+
* reused instead of re-running a journey (same worker signature, evidence newer
|
|
11
|
+
* than the current artifact head).
|
|
12
|
+
* @module cli/doctor-readiness-journey-freshness
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import { readFile, stat } from "node:fs/promises";
|
|
16
|
+
import * as path from "node:path";
|
|
17
|
+
import { promisify } from "node:util";
|
|
18
|
+
import { execFile } from "node:child_process";
|
|
19
|
+
const execFileAsync = promisify(execFile);
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the per-environment mutation policy from an already-parsed config,
|
|
22
|
+
* mirroring `lisa-use-the-product`'s gate: default `read-only`; a production-
|
|
23
|
+
* named env defaults to `forbidden` and may only be raised to `full` with a
|
|
24
|
+
* written `prodMutationAck`.
|
|
25
|
+
* @param config - Parsed `.lisa.config.json` contents
|
|
26
|
+
* @returns The resolved mutation policy
|
|
27
|
+
*/
|
|
28
|
+
export function resolveMutationPolicy(config) {
|
|
29
|
+
const exploration = isRecord(config) ? config.exploration : undefined;
|
|
30
|
+
if (!isRecord(exploration)) {
|
|
31
|
+
return "read-only";
|
|
32
|
+
}
|
|
33
|
+
const environments = isRecord(exploration.environments)
|
|
34
|
+
? exploration.environments
|
|
35
|
+
: {};
|
|
36
|
+
const envName = typeof exploration.default === "string" ? exploration.default : "default";
|
|
37
|
+
const envConfig = isRecord(environments[envName])
|
|
38
|
+
? environments[envName]
|
|
39
|
+
: undefined;
|
|
40
|
+
const level = envConfig && typeof envConfig.mutation === "string"
|
|
41
|
+
? envConfig.mutation
|
|
42
|
+
: undefined;
|
|
43
|
+
const ack = envConfig && typeof envConfig.prodMutationAck === "string"
|
|
44
|
+
? envConfig.prodMutationAck.trim() !== ""
|
|
45
|
+
: false;
|
|
46
|
+
return normalizeMutationLevel(envName, level, ack);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the mutation policy for a path by reading `.lisa.config.json`.
|
|
50
|
+
* @param targetPath - Project path to read config from
|
|
51
|
+
* @returns The resolved mutation policy (read-only when unreadable)
|
|
52
|
+
*/
|
|
53
|
+
export async function resolveMutationPolicyForPath(targetPath) {
|
|
54
|
+
const configPath = path.join(targetPath, ".lisa.config.json");
|
|
55
|
+
if (!existsSync(configPath)) {
|
|
56
|
+
return "read-only";
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
return resolveMutationPolicy(JSON.parse(await readFile(configPath, "utf8")));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return "read-only";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Determine whether recorded qualification evidence is fresh enough to reuse:
|
|
67
|
+
* the epoch is in sync (no drift), evidence is present, and it is newer than the
|
|
68
|
+
* current artifact head. When the artifact head cannot be resolved, freshness
|
|
69
|
+
* falls back to "no drift and evidence present" (the shipped #1742 notion).
|
|
70
|
+
* @param evidence - Resolved worker journey evidence
|
|
71
|
+
* @param targetPath - Project path (for git artifact-head resolution)
|
|
72
|
+
* @param artifactHeadOverride - Injected artifact head (skips git resolution)
|
|
73
|
+
* @returns True when the evidence may be reused without a new journey
|
|
74
|
+
*/
|
|
75
|
+
export async function isQualificationEvidenceFresh(evidence, targetPath, artifactHeadOverride) {
|
|
76
|
+
if (evidence.evidence === null || evidence.drift.length > 0) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const artifactHead = artifactHeadOverride ?? (await resolveArtifactHead(targetPath));
|
|
80
|
+
if (artifactHead === null) {
|
|
81
|
+
// Cannot compare to the artifact head: fall back to the #1742 notion.
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
const evidenceTime = await resolveEvidenceTimestamp(evidence);
|
|
85
|
+
return (evidenceTime !== null && evidenceTime.getTime() >= artifactHead.getTime());
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Narrow unknown JSON values to plain records.
|
|
89
|
+
* @param value - Value to inspect
|
|
90
|
+
* @returns True for plain object records
|
|
91
|
+
*/
|
|
92
|
+
export function isRecord(value) {
|
|
93
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Normalize a raw mutation level for a resolved environment, applying the
|
|
97
|
+
* production carve-out.
|
|
98
|
+
* @param envName - Resolved environment name
|
|
99
|
+
* @param level - Raw mutation level from config
|
|
100
|
+
* @param hasAck - Whether a non-empty prodMutationAck is present
|
|
101
|
+
* @returns The normalized mutation policy
|
|
102
|
+
*/
|
|
103
|
+
function normalizeMutationLevel(envName, level, hasAck) {
|
|
104
|
+
const isProduction = /^prod(uction)?$/iu.test(envName);
|
|
105
|
+
if (isProduction) {
|
|
106
|
+
if (level === "full" && hasAck) {
|
|
107
|
+
return "full";
|
|
108
|
+
}
|
|
109
|
+
return "forbidden";
|
|
110
|
+
}
|
|
111
|
+
if (level === "forbidden" || level === "full" || level === "read-only") {
|
|
112
|
+
return level;
|
|
113
|
+
}
|
|
114
|
+
return "read-only";
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Resolve the artifact-head timestamp from the git HEAD commit time.
|
|
118
|
+
* @param targetPath - Project path to inspect
|
|
119
|
+
* @returns The HEAD commit time, or null when it cannot be resolved
|
|
120
|
+
*/
|
|
121
|
+
async function resolveArtifactHead(targetPath) {
|
|
122
|
+
try {
|
|
123
|
+
const { stdout } = await execFileAsync("git", ["-C", targetPath, "log", "-1", "--format=%cI"], { encoding: "utf8" });
|
|
124
|
+
const parsed = new Date(stdout.trim());
|
|
125
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Resolve a timestamp for recorded qualification evidence: an explicit
|
|
133
|
+
* `qualifiedAt`/`recordedAt` on the worker entry, else the mtime of
|
|
134
|
+
* `.lisa/worker-config.json`.
|
|
135
|
+
* @param evidence - Resolved worker journey evidence
|
|
136
|
+
* @returns The evidence timestamp, or null when it cannot be resolved
|
|
137
|
+
*/
|
|
138
|
+
async function resolveEvidenceTimestamp(evidence) {
|
|
139
|
+
const explicit = readTimestampField(evidence.matched);
|
|
140
|
+
if (explicit !== null) {
|
|
141
|
+
return explicit;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
return (await stat(evidence.recordPath)).mtime;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Read an explicit `qualifiedAt`/`recordedAt` timestamp from a worker entry.
|
|
152
|
+
* @param matched - The matched worker entry, if any
|
|
153
|
+
* @returns The parsed timestamp, or null when absent/unparseable
|
|
154
|
+
*/
|
|
155
|
+
function readTimestampField(matched) {
|
|
156
|
+
if (!isRecord(matched)) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const raw = matched.qualifiedAt ?? matched.recordedAt;
|
|
160
|
+
if (typeof raw !== "string") {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const parsed = new Date(raw);
|
|
164
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=doctor-readiness-journey-freshness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-journey-freshness.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-journey-freshness.ts"],"names":[],"mappings":"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"}
|