@codyswann/lisa 3.52.0 → 3.54.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.
Files changed (120) hide show
  1. package/dist/cli/doctor-declared-contexts.d.ts +32 -0
  2. package/dist/cli/doctor-declared-contexts.d.ts.map +1 -0
  3. package/dist/cli/doctor-declared-contexts.js +144 -0
  4. package/dist/cli/doctor-declared-contexts.js.map +1 -0
  5. package/dist/cli/doctor.d.ts.map +1 -1
  6. package/dist/cli/doctor.js +6 -0
  7. package/dist/cli/doctor.js.map +1 -1
  8. package/dist/cli/gate-report-drift-section.d.ts +8 -0
  9. package/dist/cli/gate-report-drift-section.d.ts.map +1 -0
  10. package/dist/cli/gate-report-drift-section.js +68 -0
  11. package/dist/cli/gate-report-drift-section.js.map +1 -0
  12. package/dist/cli/gate-report-fragment.d.ts.map +1 -1
  13. package/dist/cli/gate-report-fragment.js +7 -1
  14. package/dist/cli/gate-report-fragment.js.map +1 -1
  15. package/dist/cli/gate-report-joins.d.ts +45 -0
  16. package/dist/cli/gate-report-joins.d.ts.map +1 -1
  17. package/dist/cli/gate-report-joins.js +56 -0
  18. package/dist/cli/gate-report-joins.js.map +1 -1
  19. package/dist/cli/gate-report-registry.d.ts +9 -0
  20. package/dist/cli/gate-report-registry.d.ts.map +1 -1
  21. package/dist/cli/gate-report-registry.js +15 -0
  22. package/dist/cli/gate-report-registry.js.map +1 -1
  23. package/dist/cli/gate-report-sections.d.ts +6 -0
  24. package/dist/cli/gate-report-sections.d.ts.map +1 -1
  25. package/dist/cli/gate-report-sections.js +59 -0
  26. package/dist/cli/gate-report-sections.js.map +1 -1
  27. package/dist/cli/gate-report-style.d.ts +1 -1
  28. package/dist/cli/gate-report-style.d.ts.map +1 -1
  29. package/dist/cli/gate-report-style.js +3 -0
  30. package/dist/cli/gate-report-style.js.map +1 -1
  31. package/dist/cli/gate-report-templates.d.ts +22 -0
  32. package/dist/cli/gate-report-templates.d.ts.map +1 -0
  33. package/dist/cli/gate-report-templates.js +110 -0
  34. package/dist/cli/gate-report-templates.js.map +1 -0
  35. package/dist/cli/gate-report-types.d.ts +19 -5
  36. package/dist/cli/gate-report-types.d.ts.map +1 -1
  37. package/dist/cli/gate-report-types.js.map +1 -1
  38. package/dist/cli/gate-report.d.ts +3 -0
  39. package/dist/cli/gate-report.d.ts.map +1 -1
  40. package/dist/cli/gate-report.js +26 -2
  41. package/dist/cli/gate-report.js.map +1 -1
  42. package/dist/core/gate-declaration-drift.d.ts +190 -0
  43. package/dist/core/gate-declaration-drift.d.ts.map +1 -0
  44. package/dist/core/gate-declaration-drift.js +300 -0
  45. package/dist/core/gate-declaration-drift.js.map +1 -0
  46. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  47. package/dist/core/upstream-evidence-manifest.js +13 -1
  48. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  49. package/dist/health/declared-checks-inspection.d.ts +48 -0
  50. package/dist/health/declared-checks-inspection.d.ts.map +1 -0
  51. package/dist/health/declared-checks-inspection.js +154 -0
  52. package/dist/health/declared-checks-inspection.js.map +1 -0
  53. package/dist/health/deterministic-inputs.d.ts +40 -0
  54. package/dist/health/deterministic-inputs.d.ts.map +1 -0
  55. package/dist/health/deterministic-inputs.js +71 -0
  56. package/dist/health/deterministic-inputs.js.map +1 -0
  57. package/dist/health/deterministic.d.ts.map +1 -1
  58. package/dist/health/deterministic.js +10 -45
  59. package/dist/health/deterministic.js.map +1 -1
  60. package/dist/health/ruleset-inspection.d.ts +27 -0
  61. package/dist/health/ruleset-inspection.d.ts.map +1 -1
  62. package/dist/health/ruleset-inspection.js +70 -0
  63. package/dist/health/ruleset-inspection.js.map +1 -1
  64. package/package.json +1 -1
  65. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa/.codex-plugin/skills/lisa-doctor/SKILL.md +33 -1
  68. package/plugins/lisa/skills/lisa-doctor/SKILL.md +33 -1
  69. package/plugins/lisa-agy/plugin.json +1 -1
  70. package/plugins/lisa-agy/skills/lisa-doctor/SKILL.md +33 -1
  71. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  73. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  74. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-copilot/skills/lisa-doctor/SKILL.md +33 -1
  78. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-cursor/skills/lisa-doctor/SKILL.md +33 -1
  80. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  82. package/plugins/lisa-expo-agy/plugin.json +1 -1
  83. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  87. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  88. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  92. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  93. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  96. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  97. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  98. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  100. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  101. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  102. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  103. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  104. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  105. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  106. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  107. package/plugins/lisa-rails-agy/plugin.json +1 -1
  108. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  109. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  110. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  111. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  112. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  113. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  114. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  115. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  116. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  117. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  118. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  119. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  120. package/plugins/src/base/skills/lisa-doctor/SKILL.md +33 -1
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Hold the gates declaration against the ruleset that enforces it.
3
+ *
4
+ * Three surfaces answer "what must pass before this merges" — the project's
5
+ * `gates` declarations, the shipped ruleset template, and the live GitHub
6
+ * ruleset — and until this module existed no comparator joined the first to
7
+ * either of the others. `contextsFor()` derived contexts from declarations,
8
+ * `lisa health` compared template against live, and the two halves never met,
9
+ * so a declaration and the protection enforcing it could disagree indefinitely
10
+ * with every check green.
11
+ *
12
+ * Two properties are load-bearing, and both are structural rather than
13
+ * conventional:
14
+ *
15
+ * 1. **`off` and undeclared are different findings.** `off` is a decision that
16
+ * a property is not proved here, so protection requiring it is a live
17
+ * contradiction. Undeclared is silence — the registry still has gates whose
18
+ * jobs run with no declaration at all, so silence must never be read as
19
+ * "not required", and must never justify removing live protection.
20
+ * 2. **Agreement is not proof.** A `matched` verdict means the declaration and
21
+ * the ruleset name the same required context. It says nothing about whether
22
+ * that context proves anything: one required context in this repository
23
+ * ships a skip step printing "This job going green does NOT mean any
24
+ * ast-grep rule has test coverage", and a required review context has gone
25
+ * green carrying "Review skipped". A drift report that could not tell
26
+ * "agreed and proved" from "agreed and unproved" would itself be a control
27
+ * reporting more than it measured, so the word this module uses is
28
+ * `matched` — the two surfaces agree — and never `enforced` or `proved`.
29
+ * 3. **No remedy in this module can say "remove the context".** Third-party
30
+ * contexts are enforced by construction and declared by nobody; a
31
+ * comparator whose vocabulary contained a removal would eventually propose
32
+ * deleting one. The `DriftRemedy` union simply has no such member, so the
33
+ * guarantee holds for every caller rather than for the careful ones.
34
+ * @module core/gate-declaration-drift
35
+ */
36
+ /**
37
+ * What the settings file says about one gate at one moment.
38
+ *
39
+ * `off` and `not-declared` are deliberately separate. Collapsing them is what
40
+ * let a declaration govern nothing: the CI façade read both as
41
+ * `configured=false` and ran its built-in fallback, so `off` could not turn a
42
+ * job off.
43
+ */
44
+ export type DeclarationState = "required" | "optional" | "off" | "not-declared";
45
+ /** Which enforcing surface a comparison was made against. */
46
+ export type DriftSurface = "ruleset-templates" | "live-ruleset";
47
+ /**
48
+ * One context's verdict, in the vocabulary an operator can act on.
49
+ *
50
+ * Six members rather than a matched/unmatched pair, because the four unmatched
51
+ * cases need four different actions and one of them is not a defect at all.
52
+ */
53
+ export type DriftVerdict =
54
+ /** Declared `required`, and the enforcing surface requires it. */
55
+ "matched"
56
+ /** Declared `required`; nothing on the enforcing surface requires it. */
57
+ | "declared-not-enforced"
58
+ /** Enforced, while the declaration says `optional`. */
59
+ | "enforced-declared-optional"
60
+ /** Enforced, while the declaration says `off` — a live contradiction. */
61
+ | "enforced-declared-off"
62
+ /** Enforced, and a registry gate produces it, but nothing declares it. */
63
+ | "enforced-undeclared"
64
+ /** Enforced, and no registry gate produces it — a third-party check. */
65
+ | "enforced-not-lisa-owned";
66
+ /**
67
+ * What to do about one verdict.
68
+ *
69
+ * Deliberately closed, and deliberately without a removal. See the module note.
70
+ */
71
+ export type DriftRemedy = "none" | "declare-the-gate" | "enforce-the-context" | "resolve-the-contradiction" | "decide-which-surface-wins";
72
+ /** One required status context, and where the requirement was read from. */
73
+ export interface EnforcedContext {
74
+ /** The context string, exactly as the ruleset spells it. */
75
+ readonly context: string;
76
+ /** The ruleset requiring it. */
77
+ readonly ruleset: string;
78
+ /**
79
+ * Where the requirement was read. A package-relative template path or a
80
+ * settings-file key — never an absolute path, which differs per machine and
81
+ * would break the byte-identical property the report is built on.
82
+ */
83
+ readonly source: string;
84
+ }
85
+ /** The gate a context belongs to, and what the settings file says about it. */
86
+ export interface ContextOwner {
87
+ /** Registry gate id. */
88
+ readonly gateId: string;
89
+ /** The declaration at the merge moment. */
90
+ readonly declaration: DeclarationState;
91
+ /** Whether the registry permits declaring this gate at the merge moment. */
92
+ readonly legalAtMerge: boolean;
93
+ }
94
+ /** One context, its verdict, and the evidence behind it. */
95
+ export interface DeclarationDriftEntry {
96
+ /** The context string. */
97
+ readonly context: string;
98
+ /** The verdict. */
99
+ readonly verdict: DriftVerdict;
100
+ /** The action this verdict calls for. Never a removal. */
101
+ readonly remedy: DriftRemedy;
102
+ /** The registry gate producing this context, when one does. */
103
+ readonly gateId: string | null;
104
+ /** What the settings file says, or null when no gate owns the context. */
105
+ readonly declaration: DeclarationState | null;
106
+ /** The rulesets requiring it, sorted. Empty when nothing enforces it. */
107
+ readonly rulesets: readonly string[];
108
+ /** Where the requirement was read from, sorted. */
109
+ readonly sources: readonly string[];
110
+ /** One operator-readable sentence. */
111
+ readonly detail: string;
112
+ }
113
+ /** The whole comparison against one enforcing surface. */
114
+ export interface DeclarationDriftReport {
115
+ /** Which surface the declarations were held against. */
116
+ readonly surface: DriftSurface;
117
+ /** One entry per context, sorted by context. */
118
+ readonly entries: readonly DeclarationDriftEntry[];
119
+ /** How many entries carry each verdict. Every key is present. */
120
+ readonly counts: Readonly<Record<DriftVerdict, number>>;
121
+ /** Entries whose verdict is a contradiction rather than a gap. */
122
+ readonly contradictions: number;
123
+ /** Entries whose verdict is a gap the declaration surface could close. */
124
+ readonly gaps: number;
125
+ }
126
+ /** The slice of the shipped registry this comparison reads. */
127
+ export interface MergeContextRegistry {
128
+ readonly REGISTRY: Readonly<Record<string, {
129
+ readonly label: string;
130
+ readonly moments: readonly string[];
131
+ }>>;
132
+ readonly resolveMoment: (options: {
133
+ gates: Record<string, unknown>;
134
+ moment: string;
135
+ includeOff?: boolean;
136
+ }) => readonly {
137
+ readonly id: string;
138
+ readonly level: string;
139
+ readonly mode: string;
140
+ readonly awaits: string | null;
141
+ }[];
142
+ readonly momentFamily: (moment: string) => string;
143
+ }
144
+ /** The moment a branch ruleset guards. */
145
+ export declare const MERGE_MOMENT = "pull-request";
146
+ /**
147
+ * Map every context a registry gate can produce to that gate.
148
+ *
149
+ * Built from the whole registry rather than from the declared gates, which is
150
+ * the difference between "protection requires a context whose gate nobody
151
+ * declared" and "protection requires a context Lisa knows nothing about". Those
152
+ * are different findings with different remedies, and a map built only from
153
+ * declarations could not tell them apart.
154
+ * @param options - Inputs
155
+ * @param options.registry - The shipped registry
156
+ * @param options.gates - The project's gates block
157
+ * @param options.workflowName - The workflow whose name prefixes a context
158
+ * @returns Context string to owning gate
159
+ */
160
+ export declare function contextOwners(options: {
161
+ registry: MergeContextRegistry;
162
+ gates: Record<string, unknown>;
163
+ workflowName: string;
164
+ }): ReadonlyMap<string, ContextOwner>;
165
+ /**
166
+ * The contexts a `required` declaration promises protection will require.
167
+ * @param owners - Context to owning gate
168
+ * @returns The contexts, sorted
169
+ */
170
+ export declare function declaredRequiredContexts(owners: ReadonlyMap<string, ContextOwner>): readonly string[];
171
+ /**
172
+ * Compare a project's declarations with one enforcing surface.
173
+ *
174
+ * Total and pure — the same inputs always produce the same entries in the same
175
+ * order. Reaching the surface is the caller's job, and a caller that could not
176
+ * reach it must report an unknown rather than call this with an empty list: a
177
+ * comparison against nothing would report every declaration as unenforced,
178
+ * which is a different and false claim.
179
+ * @param options - Inputs
180
+ * @param options.surface - Which surface `enforced` was read from
181
+ * @param options.owners - Context to owning gate
182
+ * @param options.enforced - Contexts the surface requires
183
+ * @returns The comparison
184
+ */
185
+ export declare function classifyDeclarationDrift(options: {
186
+ surface: DriftSurface;
187
+ owners: ReadonlyMap<string, ContextOwner>;
188
+ enforced: readonly EnforcedContext[];
189
+ }): DeclarationDriftReport;
190
+ //# sourceMappingURL=gate-declaration-drift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-declaration-drift.d.ts","sourceRoot":"","sources":["../../src/core/gate-declaration-drift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Hold the gates declaration against the ruleset that enforces it.
3
+ *
4
+ * Three surfaces answer "what must pass before this merges" — the project's
5
+ * `gates` declarations, the shipped ruleset template, and the live GitHub
6
+ * ruleset — and until this module existed no comparator joined the first to
7
+ * either of the others. `contextsFor()` derived contexts from declarations,
8
+ * `lisa health` compared template against live, and the two halves never met,
9
+ * so a declaration and the protection enforcing it could disagree indefinitely
10
+ * with every check green.
11
+ *
12
+ * Two properties are load-bearing, and both are structural rather than
13
+ * conventional:
14
+ *
15
+ * 1. **`off` and undeclared are different findings.** `off` is a decision that
16
+ * a property is not proved here, so protection requiring it is a live
17
+ * contradiction. Undeclared is silence — the registry still has gates whose
18
+ * jobs run with no declaration at all, so silence must never be read as
19
+ * "not required", and must never justify removing live protection.
20
+ * 2. **Agreement is not proof.** A `matched` verdict means the declaration and
21
+ * the ruleset name the same required context. It says nothing about whether
22
+ * that context proves anything: one required context in this repository
23
+ * ships a skip step printing "This job going green does NOT mean any
24
+ * ast-grep rule has test coverage", and a required review context has gone
25
+ * green carrying "Review skipped". A drift report that could not tell
26
+ * "agreed and proved" from "agreed and unproved" would itself be a control
27
+ * reporting more than it measured, so the word this module uses is
28
+ * `matched` — the two surfaces agree — and never `enforced` or `proved`.
29
+ * 3. **No remedy in this module can say "remove the context".** Third-party
30
+ * contexts are enforced by construction and declared by nobody; a
31
+ * comparator whose vocabulary contained a removal would eventually propose
32
+ * deleting one. The `DriftRemedy` union simply has no such member, so the
33
+ * guarantee holds for every caller rather than for the careful ones.
34
+ * @module core/gate-declaration-drift
35
+ */
36
+ /** The moment a branch ruleset guards. */
37
+ export const MERGE_MOMENT = "pull-request";
38
+ /** Every verdict, named once so no two mentions can drift apart. */
39
+ const MATCHED = "matched";
40
+ const DECLARED_NOT_ENFORCED = "declared-not-enforced";
41
+ const ENFORCED_DECLARED_OPTIONAL = "enforced-declared-optional";
42
+ const ENFORCED_DECLARED_OFF = "enforced-declared-off";
43
+ const ENFORCED_UNDECLARED = "enforced-undeclared";
44
+ const ENFORCED_NOT_LISA_OWNED = "enforced-not-lisa-owned";
45
+ /** Verdicts where the two surfaces state opposite things. */
46
+ const CONTRADICTIONS = new Set([
47
+ DECLARED_NOT_ENFORCED,
48
+ ENFORCED_DECLARED_OFF,
49
+ ]);
50
+ /** Verdicts where one surface is silent rather than contrary. */
51
+ const GAPS = new Set([
52
+ ENFORCED_DECLARED_OPTIONAL,
53
+ ENFORCED_UNDECLARED,
54
+ ]);
55
+ /** The remedy each verdict calls for. */
56
+ const REMEDIES = {
57
+ [MATCHED]: "none",
58
+ [DECLARED_NOT_ENFORCED]: "enforce-the-context",
59
+ [ENFORCED_DECLARED_OPTIONAL]: "decide-which-surface-wins",
60
+ [ENFORCED_DECLARED_OFF]: "resolve-the-contradiction",
61
+ [ENFORCED_UNDECLARED]: "declare-the-gate",
62
+ [ENFORCED_NOT_LISA_OWNED]: "none",
63
+ };
64
+ /** Every verdict, so a count of zero is still a stated zero. */
65
+ const VERDICTS = Object.keys(REMEDIES);
66
+ /** How the enforcing surface is named in a sentence. */
67
+ const SURFACE_NAMES = {
68
+ "ruleset-templates": "the shipped ruleset template",
69
+ "live-ruleset": "the live branch-protection ruleset",
70
+ };
71
+ /**
72
+ * Sort strings the same way everywhere, so two runs emit the same bytes.
73
+ * @param values - Caller-owned strings
74
+ * @returns A sorted copy
75
+ */
76
+ function sorted(values) {
77
+ return [...values].sort((left, right) => left.localeCompare(right));
78
+ }
79
+ /**
80
+ * The declaration state one resolved level names.
81
+ *
82
+ * Anything that is not one of the three levels is `not-declared`, because an
83
+ * unknown level is a typo rather than a claim.
84
+ * @param level - The resolved level
85
+ * @returns The declaration state
86
+ */
87
+ function asDeclaration(level) {
88
+ return level === "required" || level === "optional" || level === "off"
89
+ ? level
90
+ : "not-declared";
91
+ }
92
+ /**
93
+ * Map every context a registry gate can produce to that gate.
94
+ *
95
+ * Built from the whole registry rather than from the declared gates, which is
96
+ * the difference between "protection requires a context whose gate nobody
97
+ * declared" and "protection requires a context Lisa knows nothing about". Those
98
+ * are different findings with different remedies, and a map built only from
99
+ * declarations could not tell them apart.
100
+ * @param options - Inputs
101
+ * @param options.registry - The shipped registry
102
+ * @param options.gates - The project's gates block
103
+ * @param options.workflowName - The workflow whose name prefixes a context
104
+ * @returns Context string to owning gate
105
+ */
106
+ export function contextOwners(options) {
107
+ const { registry, gates, workflowName } = options;
108
+ const resolved = resolveMergeMoment(registry, gates);
109
+ const family = registry.momentFamily(MERGE_MOMENT);
110
+ const owners = Object.entries(registry.REGISTRY).map(([gateId, definition]) => {
111
+ const hit = resolved.get(gateId);
112
+ return [
113
+ `${workflowName} / ${definition.label}`,
114
+ {
115
+ gateId,
116
+ declaration: asDeclaration(hit?.level),
117
+ legalAtMerge: definition.moments.includes(family),
118
+ },
119
+ ];
120
+ });
121
+ const awaited = [...resolved.values()].flatMap(hit => hit.mode === "await" && hit.awaits !== null
122
+ ? [
123
+ [
124
+ hit.awaits,
125
+ {
126
+ gateId: hit.id,
127
+ declaration: asDeclaration(hit.level),
128
+ legalAtMerge: registry.REGISTRY[hit.id]?.moments.includes(family) === true,
129
+ },
130
+ ],
131
+ ]
132
+ : []);
133
+ return new Map([...owners, ...awaited]);
134
+ }
135
+ /**
136
+ * Resolve the merge moment, treating a refusal as "nothing resolved".
137
+ *
138
+ * A refusal is never swallowed by the caller: `readTemplateEnforcement` and the
139
+ * health check both report the declaration problems separately. What must not
140
+ * happen here is a throw that turns a comparison into no comparison at all.
141
+ * @param registry - The shipped registry
142
+ * @param gates - The project's gates block
143
+ * @returns Resolved gates keyed by id
144
+ */
145
+ function resolveMergeMoment(registry, gates) {
146
+ try {
147
+ return new Map(registry
148
+ .resolveMoment({ gates, moment: MERGE_MOMENT, includeOff: true })
149
+ .map(entry => [entry.id, { ...entry }]));
150
+ }
151
+ catch {
152
+ return new Map();
153
+ }
154
+ }
155
+ /**
156
+ * The contexts a `required` declaration promises protection will require.
157
+ * @param owners - Context to owning gate
158
+ * @returns The contexts, sorted
159
+ */
160
+ export function declaredRequiredContexts(owners) {
161
+ return sorted([...owners.entries()]
162
+ .filter(([, owner]) => owner.declaration === "required")
163
+ .map(([context]) => context));
164
+ }
165
+ /**
166
+ * The verdict for one enforced context.
167
+ * @param owner - The gate producing it, when one does
168
+ * @returns The verdict
169
+ */
170
+ function verdictForEnforced(owner) {
171
+ if (owner === undefined)
172
+ return ENFORCED_NOT_LISA_OWNED;
173
+ if (owner.declaration === "required")
174
+ return MATCHED;
175
+ if (owner.declaration === "optional")
176
+ return ENFORCED_DECLARED_OPTIONAL;
177
+ if (owner.declaration === "off")
178
+ return ENFORCED_DECLARED_OFF;
179
+ return ENFORCED_UNDECLARED;
180
+ }
181
+ /**
182
+ * The sentence one verdict is explained with.
183
+ * @param options - Inputs
184
+ * @param options.verdict - The verdict
185
+ * @param options.surface - The enforcing surface
186
+ * @param options.gateId - The owning gate, when there is one
187
+ * @param options.sources - Where the requirement was read from
188
+ * @returns One operator-readable sentence
189
+ */
190
+ // eslint-disable-next-line sonarjs/cognitive-complexity -- one branch per verdict keeps the wording auditable
191
+ function detailFor(options) {
192
+ const { verdict, gateId, sources } = options;
193
+ const surface = SURFACE_NAMES[options.surface];
194
+ const where = sources.length === 0 ? "" : ` (${sources.join(", ")})`;
195
+ if (verdict === MATCHED) {
196
+ return `Declared required, and ${surface} requires it${where}. The two surfaces agree; that is not evidence the check proves its property.`;
197
+ }
198
+ if (verdict === DECLARED_NOT_ENFORCED) {
199
+ return `The settings file declares "${String(gateId)}" required at ${MERGE_MOMENT}, but ${surface} does not require this context, so the declaration blocks nothing.`;
200
+ }
201
+ if (verdict === ENFORCED_DECLARED_OPTIONAL) {
202
+ return `${surface} requires this context${where}, while the settings file declares "${String(gateId)}" optional at ${MERGE_MOMENT}. Two surfaces, two answers — name which one wins.`;
203
+ }
204
+ if (verdict === ENFORCED_DECLARED_OFF) {
205
+ return `The settings file declares "${String(gateId)}" off at ${MERGE_MOMENT} — an explicit decision not to prove it here — yet ${surface} requires this context${where}. That is a contradiction, not a gap.`;
206
+ }
207
+ if (verdict === ENFORCED_UNDECLARED) {
208
+ return `${surface} requires this context${where}, and it is produced by the gate "${String(gateId)}", which the settings file never declares at any moment. Undeclared is silence, not permission to stop requiring it.`;
209
+ }
210
+ return `${surface} requires this context${where}, and no gate in Lisa's registry produces it — it comes from a third-party app or from a job this project's own CI defines. Matching is on the exact context string, never on a job name that merely resembles it: a third-party app status and a Lisa job with a similar name are different things, and treating them as one produces a false drift report, or worse a false clean one. Reported so it can be told apart from a Lisa gate that fell out of the settings file, never so it can be removed.`;
211
+ }
212
+ /**
213
+ * Group enforced contexts, keeping every ruleset and source that named one.
214
+ * @param enforced - Enforced contexts, possibly repeating a context
215
+ * @returns Context to its rulesets and sources
216
+ */
217
+ function groupEnforced(enforced) {
218
+ return enforced.reduce((grouped, entry) => {
219
+ const existing = grouped.get(entry.context) ?? {
220
+ rulesets: [],
221
+ sources: [],
222
+ };
223
+ return new Map(grouped).set(entry.context, {
224
+ rulesets: [...existing.rulesets, entry.ruleset],
225
+ sources: [...existing.sources, entry.source],
226
+ });
227
+ }, new Map());
228
+ }
229
+ /**
230
+ * Compare a project's declarations with one enforcing surface.
231
+ *
232
+ * Total and pure — the same inputs always produce the same entries in the same
233
+ * order. Reaching the surface is the caller's job, and a caller that could not
234
+ * reach it must report an unknown rather than call this with an empty list: a
235
+ * comparison against nothing would report every declaration as unenforced,
236
+ * which is a different and false claim.
237
+ * @param options - Inputs
238
+ * @param options.surface - Which surface `enforced` was read from
239
+ * @param options.owners - Context to owning gate
240
+ * @param options.enforced - Contexts the surface requires
241
+ * @returns The comparison
242
+ */
243
+ export function classifyDeclarationDrift(options) {
244
+ const { surface, owners, enforced } = options;
245
+ const grouped = groupEnforced(enforced);
246
+ const enforcedEntries = sorted(grouped.keys()).map((context) => {
247
+ const owner = owners.get(context);
248
+ const verdict = verdictForEnforced(owner);
249
+ const found = grouped.get(context);
250
+ const sources = sorted(new Set(found?.sources ?? []));
251
+ return {
252
+ context,
253
+ verdict,
254
+ remedy: REMEDIES[verdict],
255
+ gateId: owner?.gateId ?? null,
256
+ declaration: owner?.declaration ?? null,
257
+ rulesets: sorted(new Set(found?.rulesets ?? [])),
258
+ sources,
259
+ detail: detailFor({
260
+ verdict,
261
+ surface,
262
+ gateId: owner?.gateId ?? null,
263
+ sources,
264
+ }),
265
+ };
266
+ });
267
+ const unenforced = declaredRequiredContexts(owners)
268
+ .filter(context => !grouped.has(context))
269
+ .map((context) => {
270
+ const gateId = owners.get(context)?.gateId ?? null;
271
+ return {
272
+ context,
273
+ verdict: DECLARED_NOT_ENFORCED,
274
+ remedy: REMEDIES[DECLARED_NOT_ENFORCED],
275
+ gateId,
276
+ declaration: "required",
277
+ rulesets: [],
278
+ sources: [],
279
+ detail: detailFor({
280
+ verdict: DECLARED_NOT_ENFORCED,
281
+ surface,
282
+ gateId,
283
+ sources: [],
284
+ }),
285
+ };
286
+ });
287
+ const entries = [...enforcedEntries, ...unenforced].sort((left, right) => left.context.localeCompare(right.context));
288
+ return {
289
+ surface,
290
+ entries,
291
+ counts: Object.fromEntries(VERDICTS.map(verdict => [
292
+ verdict,
293
+ entries.filter(entry => entry.verdict === verdict).length,
294
+ ])),
295
+ contradictions: entries.filter(entry => CONTRADICTIONS.has(entry.verdict))
296
+ .length,
297
+ gaps: entries.filter(entry => GAPS.has(entry.verdict)).length,
298
+ };
299
+ }
300
+ //# sourceMappingURL=gate-declaration-drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-declaration-drift.js","sourceRoot":"","sources":["../../src/core/gate-declaration-drift.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"upstream-evidence-manifest.d.ts","sourceRoot":"","sources":["../../src/core/upstream-evidence-manifest.ts"],"names":[],"mappings":"AACA,iFAAiF;AACjF,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAg3EpE,CAAC;AAEL,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAk5OjE,CAAC;AAEL,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAk6I/D,CAAC"}
1
+ {"version":3,"file":"upstream-evidence-manifest.d.ts","sourceRoot":"","sources":["../../src/core/upstream-evidence-manifest.ts"],"names":[],"mappings":"AACA,iFAAiF;AACjF,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAg3EpE,CAAC;AAEL,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CA85OjE,CAAC;AAEL,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAk6I/D,CAAC"}
@@ -521,7 +521,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
521
521
  "plugins/src/base/skills/lisa-detect-tooling/SKILL.md": "6ea2b1404d5c27f8a5bec8c90ad35ed0124789b70c091869455f538a2a9debbe",
522
522
  "plugins/src/base/skills/lisa-detect-tooling/scripts/commands.mjs": "e28bd61fdde4a336b56ae3395423026943a5816015719d31d04f0d5a0ab50eec",
523
523
  "plugins/src/base/skills/lisa-detect-tooling/scripts/detect-tooling.mjs": "d9419814fc04c935bd7e320e85b1977c9bfc9275d9ea5fb557002ad438ee7925",
524
- "plugins/src/base/skills/lisa-doctor/SKILL.md": "a16ded88a648852c02f7ee3e30ef97afb644384f2ea2e977c3e4a288600278de",
524
+ "plugins/src/base/skills/lisa-doctor/SKILL.md": "83fd779c341108729a926bc2680d54f0b69044137840b1d80d660243a7f74ba5",
525
525
  "plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md": "e27849a2567081bce5ea3aa31f7cc5868f884a59c343c685b900ac7aa707666a",
526
526
  "plugins/src/base/skills/lisa-epic-triage/SKILL.md": "d02760411249bddbd396f283191fe3e82bb7b95bf9393a19a7025dc5a57c3ab7",
527
527
  "plugins/src/base/skills/lisa-evaluation-suite/SKILL.md": "96b5c2091ccd22a565935a7b0b917f67998881b81055ce3e4d518319472eac8b",
@@ -7110,6 +7110,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7110
7110
  "src/cli/cross-pollinate-nudge.ts": true,
7111
7111
  "src/cli/doctor-apply-failure.ts": true,
7112
7112
  "src/cli/doctor-apply-freshness.ts": true,
7113
+ "src/cli/doctor-declared-contexts.ts": true,
7113
7114
  "src/cli/doctor-gate-recommendation.ts": true,
7114
7115
  "src/cli/doctor-hook-copy-parity.ts": true,
7115
7116
  "src/cli/doctor-kane.ts": true,
@@ -7174,6 +7175,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7174
7175
  "src/cli/gate-report-cells.ts": true,
7175
7176
  "src/cli/gate-report-config.ts": true,
7176
7177
  "src/cli/gate-report-contexts.ts": true,
7178
+ "src/cli/gate-report-drift-section.ts": true,
7177
7179
  "src/cli/gate-report-executors.ts": true,
7178
7180
  "src/cli/gate-report-facade.ts": true,
7179
7181
  "src/cli/gate-report-fragment.ts": true,
@@ -7188,6 +7190,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7188
7190
  "src/cli/gate-report-skip-jobs.ts": true,
7189
7191
  "src/cli/gate-report-style.ts": true,
7190
7192
  "src/cli/gate-report-summary.ts": true,
7193
+ "src/cli/gate-report-templates.ts": true,
7191
7194
  "src/cli/gate-report-types.ts": true,
7192
7195
  "src/cli/gate-report-upstream.ts": true,
7193
7196
  "src/cli/gate-report.ts": true,
@@ -7300,6 +7303,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7300
7303
  "src/core/config.ts": true,
7301
7304
  "src/core/downstream-names.ts": true,
7302
7305
  "src/core/downstream-references.ts": true,
7306
+ "src/core/gate-declaration-drift.ts": true,
7303
7307
  "src/core/git-service.ts": true,
7304
7308
  "src/core/guard-capabilities.ts": true,
7305
7309
  "src/core/hook-copy-parity.ts": true,
@@ -7361,6 +7365,8 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7361
7365
  "src/health/consumer.ts": true,
7362
7366
  "src/health/contract.ts": true,
7363
7367
  "src/health/deadline.ts": true,
7368
+ "src/health/declared-checks-inspection.ts": true,
7369
+ "src/health/deterministic-inputs.ts": true,
7364
7370
  "src/health/deterministic.ts": true,
7365
7371
  "src/health/drift-tickets.ts": true,
7366
7372
  "src/health/evaluation-protocol.ts": true,
@@ -7660,6 +7666,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7660
7666
  "tests/unit/cli/check-learnings-budget-cmd.test.ts": true,
7661
7667
  "tests/unit/cli/doctor-apply-failure.test.ts": true,
7662
7668
  "tests/unit/cli/doctor-apply-freshness.test.ts": true,
7669
+ "tests/unit/cli/doctor-declared-contexts.test.ts": true,
7663
7670
  "tests/unit/cli/doctor-gate-recommendation.test.ts": true,
7664
7671
  "tests/unit/cli/doctor-hook-copy-parity.test.ts": true,
7665
7672
  "tests/unit/cli/doctor-kane.test.ts": true,
@@ -7715,10 +7722,13 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7715
7722
  "tests/unit/cli/file-upstream-contract.test.ts": true,
7716
7723
  "tests/unit/cli/gate-commands.test.ts": true,
7717
7724
  "tests/unit/cli/gate-report-attribution.test.ts": true,
7725
+ "tests/unit/cli/gate-report-declaration-drift.test.ts": true,
7718
7726
  "tests/unit/cli/gate-report-executors.test.ts": true,
7719
7727
  "tests/unit/cli/gate-report-fixtures.ts": true,
7728
+ "tests/unit/cli/gate-report-preview-escaping.test.ts": true,
7720
7729
  "tests/unit/cli/gate-report-preview.test.ts": true,
7721
7730
  "tests/unit/cli/gate-report-ruleset.test.ts": true,
7731
+ "tests/unit/cli/gate-report-skip-jobs-render.test.ts": true,
7722
7732
  "tests/unit/cli/gate-report-states.test.ts": true,
7723
7733
  "tests/unit/cli/gate-report-workflows.ts": true,
7724
7734
  "tests/unit/cli/gate-report.test.ts": true,
@@ -7856,6 +7866,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7856
7866
  "tests/unit/core/bootstrap-environment.test.ts": true,
7857
7867
  "tests/unit/core/fs-extra-namespace-callsites.test.ts": true,
7858
7868
  "tests/unit/core/fs-extra-namespace-members.test.ts": true,
7869
+ "tests/unit/core/gate-declaration-drift.test.ts": true,
7859
7870
  "tests/unit/core/hook-copy-parity.test.ts": true,
7860
7871
  "tests/unit/core/host-rules-parity.test.ts": true,
7861
7872
  "tests/unit/core/host-rules-pointer.test.ts": true,
@@ -7913,6 +7924,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7913
7924
  "tests/unit/health/consumer.test.ts": true,
7914
7925
  "tests/unit/health/contract.test.ts": true,
7915
7926
  "tests/unit/health/deadline.test.ts": true,
7927
+ "tests/unit/health/declared-checks.test.ts": true,
7916
7928
  "tests/unit/health/deterministic-regressions.test.ts": true,
7917
7929
  "tests/unit/health/deterministic.test.ts": true,
7918
7930
  "tests/unit/health/drift-tickets.test.ts": true,