@objectstack/lint 16.0.0 → 17.0.0-rc.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 +5 -2
- package/dist/index.cjs +2925 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +755 -33
- package/dist/index.d.ts +755 -33
- package/dist/index.js +2882 -77
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.d.cts
CHANGED
|
@@ -33,6 +33,16 @@ import { AccessMatrix } from '@objectstack/spec/security';
|
|
|
33
33
|
* renders nothing. Errored (not warned) so this class of authoring mistake —
|
|
34
34
|
* very often an AI emitting a removed shape — fails the build instead of
|
|
35
35
|
* shipping a blank widget past human review.
|
|
36
|
+
* - `dashboard-filter-field-unknown` (#3365) — a dashboard-level filter
|
|
37
|
+
* (`dateRange` or a `globalFilters[]` entry) is wired into EVERY widget's
|
|
38
|
+
* analytics query (#2501), but its EFFECTIVE field (after any `filterBindings`
|
|
39
|
+
* re-target) does not exist on a bound widget's dataset object. The widget's
|
|
40
|
+
* query then references a non-existent column and crashes at render time
|
|
41
|
+
* (`no such column …`) — a build-decidable invariant that previously escaped
|
|
42
|
+
* the static gate and failed only when a user opened the dashboard. A widget
|
|
43
|
+
* opts out with `filterBindings: { <name>: false }` or re-targets to a real
|
|
44
|
+
* field. This is the same field-existence invariant ADR-0032 enforces for
|
|
45
|
+
* CEL formula / sharing-rule references, applied to dashboard filter fields.
|
|
36
46
|
*
|
|
37
47
|
* Advisory rules — severity `warning`, build stays green:
|
|
38
48
|
*
|
|
@@ -68,6 +78,7 @@ declare const CHART_FIELD_UNKNOWN = "chart-field-unknown";
|
|
|
68
78
|
declare const CHART_CONFIG_MISSING = "chart-config-missing";
|
|
69
79
|
declare const TABLE_COUNT_ONLY = "table-count-only";
|
|
70
80
|
declare const MEASURE_AGGREGATE_INCOHERENT = "measure-aggregate-incoherent";
|
|
81
|
+
declare const DASHBOARD_FILTER_FIELD_UNKNOWN = "dashboard-filter-field-unknown";
|
|
71
82
|
type WidgetBindingSeverity = 'error' | 'warning';
|
|
72
83
|
interface WidgetBindingFinding {
|
|
73
84
|
/** `error` = unresolvable binding (broken page); `warning` = advisory. */
|
|
@@ -83,7 +94,7 @@ interface WidgetBindingFinding {
|
|
|
83
94
|
/** How to fix (or deliberately suppress) it. */
|
|
84
95
|
hint: string;
|
|
85
96
|
}
|
|
86
|
-
type AnyRec$
|
|
97
|
+
type AnyRec$t = Record<string, unknown>;
|
|
87
98
|
/**
|
|
88
99
|
* Validate every dashboard widget's dataset binding. Returns the list of
|
|
89
100
|
* findings (empty = clean). Caller decides how to surface them: `error`
|
|
@@ -91,7 +102,7 @@ type AnyRec$g = Record<string, unknown>;
|
|
|
91
102
|
* should fail validate/build; `warning` findings are advisory and must
|
|
92
103
|
* never fail the build on their own.
|
|
93
104
|
*/
|
|
94
|
-
declare function validateWidgetBindings(stack: AnyRec$
|
|
105
|
+
declare function validateWidgetBindings(stack: AnyRec$t): WidgetBindingFinding[];
|
|
95
106
|
|
|
96
107
|
interface ExprIssue {
|
|
97
108
|
where: string;
|
|
@@ -104,12 +115,12 @@ interface ExprIssue {
|
|
|
104
115
|
*/
|
|
105
116
|
severity?: 'error' | 'warning';
|
|
106
117
|
}
|
|
107
|
-
type AnyRec$
|
|
118
|
+
type AnyRec$s = Record<string, unknown>;
|
|
108
119
|
/**
|
|
109
120
|
* Validate every predicate in the stack. Returns the list of issues (empty =
|
|
110
121
|
* clean). Caller decides how to surface / whether to fail the build.
|
|
111
122
|
*/
|
|
112
|
-
declare function validateStackExpressions(stack: AnyRec$
|
|
123
|
+
declare function validateStackExpressions(stack: AnyRec$s): ExprIssue[];
|
|
113
124
|
|
|
114
125
|
type ListViewModeSeverity = 'error' | 'warning';
|
|
115
126
|
interface ListViewModeFinding {
|
|
@@ -123,7 +134,7 @@ interface ListViewModeFinding {
|
|
|
123
134
|
hint: string;
|
|
124
135
|
}
|
|
125
136
|
declare const LIST_VIEW_FILTERS_IN_VIEWS_MODE = "list-view-filters-in-views-mode";
|
|
126
|
-
type AnyRec$
|
|
137
|
+
type AnyRec$r = Record<string, unknown>;
|
|
127
138
|
/**
|
|
128
139
|
* Flag ADR-0047 "views" mode violations on an object's built-in named views or a
|
|
129
140
|
* `defineView` default `list` / named `listViews`: `quickFilters`, or a `tabs`
|
|
@@ -133,7 +144,7 @@ type AnyRec$e = Record<string, unknown>;
|
|
|
133
144
|
*
|
|
134
145
|
* Feed the PRE-parse stack (normalizeStackInput output) — see file header.
|
|
135
146
|
*/
|
|
136
|
-
declare function validateListViewMode(stack: AnyRec$
|
|
147
|
+
declare function validateListViewMode(stack: AnyRec$r): ListViewModeFinding[];
|
|
137
148
|
|
|
138
149
|
type FlowTriggerReadinessSeverity = 'error' | 'warning';
|
|
139
150
|
interface FlowTriggerReadinessFinding {
|
|
@@ -148,12 +159,52 @@ interface FlowTriggerReadinessFinding {
|
|
|
148
159
|
}
|
|
149
160
|
declare const FLOW_TRIGGER_UNKNOWN_OBJECT = "flow-trigger-unknown-object";
|
|
150
161
|
declare const FLOW_DRAFT_STATUS_AMBIGUOUS = "flow-draft-status-ambiguous";
|
|
151
|
-
type AnyRec$
|
|
162
|
+
type AnyRec$q = Record<string, unknown>;
|
|
152
163
|
/**
|
|
153
164
|
* Validate auto-launched flow trigger wiring against the stack definition.
|
|
154
165
|
* Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
155
166
|
*/
|
|
156
|
-
declare function validateFlowTriggerReadiness(stack: AnyRec$
|
|
167
|
+
declare function validateFlowTriggerReadiness(stack: AnyRec$q): FlowTriggerReadinessFinding[];
|
|
168
|
+
|
|
169
|
+
type FlowTemplatePathSeverity = 'error' | 'warning';
|
|
170
|
+
interface FlowTemplatePathFinding {
|
|
171
|
+
severity: FlowTemplatePathSeverity;
|
|
172
|
+
rule: string;
|
|
173
|
+
/** Human-readable location, e.g. `flow "notify_lead" node "notify"`. */
|
|
174
|
+
where: string;
|
|
175
|
+
/** Config path, e.g. `flows[0].nodes[2]`. */
|
|
176
|
+
path: string;
|
|
177
|
+
message: string;
|
|
178
|
+
hint: string;
|
|
179
|
+
}
|
|
180
|
+
declare const FLOW_TEMPLATE_UNKNOWN_FIELD = "flow-template-unknown-field";
|
|
181
|
+
declare const FLOW_TEMPLATE_LOOKUP_TRAVERSAL = "flow-template-lookup-traversal";
|
|
182
|
+
type AnyRec$p = Record<string, unknown>;
|
|
183
|
+
/**
|
|
184
|
+
* Validate `{record.<path>}` template references across every record-change
|
|
185
|
+
* flow. Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
186
|
+
*/
|
|
187
|
+
declare function validateFlowTemplatePaths(stack: AnyRec$p): FlowTemplatePathFinding[];
|
|
188
|
+
|
|
189
|
+
type ReadonlyFlowWriteSeverity = 'error' | 'warning';
|
|
190
|
+
interface ReadonlyFlowWriteFinding {
|
|
191
|
+
severity: ReadonlyFlowWriteSeverity;
|
|
192
|
+
rule: string;
|
|
193
|
+
/** Human-readable location, e.g. `flow "approve_deal" › node "Mark approved"`. */
|
|
194
|
+
where: string;
|
|
195
|
+
/** Config path, e.g. `flows[0].nodes[3].config.fields.approval_status`. */
|
|
196
|
+
path: string;
|
|
197
|
+
message: string;
|
|
198
|
+
hint: string;
|
|
199
|
+
}
|
|
200
|
+
declare const FLOW_UPDATE_READONLY_FIELD = "flow-update-readonly-field";
|
|
201
|
+
declare const FLOW_UPDATE_READONLY_WHEN_FIELD = "flow-update-readonly-when-field";
|
|
202
|
+
type AnyRec$o = Record<string, unknown>;
|
|
203
|
+
/**
|
|
204
|
+
* Validate flow `update_record` writes against target-object readonly
|
|
205
|
+
* declarations. Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
206
|
+
*/
|
|
207
|
+
declare function validateReadonlyFlowWrites(stack: AnyRec$o): ReadonlyFlowWriteFinding[];
|
|
157
208
|
|
|
158
209
|
type ViewContainerSeverity = 'error' | 'warning';
|
|
159
210
|
interface ViewContainerFinding {
|
|
@@ -190,14 +241,14 @@ declare const STYLE_CLASSNAME_TAILWIND = "style-classname-tailwind";
|
|
|
190
241
|
declare const STYLE_RESPONSIVE_NO_BASE = "style-responsive-no-base";
|
|
191
242
|
declare const STYLE_UNKNOWN_CSS_PROPERTY = "style-unknown-css-property";
|
|
192
243
|
declare const STYLE_UNKNOWN_TOKEN = "style-unknown-token";
|
|
193
|
-
type AnyRec$
|
|
244
|
+
type AnyRec$n = Record<string, unknown>;
|
|
194
245
|
/**
|
|
195
246
|
* Validate every page's component tree for SDUI styling correctness (ADR-0065).
|
|
196
247
|
* Returns findings (empty = clean). `error` findings describe styles that are
|
|
197
248
|
* silently dropped and should fail validate/build; `warning` findings are
|
|
198
249
|
* advisory (typos, drift, footguns).
|
|
199
250
|
*/
|
|
200
|
-
declare function validateResponsiveStyles(stack: AnyRec$
|
|
251
|
+
declare function validateResponsiveStyles(stack: AnyRec$n): StyleFinding[];
|
|
201
252
|
|
|
202
253
|
type JsxPageSeverity = 'error' | 'warning';
|
|
203
254
|
interface JsxPageFinding {
|
|
@@ -210,8 +261,8 @@ interface JsxPageFinding {
|
|
|
210
261
|
message: string;
|
|
211
262
|
hint: string;
|
|
212
263
|
}
|
|
213
|
-
type AnyRec$
|
|
214
|
-
declare function validateJsxPages(stack: AnyRec$
|
|
264
|
+
type AnyRec$m = Record<string, unknown>;
|
|
265
|
+
declare function validateJsxPages(stack: AnyRec$m, opts?: {
|
|
215
266
|
manifest?: Manifest;
|
|
216
267
|
}): JsxPageFinding[];
|
|
217
268
|
|
|
@@ -224,8 +275,8 @@ interface ReactPageFinding {
|
|
|
224
275
|
message: string;
|
|
225
276
|
hint: string;
|
|
226
277
|
}
|
|
227
|
-
type AnyRec$
|
|
228
|
-
declare function validateReactPages(stack: AnyRec$
|
|
278
|
+
type AnyRec$l = Record<string, unknown>;
|
|
279
|
+
declare function validateReactPages(stack: AnyRec$l): ReactPageFinding[];
|
|
229
280
|
|
|
230
281
|
type ReactPropSeverity = 'error' | 'warning';
|
|
231
282
|
interface ReactPropFinding {
|
|
@@ -236,8 +287,11 @@ interface ReactPropFinding {
|
|
|
236
287
|
message: string;
|
|
237
288
|
hint: string;
|
|
238
289
|
}
|
|
239
|
-
type AnyRec$
|
|
240
|
-
declare
|
|
290
|
+
type AnyRec$k = Record<string, unknown>;
|
|
291
|
+
declare const REACT_CHART_FIELD_UNKNOWN = "react-chart-field-unknown";
|
|
292
|
+
declare const REACT_CHART_AGGREGATE_INVALID = "react-chart-aggregate-invalid";
|
|
293
|
+
declare const REACT_CHART_AXIS_UNKNOWN = "react-chart-axis-unknown";
|
|
294
|
+
declare function validateReactPageProps(stack: AnyRec$k): ReactPropFinding[];
|
|
241
295
|
|
|
242
296
|
type SourceStyleSeverity = 'error' | 'warning';
|
|
243
297
|
interface SourceStyleFinding {
|
|
@@ -249,8 +303,8 @@ interface SourceStyleFinding {
|
|
|
249
303
|
hint: string;
|
|
250
304
|
}
|
|
251
305
|
declare const PAGE_SOURCE_CLASSNAME = "page-source-className-tailwind";
|
|
252
|
-
type AnyRec$
|
|
253
|
-
declare function validatePageSourceStyling(stack: AnyRec$
|
|
306
|
+
type AnyRec$j = Record<string, unknown>;
|
|
307
|
+
declare function validatePageSourceStyling(stack: AnyRec$j): SourceStyleFinding[];
|
|
254
308
|
|
|
255
309
|
/**
|
|
256
310
|
* Build-time record-title diagnostics (ADR-0079).
|
|
@@ -294,14 +348,14 @@ interface RecordTitleFinding {
|
|
|
294
348
|
/** How to fix it. */
|
|
295
349
|
hint: string;
|
|
296
350
|
}
|
|
297
|
-
type AnyRec$
|
|
351
|
+
type AnyRec$i = Record<string, unknown>;
|
|
298
352
|
/**
|
|
299
353
|
* Validate every object's record-title declaration. Returns the list of
|
|
300
354
|
* findings (empty = clean). Both rules are advisory (`warning`): the caller
|
|
301
355
|
* must never fail the build on them alone — auto-provision + the `Record #<id>`
|
|
302
356
|
* floor guarantee a resolvable title at runtime.
|
|
303
357
|
*/
|
|
304
|
-
declare function validateRecordTitle(stack: AnyRec$
|
|
358
|
+
declare function validateRecordTitle(stack: AnyRec$i): RecordTitleFinding[];
|
|
305
359
|
|
|
306
360
|
/**
|
|
307
361
|
* Build-time semantic-role diagnostics (ADR-0085).
|
|
@@ -338,13 +392,13 @@ interface SemanticRoleFinding {
|
|
|
338
392
|
/** How to fix it. */
|
|
339
393
|
hint: string;
|
|
340
394
|
}
|
|
341
|
-
type AnyRec$
|
|
395
|
+
type AnyRec$h = Record<string, unknown>;
|
|
342
396
|
/**
|
|
343
397
|
* Validate every object's semantic-role pointers. Returns the list of
|
|
344
398
|
* findings (empty = clean). Advisory only — the caller must never fail the
|
|
345
399
|
* build on these alone.
|
|
346
400
|
*/
|
|
347
|
-
declare function validateSemanticRoles(stack: AnyRec$
|
|
401
|
+
declare function validateSemanticRoles(stack: AnyRec$h): SemanticRoleFinding[];
|
|
348
402
|
|
|
349
403
|
/**
|
|
350
404
|
* Build-time form-layout diagnostics (#2578).
|
|
@@ -387,12 +441,12 @@ interface FormLayoutFinding {
|
|
|
387
441
|
/** How to fix it. */
|
|
388
442
|
hint: string;
|
|
389
443
|
}
|
|
390
|
-
type AnyRec$
|
|
444
|
+
type AnyRec$g = Record<string, unknown>;
|
|
391
445
|
/**
|
|
392
446
|
* Validate authored form-view layout. Returns findings (empty = clean).
|
|
393
447
|
* Advisory only — the caller must never fail the build on these alone.
|
|
394
448
|
*/
|
|
395
|
-
declare function validateFormLayout(stack: AnyRec$
|
|
449
|
+
declare function validateFormLayout(stack: AnyRec$g): FormLayoutFinding[];
|
|
396
450
|
|
|
397
451
|
/**
|
|
398
452
|
* Build-time conditional-visibility diagnostics (ADR-0089 D3b).
|
|
@@ -454,7 +508,7 @@ interface VisibilityFinding {
|
|
|
454
508
|
/** How to fix it. */
|
|
455
509
|
hint: string;
|
|
456
510
|
}
|
|
457
|
-
type AnyRec$
|
|
511
|
+
type AnyRec$f = Record<string, unknown>;
|
|
458
512
|
/**
|
|
459
513
|
* Validate conditional-visibility keys across authored views and pages.
|
|
460
514
|
*
|
|
@@ -469,7 +523,7 @@ type AnyRec$4 = Record<string, unknown>;
|
|
|
469
523
|
* `*.view.ts` / `*.page.ts` surfaces (so a `data.`-rooted predicate is flagged). The
|
|
470
524
|
* alias-deprecated check is layer-agnostic.
|
|
471
525
|
*/
|
|
472
|
-
declare function validateVisibilityPredicates(stack: AnyRec$
|
|
526
|
+
declare function validateVisibilityPredicates(stack: AnyRec$f, opts?: VisibilityOptions): VisibilityFinding[];
|
|
473
527
|
|
|
474
528
|
declare const CAPABILITY_REFERENCE_UNKNOWN = "capability-reference-unknown";
|
|
475
529
|
type CapabilityRefSeverity = 'error' | 'warning';
|
|
@@ -487,17 +541,22 @@ interface CapabilityRefFinding {
|
|
|
487
541
|
/** How to fix it. */
|
|
488
542
|
hint: string;
|
|
489
543
|
}
|
|
490
|
-
type AnyRec$
|
|
544
|
+
type AnyRec$e = Record<string, unknown>;
|
|
491
545
|
/**
|
|
492
546
|
* Validate every capability reference in a stack. Returns findings (empty =
|
|
493
547
|
* clean). Advisory only — callers must not fail the build on these alone.
|
|
494
548
|
*/
|
|
495
|
-
declare function validateCapabilityReferences(stack: AnyRec$
|
|
549
|
+
declare function validateCapabilityReferences(stack: AnyRec$e): CapabilityRefFinding[];
|
|
496
550
|
|
|
497
551
|
declare const APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER = "approval-approver-not-membership-tier";
|
|
498
552
|
declare const APPROVAL_APPROVER_TYPE_DEPRECATED = "approval-approver-type-deprecated";
|
|
499
553
|
declare const APPROVAL_APPROVER_TYPE_UNKNOWN = "approval-approver-type-unknown";
|
|
500
554
|
declare const APPROVAL_ESCALATION_REASSIGN_NO_TARGET = "approval-escalation-reassign-no-target";
|
|
555
|
+
declare const APPROVAL_APPROVERS_MAY_RESOLVE_EMPTY = "approval-approvers-may-resolve-empty";
|
|
556
|
+
declare const APPROVAL_EXPRESSION_INVALID = "approval-expression-invalid";
|
|
557
|
+
declare const APPROVAL_EXPRESSION_NO_EMPTY_POLICY = "approval-expression-no-empty-policy";
|
|
558
|
+
declare const APPROVAL_DECISION_OUTPUTS_RESERVED = "approval-decision-outputs-reserved";
|
|
559
|
+
declare const APPROVAL_APPROVER_CROSS_ORG_UNSUPPORTED = "approval-approver-cross-org-unsupported";
|
|
501
560
|
type ApprovalApproverSeverity = 'error' | 'warning' | 'info';
|
|
502
561
|
interface ApprovalApproverFinding {
|
|
503
562
|
severity: ApprovalApproverSeverity;
|
|
@@ -512,12 +571,63 @@ interface ApprovalApproverFinding {
|
|
|
512
571
|
/** How to fix it. */
|
|
513
572
|
hint: string;
|
|
514
573
|
}
|
|
515
|
-
type AnyRec$
|
|
574
|
+
type AnyRec$d = Record<string, unknown>;
|
|
516
575
|
/**
|
|
517
576
|
* Validate the approvers of every Approval node in the stack's flows.
|
|
518
577
|
* Returns findings (empty = clean).
|
|
519
578
|
*/
|
|
520
|
-
declare function validateApprovalApprovers(stack: AnyRec$
|
|
579
|
+
declare function validateApprovalApprovers(stack: AnyRec$d): ApprovalApproverFinding[];
|
|
580
|
+
|
|
581
|
+
type SeedReplaySafetySeverity = 'error' | 'warning';
|
|
582
|
+
interface SeedReplaySafetyFinding {
|
|
583
|
+
severity: SeedReplaySafetySeverity;
|
|
584
|
+
rule: string;
|
|
585
|
+
/** Human-readable location, e.g. `seed "showcase_project_membership"`. */
|
|
586
|
+
where: string;
|
|
587
|
+
/** Config path, e.g. `data[12].mode`. */
|
|
588
|
+
path: string;
|
|
589
|
+
message: string;
|
|
590
|
+
hint: string;
|
|
591
|
+
}
|
|
592
|
+
declare const SEED_INSERT_MODE_DUPLICATES_ON_REPLAY = "seed-insert-mode-duplicates-on-replay";
|
|
593
|
+
type AnyRec$c = Record<string, unknown>;
|
|
594
|
+
/**
|
|
595
|
+
* Flag every seed dataset declared with `mode: 'insert'` — the one non-idempotent
|
|
596
|
+
* mode, which duplicates its rows on every replay boot (framework#3434). Returns
|
|
597
|
+
* the findings (empty = clean). The caller decides how to surface them / whether
|
|
598
|
+
* to fail the build; the CLI folds them in as advisory warnings.
|
|
599
|
+
*
|
|
600
|
+
* Reads `stack.data` (the `SeedSchema[]` fixtures). Safe on any shape — a stack
|
|
601
|
+
* with no `data` array yields no findings.
|
|
602
|
+
*/
|
|
603
|
+
declare function validateSeedReplaySafety(stack: AnyRec$c): SeedReplaySafetyFinding[];
|
|
604
|
+
|
|
605
|
+
type SeedStateMachineSeverity = 'warning';
|
|
606
|
+
interface SeedStateMachineFinding {
|
|
607
|
+
severity: SeedStateMachineSeverity;
|
|
608
|
+
rule: string;
|
|
609
|
+
/** Human-readable location, e.g. `seed "showcase_project" ("Legacy Sunset")`. */
|
|
610
|
+
where: string;
|
|
611
|
+
/** Config path, e.g. `data[4].records[3].status`. */
|
|
612
|
+
path: string;
|
|
613
|
+
message: string;
|
|
614
|
+
hint: string;
|
|
615
|
+
}
|
|
616
|
+
declare const SEED_VALUE_OUTSIDE_STATE_MACHINE = "seed-value-outside-state-machine";
|
|
617
|
+
type AnyRec$b = Record<string, unknown>;
|
|
618
|
+
/**
|
|
619
|
+
* Flag every seed record whose `state_machine`-governed field carries a value
|
|
620
|
+
* the machine does not declare (framework#3433 follow-up). Returns the findings
|
|
621
|
+
* (empty = clean). The caller decides how to surface them; the CLI folds them in
|
|
622
|
+
* as advisory warnings.
|
|
623
|
+
*
|
|
624
|
+
* Reads `stack.objects` (for the state-machine rules) and `stack.data` (the
|
|
625
|
+
* `SeedSchema[]` fixtures). Safe on any shape — a stack with no objects or no
|
|
626
|
+
* `data` array yields no findings. A value that is not a plain string (an
|
|
627
|
+
* unresolved `cel` Expression envelope, a number) is skipped: it cannot be
|
|
628
|
+
* statically compared to the declared-state set.
|
|
629
|
+
*/
|
|
630
|
+
declare function validateSeedStateMachine(stack: AnyRec$b): SeedStateMachineFinding[];
|
|
521
631
|
|
|
522
632
|
declare const SECURITY_OWD_UNSET = "security-owd-unset";
|
|
523
633
|
declare const SECURITY_OWD_ALIAS = "security-owd-alias";
|
|
@@ -544,7 +654,7 @@ interface SecurityFinding {
|
|
|
544
654
|
/** How to fix it. */
|
|
545
655
|
hint: string;
|
|
546
656
|
}
|
|
547
|
-
type AnyRec$
|
|
657
|
+
type AnyRec$a = Record<string, unknown>;
|
|
548
658
|
/**
|
|
549
659
|
* Validate the security posture of a stack. Returns findings (empty = clean).
|
|
550
660
|
* `error` findings gate the build in `os compile`; `info` is advisory.
|
|
@@ -552,10 +662,622 @@ type AnyRec$1 = Record<string, unknown>;
|
|
|
552
662
|
* `opts.nowMs` injects the clock for the ADR-0091 authoring-time expiry rule
|
|
553
663
|
* (tests); production callers omit it.
|
|
554
664
|
*/
|
|
555
|
-
declare function validateSecurityPosture(stack: AnyRec$
|
|
665
|
+
declare function validateSecurityPosture(stack: AnyRec$a, opts?: {
|
|
556
666
|
nowMs?: number;
|
|
557
667
|
}): SecurityFinding[];
|
|
558
668
|
|
|
669
|
+
/**
|
|
670
|
+
* [ADR-0105 D6] The two organization-axis red lines, enforced at authoring time.
|
|
671
|
+
*
|
|
672
|
+
* ADR-0105 gives organizations a reporting/grouping dimension
|
|
673
|
+
* (`sys_organization.parent_organization_id`, sibling ordering). That dimension
|
|
674
|
+
* is load-bearing for consolidated reporting — and dangerous, because it LOOKS
|
|
675
|
+
* like a permission hierarchy. Two lines keep it from becoming one:
|
|
676
|
+
*
|
|
677
|
+
* | Rule | Red line |
|
|
678
|
+
* |-----------------------------------------|-----------------------------------|
|
|
679
|
+
* | org-axis-permission-inheritance (error) | D6 ①: no inheritance along the org tree |
|
|
680
|
+
* | org-axis-cross-org-bu-grant (error) | D6 ②: business-unit trees stay org-internal |
|
|
681
|
+
*
|
|
682
|
+
* **① No permission inheritance along the org axis.** Cross-organization
|
|
683
|
+
* visibility comes from membership union (`accessible_org_ids`, ADR-0105 D2) —
|
|
684
|
+
* the engine's own Layer 0 wall — never from walking a parent reference. An RLS
|
|
685
|
+
* policy or sharing rule that reads `parent_organization_id` builds a SECOND
|
|
686
|
+
* permission hierarchy beside the business-unit tree: exactly the dual-hierarchy
|
|
687
|
+
* mistake ADR-0057 D5 retired and ADR-0090 D3 finalized for positions. It also
|
|
688
|
+
* silently outranks the wall it sits behind, since a Layer-1 policy cannot widen
|
|
689
|
+
* Layer 0 (W1) — so the author gets a rule that appears to grant access and
|
|
690
|
+
* does not. Fail at authoring, not in a support ticket.
|
|
691
|
+
*
|
|
692
|
+
* **② Business-unit trees remain org-internal.** `sys_business_unit` is
|
|
693
|
+
* org-scoped and every BU mechanism (`unit_and_subordinates` sharing,
|
|
694
|
+
* `adminScope` delegation, depth scopes) resolves within ONE organization. A
|
|
695
|
+
* business-unit sharing rule on a PLATFORM-GLOBAL object (`tenancy.enabled:
|
|
696
|
+
* false`) has no organization column to scope against, so the grant spans every
|
|
697
|
+
* organization in the database — a cross-org BU grant by construction, and the
|
|
698
|
+
* "cross-org BU mega-tree" the ADR rejected, arrived at by accident.
|
|
699
|
+
*
|
|
700
|
+
* Both are `error`, per ADR-0049 discipline: each mirrors a real enforcement
|
|
701
|
+
* property (the Layer 0 wall's independence; the org-predicated BU resolver),
|
|
702
|
+
* so the lint moves the failure from silent-wrong-answer to author-time fix-it.
|
|
703
|
+
*
|
|
704
|
+
* Pure `(stack) => Finding[]`; accepts the NORMALIZED stack input.
|
|
705
|
+
*/
|
|
706
|
+
declare const ORG_AXIS_PERMISSION_INHERITANCE = "org-axis-permission-inheritance";
|
|
707
|
+
declare const ORG_AXIS_CROSS_ORG_BU_GRANT = "org-axis-cross-org-bu-grant";
|
|
708
|
+
type OrgAxisSeverity = 'error' | 'warning';
|
|
709
|
+
interface OrgAxisFinding {
|
|
710
|
+
severity: OrgAxisSeverity;
|
|
711
|
+
/** Diagnostic rule id (`org-axis-*`). */
|
|
712
|
+
rule: string;
|
|
713
|
+
/** Human-readable location, e.g. `permission set "plant_reader"`. */
|
|
714
|
+
where: string;
|
|
715
|
+
/** Config path, e.g. `permissions[2].rowLevelSecurity[0].using`. */
|
|
716
|
+
path: string;
|
|
717
|
+
/** What is wrong. */
|
|
718
|
+
message: string;
|
|
719
|
+
/** How to fix it. */
|
|
720
|
+
hint: string;
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Lint an ObjectStack config for the ADR-0105 D6 organization-axis red lines.
|
|
724
|
+
*/
|
|
725
|
+
declare function validateOrgAxisRedLines(stack: unknown): OrgAxisFinding[];
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* [ADR-0049 — references] Reference-integrity for dashboard header & widget
|
|
729
|
+
* action targets (issue #3367).
|
|
730
|
+
*
|
|
731
|
+
* ADR-0049 established the "enforce-or-remove" gate for spec *properties*: a
|
|
732
|
+
* declared property the runtime does not honour is a false promise and must be
|
|
733
|
+
* enforced, marked experimental, or removed. This rule applies the SAME honesty
|
|
734
|
+
* principle to *references*. A dashboard header action (or a widget's header
|
|
735
|
+
* action button) names a target — a `script`/`modal` action, or a `url` route —
|
|
736
|
+
* that must actually resolve. A dangling target ships a button that renders and,
|
|
737
|
+
* on click, silently does nothing: a false affordance, exactly the failure
|
|
738
|
+
* ADR-0049 exists to prevent, just for a reference rather than a property.
|
|
739
|
+
*
|
|
740
|
+
* Nothing in the protocol schema can express this: `actionUrl` is a free string,
|
|
741
|
+
* so `{ actionType: 'script', actionUrl: 'export_dashboard_pdf' }` parses and
|
|
742
|
+
* ships even when no such action is defined anywhere in the stack.
|
|
743
|
+
*
|
|
744
|
+
* Surfaces checked:
|
|
745
|
+
* - dashboard `header.actions[]` — each `{ actionType, actionUrl }`
|
|
746
|
+
* - dashboard `widgets[].actionUrl` (+ `actionType`) — the per-widget button
|
|
747
|
+
*
|
|
748
|
+
* Resolution mirrors the objectui runtime dispatch (`DashboardRenderer` +
|
|
749
|
+
* `DashboardView`) so the lint flags exactly what would fail to resolve at
|
|
750
|
+
* runtime:
|
|
751
|
+
*
|
|
752
|
+
* actionType 'script' → `actionUrl` must name a DEFINED action (`stack.actions`
|
|
753
|
+
* or any `object.actions`, by `name`). A script target that names no
|
|
754
|
+
* defined action fails open at runtime ("action not found"). → ERROR.
|
|
755
|
+
*
|
|
756
|
+
* actionType 'modal' → `actionUrl` resolves if it names a defined action, OR
|
|
757
|
+
* matches the runtime `<verb>_<object>` convention the modalHandler
|
|
758
|
+
* implements (create_/new_/add_/edit_/update_ + a defined object), OR is a
|
|
759
|
+
* bare defined object name (the handler falls back to that object's create
|
|
760
|
+
* form). Otherwise → ERROR.
|
|
761
|
+
*
|
|
762
|
+
* actionType 'url' → a relative in-app path. WARN when a recognizable
|
|
763
|
+
* `<collection>/<name>` segment (objects/reports/dashboards/pages/views)
|
|
764
|
+
* names an entity that does not exist in this stack. External URLs
|
|
765
|
+
* (`http(s)://`, `//`), interpolated targets (`${…}`), and opaque routes
|
|
766
|
+
* (no recognized collection segment) are skipped — they cannot be resolved
|
|
767
|
+
* statically and may be host/app/plugin routes. → WARNING.
|
|
768
|
+
*
|
|
769
|
+
* actionType 'flow' | 'api' — not checked: flow targets resolve against the
|
|
770
|
+
* automation engine / other packages, and api targets are opaque endpoints.
|
|
771
|
+
* Out of scope for #3367.
|
|
772
|
+
*
|
|
773
|
+
* Severity split follows the issue's acceptance criteria: an undefined
|
|
774
|
+
* `script`/`modal` target FAILS validation (a genuine dead reference that fails
|
|
775
|
+
* open at runtime as a dead button); an unresolved `url` route is advisory
|
|
776
|
+
* (route resolution is app-context-dependent, and a path may be served by
|
|
777
|
+
* another installed package or a host/console route). External, interpolated,
|
|
778
|
+
* convention, and opaque targets are exempted to keep false positives near zero
|
|
779
|
+
* — the same conservative posture as the sibling `lint-view-refs` and
|
|
780
|
+
* `validate-capability-references` rules.
|
|
781
|
+
*/
|
|
782
|
+
declare const DASHBOARD_ACTION_TARGET_UNDEFINED = "dashboard-action-target-undefined";
|
|
783
|
+
declare const DASHBOARD_ACTION_ROUTE_UNRESOLVED = "dashboard-action-route-unresolved";
|
|
784
|
+
type DashboardActionRefSeverity = 'error' | 'warning';
|
|
785
|
+
interface DashboardActionRefFinding {
|
|
786
|
+
/** `error` for a dangling script/modal action; `warning` for an unresolved url route. */
|
|
787
|
+
severity: DashboardActionRefSeverity;
|
|
788
|
+
/** Diagnostic rule id. */
|
|
789
|
+
rule: string;
|
|
790
|
+
/** Human-readable location, e.g. `dashboard "sales_overview" · header action "Export PDF"`. */
|
|
791
|
+
where: string;
|
|
792
|
+
/** Config path, e.g. `dashboards[2].header.actions[0].actionUrl`. */
|
|
793
|
+
path: string;
|
|
794
|
+
/** What is wrong. */
|
|
795
|
+
message: string;
|
|
796
|
+
/** How to fix it. */
|
|
797
|
+
hint: string;
|
|
798
|
+
}
|
|
799
|
+
type AnyRec$9 = Record<string, unknown>;
|
|
800
|
+
/**
|
|
801
|
+
* Validate every dashboard header / widget action reference in a stack. Returns
|
|
802
|
+
* findings (empty = clean). `script`/`modal` dead targets are errors; `url`
|
|
803
|
+
* unresolved routes are warnings.
|
|
804
|
+
*/
|
|
805
|
+
declare function validateDashboardActionRefs(stack: AnyRec$9): DashboardActionRefFinding[];
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Build-time filter-placeholder diagnostics (issue #3574).
|
|
809
|
+
*
|
|
810
|
+
* Filter values travel as JSON, so a user-scoped or time-scoped slice cannot
|
|
811
|
+
* call code inline — it writes a placeholder that the client resolves just
|
|
812
|
+
* before querying:
|
|
813
|
+
*
|
|
814
|
+
* { owner_id: '{current_user_id}', created_at: { $gte: '{week_start}' } }
|
|
815
|
+
*
|
|
816
|
+
* Exactly two vocabularies resolve inside a filter value: context tokens
|
|
817
|
+
* (`{current_user_id}`, `{current_org_id}` — see `context-tokens.zod.ts`) and
|
|
818
|
+
* date macros (`{today}`, `{30_days_ago}` — see `date-macros.zod.ts`).
|
|
819
|
+
* Anything else is passed to the data engine **verbatim**, matches no row, and
|
|
820
|
+
* the surface renders an empty result.
|
|
821
|
+
*
|
|
822
|
+
* ## Why this is an error, not a warning
|
|
823
|
+
*
|
|
824
|
+
* The runtime failure mode is silent and indistinguishable from success. A
|
|
825
|
+
* metric widget filtered on an unresolved `{current_user}` renders `0`, which
|
|
826
|
+
* looks exactly like a metric that is legitimately zero — no console error, no
|
|
827
|
+
* server log, nothing for a human reviewer to notice. Issue #3574 found a
|
|
828
|
+
* dashboard that had been broken this way since the day it was written.
|
|
829
|
+
*
|
|
830
|
+
* That failure mode is worse for AI authors than for humans. An AI reads a
|
|
831
|
+
* successful query returning `0` as a correct answer and builds on it — it has
|
|
832
|
+
* no instinct that the number looks wrong. Its correction loop is
|
|
833
|
+
* "author → validate → fix", so a diagnostic only reaches it if the diagnostic
|
|
834
|
+
* can fail the build. A runtime warning in a server log is invisible to it.
|
|
835
|
+
* Hence: authoring-time error.
|
|
836
|
+
*
|
|
837
|
+
* The near-miss spellings this catches are not hypothetical. Each is a correct
|
|
838
|
+
* spelling *somewhere else* in the platform, which is precisely why authors
|
|
839
|
+
* reach for them:
|
|
840
|
+
*
|
|
841
|
+
* - `{current_user}` — `current_user.id` is the RLS expression root
|
|
842
|
+
* - `{user_id}` — `{user_id}` is valid `titleFormat` field interpolation
|
|
843
|
+
* - `{current_organization_id}` — `organization_id` is the real column name
|
|
844
|
+
*
|
|
845
|
+
* `CONTEXT_TOKEN_SUGGESTIONS` maps each to what the author meant, so the
|
|
846
|
+
* diagnostic names the fix instead of only reporting the symptom.
|
|
847
|
+
*
|
|
848
|
+
* ## Scope — filter subtrees only
|
|
849
|
+
*
|
|
850
|
+
* The walk descends into `filter` / `filters` / `runtimeFilter` subtrees and
|
|
851
|
+
* classifies string values inside them. It deliberately does NOT check
|
|
852
|
+
* navigation `recordId` / `params`, which resolve an additional vocabulary —
|
|
853
|
+
* `AppContextSelector` ids such as `{active_package}` — that is meaningless in
|
|
854
|
+
* a filter because filters are not evaluated with the sidebar's selector
|
|
855
|
+
* state. Restricting the walk keeps that legitimate usage out of the rule and
|
|
856
|
+
* holds false positives at zero.
|
|
857
|
+
*
|
|
858
|
+
* Only whole-string placeholders are considered (`'{token}'` / `'${token}'`,
|
|
859
|
+
* anchored). A value that merely contains braces is left alone.
|
|
860
|
+
*/
|
|
861
|
+
declare const FILTER_TOKEN_UNKNOWN = "filter-token-unknown";
|
|
862
|
+
type FilterTokenSeverity = 'error' | 'warning';
|
|
863
|
+
interface FilterTokenFinding {
|
|
864
|
+
/** Always `error` today — an unresolved placeholder silently matches nothing. */
|
|
865
|
+
severity: FilterTokenSeverity;
|
|
866
|
+
/** Diagnostic rule id. */
|
|
867
|
+
rule: string;
|
|
868
|
+
/** Human-readable location, e.g. `dashboard "sales" · widget "my_deals"`. */
|
|
869
|
+
where: string;
|
|
870
|
+
/** Config path, e.g. `dashboards[0].widgets[2].filter.owner_id`. */
|
|
871
|
+
path: string;
|
|
872
|
+
/** What is wrong. */
|
|
873
|
+
message: string;
|
|
874
|
+
/** How to fix it. */
|
|
875
|
+
hint: string;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Validate filter placeholders across a schema-parsed stack.
|
|
879
|
+
*
|
|
880
|
+
* Pure `(stack) => Finding[]`; no I/O. Covers dashboards (widget + global
|
|
881
|
+
* filters), objects (list views), top-level view containers, reports,
|
|
882
|
+
* datasets, and pages.
|
|
883
|
+
*/
|
|
884
|
+
declare function validateFilterTokens(stack: Record<string, unknown> | undefined | null): FilterTokenFinding[];
|
|
885
|
+
|
|
886
|
+
declare const OBJECT_REFERENCE_UNKNOWN = "object-reference-unknown";
|
|
887
|
+
declare const OBJECT_REFERENCE_UNREGISTERED_PLATFORM = "object-reference-unregistered-platform";
|
|
888
|
+
type ObjectRefSeverity = 'error' | 'warning';
|
|
889
|
+
interface ObjectRefFinding {
|
|
890
|
+
/** `error` for an unresolvable own-stack name; `warning` for an unknown platform name. */
|
|
891
|
+
severity: ObjectRefSeverity;
|
|
892
|
+
/** Diagnostic rule id. */
|
|
893
|
+
rule: string;
|
|
894
|
+
/** Human-readable location, e.g. `action "mass_update" · param "owner"`. */
|
|
895
|
+
where: string;
|
|
896
|
+
/** Config path, e.g. `actions[2].params[0].reference`. */
|
|
897
|
+
path: string;
|
|
898
|
+
/** What is wrong. */
|
|
899
|
+
message: string;
|
|
900
|
+
/** How to fix it. */
|
|
901
|
+
hint: string;
|
|
902
|
+
}
|
|
903
|
+
type AnyRec$8 = Record<string, unknown>;
|
|
904
|
+
/**
|
|
905
|
+
* Validate every object-name reference on the surfaces listed in the module
|
|
906
|
+
* header. Returns findings (empty = clean).
|
|
907
|
+
*/
|
|
908
|
+
declare function validateObjectReferences(stack: AnyRec$8): ObjectRefFinding[];
|
|
909
|
+
|
|
910
|
+
declare const ACTION_NAME_UNDEFINED = "action-name-undefined";
|
|
911
|
+
type ActionNameRefSeverity = 'error' | 'warning';
|
|
912
|
+
interface ActionNameRefFinding {
|
|
913
|
+
/** Always `error` — a name-bound action that resolves nowhere is a dead button. */
|
|
914
|
+
severity: ActionNameRefSeverity;
|
|
915
|
+
/** Diagnostic rule id. */
|
|
916
|
+
rule: string;
|
|
917
|
+
/** Human-readable location, e.g. `view "crm_lead" · list "all" · bulkActions`. */
|
|
918
|
+
where: string;
|
|
919
|
+
/** Config path, e.g. `views[0].list.bulkActions[1]`. */
|
|
920
|
+
path: string;
|
|
921
|
+
/** What is wrong. */
|
|
922
|
+
message: string;
|
|
923
|
+
/** How to fix it. */
|
|
924
|
+
hint: string;
|
|
925
|
+
}
|
|
926
|
+
type AnyRec$7 = Record<string, unknown>;
|
|
927
|
+
/**
|
|
928
|
+
* Validate every name-bound action reference in a stack. Returns findings
|
|
929
|
+
* (empty = clean).
|
|
930
|
+
*/
|
|
931
|
+
declare function validateActionNameRefs(stack: AnyRec$7): ActionNameRefFinding[];
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Shared page-component traversal for the lint rules that inspect
|
|
935
|
+
* `PageComponent.properties` (issue #3583).
|
|
936
|
+
*
|
|
937
|
+
* Getting this walk right is subtle enough that duplicating it has already
|
|
938
|
+
* produced one dead rule, so it lives here once:
|
|
939
|
+
*
|
|
940
|
+
* - Components hang off `page.regions[].components[]` and `page.slots.<slot>`
|
|
941
|
+
* — there is NO top-level `page.components`. A walker that reads
|
|
942
|
+
* `page.components` silently visits nothing on a schema-parsed stack.
|
|
943
|
+
* - `slots.<slot>` is `PageComponent | PageComponent[]` — a single component
|
|
944
|
+
* is legal and must be normalized.
|
|
945
|
+
* - `PageComponentSchema` is `.strict()`, so a component carries no `children`
|
|
946
|
+
* key of its own. Sub-trees live INSIDE the untyped `properties` bag:
|
|
947
|
+
* `page:tabs` → `properties.items[].children`, `page:accordion` →
|
|
948
|
+
* `properties.items[].children`, `page:card` → `properties.body` /
|
|
949
|
+
* `properties.footer`. All are `z.array(z.unknown())`, so the recursion is
|
|
950
|
+
* untyped and has to be done by hand.
|
|
951
|
+
* - `kind: 'html' | 'react' | 'jsx'` pages are authored as `source`, which is
|
|
952
|
+
* authoritative; their `regions` hold at most a DERIVED cache that the
|
|
953
|
+
* source wins over. Linting that cache reports findings about metadata the
|
|
954
|
+
* author never wrote, so those pages are skipped here and covered by
|
|
955
|
+
* `validate-jsx-pages` / `validate-react-page-props` instead.
|
|
956
|
+
*/
|
|
957
|
+
type AnyRec$6 = Record<string, unknown>;
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* [ADR-0078 — completeness] Field-reference integrity for page components
|
|
961
|
+
* (issue #3583, assessment R3).
|
|
962
|
+
*
|
|
963
|
+
* `PageComponent.properties` is `z.record(z.string(), z.unknown())` — an
|
|
964
|
+
* untyped bag. The typed prop schemas exist (`ComponentPropsMap` in
|
|
965
|
+
* `@objectstack/spec/ui`) but nothing validates `properties` against them, so
|
|
966
|
+
* every field name a component references ships exactly as typed. The HotCRM
|
|
967
|
+
* audit found KPI cards and page headers bound to fields the object does not
|
|
968
|
+
* have; each renders blank or falls back, and nothing reports the miss.
|
|
969
|
+
*
|
|
970
|
+
* Field-existence lint already exists for forms (`FORM_FIELD_UNKNOWN`),
|
|
971
|
+
* semantic roles, and flow templates. This is the same check for pages, at the
|
|
972
|
+
* same advisory severity: every consumer degrades gracefully (a missing field
|
|
973
|
+
* is skipped, not crashed on), so a warning is the honest level.
|
|
974
|
+
*
|
|
975
|
+
* ── Which object a component binds ──────────────────────────────────────
|
|
976
|
+
*
|
|
977
|
+
* `dataSource.object` → `properties.object` → the page's `object`. A per-element
|
|
978
|
+
* `dataSource` exists precisely so one page can bind several objects, and the
|
|
979
|
+
* `element:*` family declares its own `object`; both must win over the page's.
|
|
980
|
+
*
|
|
981
|
+
* ── Why a hand-written descriptor table ─────────────────────────────────
|
|
982
|
+
*
|
|
983
|
+
* `ComponentPropsMap` cannot drive this rule: a Zod schema does not say which
|
|
984
|
+
* of its `z.string()` props is a FIELD NAME (`RecordPathProps.statusField` and
|
|
985
|
+
* `AIChatWindowProps.agentId` are both plain strings), and the type universe is
|
|
986
|
+
* open anyway — `PageComponent.type` is `z.union([PageComponentType,
|
|
987
|
+
* z.string()])`, so unregistered types like `record:line_items` parse and are
|
|
988
|
+
* authored in the wild. The table below names the field-bearing props
|
|
989
|
+
* explicitly; an unknown component type is SKIPPED silently, never flagged.
|
|
990
|
+
*
|
|
991
|
+
* The table also covers shapes the props schemas do not yet describe but real
|
|
992
|
+
* pages authored anyway (they pass only because `properties` is unvalidated):
|
|
993
|
+
* `record:details` `sections[].fields[]` and `hideFields[]`, and the record
|
|
994
|
+
* picker's `labelField`. Linting the schema's shape alone would find nothing on
|
|
995
|
+
* the actual corpus.
|
|
996
|
+
*/
|
|
997
|
+
declare const PAGE_FIELD_UNKNOWN = "page-field-unknown";
|
|
998
|
+
type PageFieldSeverity = 'error' | 'warning';
|
|
999
|
+
interface PageFieldFinding {
|
|
1000
|
+
/** Always `warning` — page renderers skip an unknown field rather than fail. */
|
|
1001
|
+
severity: PageFieldSeverity;
|
|
1002
|
+
/** Diagnostic rule id. */
|
|
1003
|
+
rule: string;
|
|
1004
|
+
/** Human-readable location, e.g. `page "task_detail" · record:highlights`. */
|
|
1005
|
+
where: string;
|
|
1006
|
+
/** Config path, e.g. `pages[0].regions[1].components[0].properties.fields[2]`. */
|
|
1007
|
+
path: string;
|
|
1008
|
+
/** What is wrong. */
|
|
1009
|
+
message: string;
|
|
1010
|
+
/** How to fix it. */
|
|
1011
|
+
hint: string;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
declare function validatePageFieldBindings(stack: AnyRec$6): PageFieldFinding[];
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
* [ADR-0021 — semantic layer] Chart-binding integrity for the surfaces the
|
|
1018
|
+
* dashboard rule does not reach (issue #3583, assessment R4).
|
|
1019
|
+
*
|
|
1020
|
+
* `validate-widget-bindings` already resolves a dashboard widget's
|
|
1021
|
+
* `chartConfig` axes against its dataset's declared dimensions and measures
|
|
1022
|
+
* (`chart-field-unknown`). It is scoped to `stack.dashboards`, so three other
|
|
1023
|
+
* chart surfaces ship unchecked — and the HotCRM audit found exactly the bug
|
|
1024
|
+
* that scoping allows: an axis naming a RAW FIELD instead of a dataset measure.
|
|
1025
|
+
* Post-ADR-0021 the result rows are keyed by measure NAME (`sum_amount`), not
|
|
1026
|
+
* the base column (`amount`), so the axis renders and the series is empty.
|
|
1027
|
+
*
|
|
1028
|
+
* Surfaces covered here:
|
|
1029
|
+
*
|
|
1030
|
+
* 1. **Report charts** — `report.chart` and `report.blocks[].chart`.
|
|
1031
|
+
* `ReportChartSchema` narrows `xAxis`/`yAxis` from ChartConfig's
|
|
1032
|
+
* object/array shapes to bare STRINGS, which is why simply pointing the
|
|
1033
|
+
* dashboard rule at reports would find nothing: its `Array.isArray(yAxis)`
|
|
1034
|
+
* guard skips a string silently. `series[].name` keeps the array shape.
|
|
1035
|
+
* 2. **List-view charts** — `ListChartConfigSchema` (`dataset` +
|
|
1036
|
+
* `dimensions` + `values`), reachable through `views[].list`,
|
|
1037
|
+
* `views[].listViews.<key>`, and `objects[].listViews.<key>`.
|
|
1038
|
+
* 3. **Dataset-bound page chart components** — a `PageComponent` whose
|
|
1039
|
+
* `properties` carry a `dataset` (the `object-chart` component). Same
|
|
1040
|
+
* binding shape as a list chart, but it arrives through the untyped
|
|
1041
|
+
* `properties` bag.
|
|
1042
|
+
*
|
|
1043
|
+
* Not covered HERE, and deliberately so: the react `<ObjectChart>` block. It is
|
|
1044
|
+
* OBJECT-bound (`objectName` + an inline `aggregate`), so its result rows are
|
|
1045
|
+
* keyed by the RAW FIELD NAMES rather than by a measure name — the opposite
|
|
1046
|
+
* convention, which would make `chart-measure-unknown`'s message a lie. It also
|
|
1047
|
+
* arrives as JSX rather than config, so it needs the TypeScript compiler this
|
|
1048
|
+
* rule has no business loading. It is checked by `validate-react-page-props`
|
|
1049
|
+
* instead, against the naming convention `chartAggregateResultKeys`
|
|
1050
|
+
* (`@objectstack/spec/ui`) now pins down (#3701).
|
|
1051
|
+
*/
|
|
1052
|
+
declare const CHART_DIMENSION_UNKNOWN = "chart-dimension-unknown";
|
|
1053
|
+
declare const CHART_MEASURE_UNKNOWN = "chart-measure-unknown";
|
|
1054
|
+
declare const CHART_DATASET_UNKNOWN = "chart-dataset-unknown";
|
|
1055
|
+
declare const CHART_AXIS_NOT_SELECTED = "chart-axis-not-selected";
|
|
1056
|
+
type ChartBindingSeverity = 'error' | 'warning';
|
|
1057
|
+
interface ChartBindingFinding {
|
|
1058
|
+
severity: ChartBindingSeverity;
|
|
1059
|
+
/** Diagnostic rule id. */
|
|
1060
|
+
rule: string;
|
|
1061
|
+
/** Human-readable location, e.g. `report "hours_by_status" · chart`. */
|
|
1062
|
+
where: string;
|
|
1063
|
+
/** Config path, e.g. `reports[2].chart.yAxis`. */
|
|
1064
|
+
path: string;
|
|
1065
|
+
/** What is wrong. */
|
|
1066
|
+
message: string;
|
|
1067
|
+
/** How to fix it. */
|
|
1068
|
+
hint: string;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
declare function validateChartBindings(stack: AnyRec$6): ChartBindingFinding[];
|
|
1072
|
+
|
|
1073
|
+
declare const NAV_OBJECT_UNGRANTED = "nav-object-ungranted";
|
|
1074
|
+
type NavAccessSeverity = 'error' | 'warning';
|
|
1075
|
+
interface NavAccessFinding {
|
|
1076
|
+
/** Always `warning` — a grant may come from a package this stack cannot see. */
|
|
1077
|
+
severity: NavAccessSeverity;
|
|
1078
|
+
/** Diagnostic rule id. */
|
|
1079
|
+
rule: string;
|
|
1080
|
+
/** Human-readable location, e.g. `app "crm" · nav "nav_forecast"`. */
|
|
1081
|
+
where: string;
|
|
1082
|
+
/** Config path, e.g. `apps[0].navigation[3].objectName`. */
|
|
1083
|
+
path: string;
|
|
1084
|
+
/** What is wrong. */
|
|
1085
|
+
message: string;
|
|
1086
|
+
/** How to fix it. */
|
|
1087
|
+
hint: string;
|
|
1088
|
+
}
|
|
1089
|
+
type AnyRec$5 = Record<string, unknown>;
|
|
1090
|
+
/**
|
|
1091
|
+
* Validate that every object a stack's navigation exposes is readable by at
|
|
1092
|
+
* least one permission set the stack declares. Returns findings (empty = clean).
|
|
1093
|
+
*/
|
|
1094
|
+
declare function validateNavAccess(stack: AnyRec$5): NavAccessFinding[];
|
|
1095
|
+
|
|
1096
|
+
declare const TRANSLATION_TARGET_UNKNOWN = "translation-target-unknown";
|
|
1097
|
+
declare const TRANSLATION_OPTION_KEY_UNKNOWN = "translation-option-key-unknown";
|
|
1098
|
+
type TranslationRefSeverity = 'warning';
|
|
1099
|
+
interface TranslationRefFinding {
|
|
1100
|
+
/** Always `warning` — an orphan translation key is inert, not broken. */
|
|
1101
|
+
severity: TranslationRefSeverity;
|
|
1102
|
+
/** Diagnostic rule id. */
|
|
1103
|
+
rule: string;
|
|
1104
|
+
/** Human-readable location, e.g. `locale "zh-CN" · object "crm_lead"`. */
|
|
1105
|
+
where: string;
|
|
1106
|
+
/** Config path, e.g. `translations[0]["zh-CN"].objects.crm_lead.fields.campaign`. */
|
|
1107
|
+
path: string;
|
|
1108
|
+
/** What is wrong. */
|
|
1109
|
+
message: string;
|
|
1110
|
+
/** How to fix it. */
|
|
1111
|
+
hint: string;
|
|
1112
|
+
}
|
|
1113
|
+
type AnyRec$4 = Record<string, unknown>;
|
|
1114
|
+
/**
|
|
1115
|
+
* Validate every reference a translation bundle makes against the metadata it
|
|
1116
|
+
* claims to translate. Returns findings (empty = clean).
|
|
1117
|
+
*/
|
|
1118
|
+
declare function validateTranslationReferences(stack: AnyRec$4): TranslationRefFinding[];
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* [ADR-0064 §3] Skill ↔ agent surface affinity (issue #3820).
|
|
1122
|
+
*
|
|
1123
|
+
* An agent binds a product surface (`'ask'` | `'build'`, ADR-0063 §1) and a
|
|
1124
|
+
* skill declares which surface it belongs to (`'ask'` | `'build'` | `'both'`,
|
|
1125
|
+
* ADR-0063 §3). A skill may only attach to an agent whose surface it matches —
|
|
1126
|
+
* `'both'` attaches to either. The runtime treats a violation as a FAST LOAD
|
|
1127
|
+
* ERROR: `resolveActiveSkills()` throws on the first incompatible binding, so
|
|
1128
|
+
* an agent shipping one mismatched skill reference fails at **chat time** with
|
|
1129
|
+
* a 500 — after parse, after validate, after deploy.
|
|
1130
|
+
*
|
|
1131
|
+
* Both sides of the check are declared in the same stack, so the contradiction
|
|
1132
|
+
* is statically provable and this rule carries severity **error** with zero
|
|
1133
|
+
* false positives by construction. Both sides default to `'ask'` when the
|
|
1134
|
+
* `surface` field is absent (mirroring the runtime's defaults), so the rule is
|
|
1135
|
+
* safe on the raw/normalized config the `lint` path carries as well as the
|
|
1136
|
+
* schema-parsed stack.
|
|
1137
|
+
*
|
|
1138
|
+
* Scope note: this rule deliberately does NOT check that `agent.skills[]`
|
|
1139
|
+
* names resolve at all. Kernel skills (`schema_reader`, the `ask`/`build`
|
|
1140
|
+
* bundles) are runtime-registered and statically invisible, and whether
|
|
1141
|
+
* app-stack tool/skill namespaces get a platform-name registry is an open
|
|
1142
|
+
* decision (#3820 D0/D2) — resolving names against `stack.skills` alone would
|
|
1143
|
+
* flag every kernel-skill reference. An unresolved name is therefore skipped
|
|
1144
|
+
* here; only a reference that resolves in-stack AND contradicts the affinity
|
|
1145
|
+
* contract is reported.
|
|
1146
|
+
*/
|
|
1147
|
+
declare const AI_SKILL_SURFACE_MISMATCH = "ai-skill-surface-mismatch";
|
|
1148
|
+
type AiSurfaceAffinitySeverity = 'error' | 'warning';
|
|
1149
|
+
interface AiSurfaceAffinityFinding {
|
|
1150
|
+
/** Always `error` — the runtime throws on this binding at chat time. */
|
|
1151
|
+
severity: AiSurfaceAffinitySeverity;
|
|
1152
|
+
/** Diagnostic rule id. */
|
|
1153
|
+
rule: string;
|
|
1154
|
+
/** Human-readable location, e.g. `agent "sales_copilot" · skills`. */
|
|
1155
|
+
where: string;
|
|
1156
|
+
/** Config path, e.g. `agents[0].skills[2]`. */
|
|
1157
|
+
path: string;
|
|
1158
|
+
/** What is wrong. */
|
|
1159
|
+
message: string;
|
|
1160
|
+
/** How to fix it. */
|
|
1161
|
+
hint: string;
|
|
1162
|
+
}
|
|
1163
|
+
type AnyRec$3 = Record<string, unknown>;
|
|
1164
|
+
/**
|
|
1165
|
+
* Validate every in-stack agent→skill binding against the ADR-0064 §3 surface
|
|
1166
|
+
* affinity contract. Returns findings (empty = clean).
|
|
1167
|
+
*/
|
|
1168
|
+
declare function validateAiSurfaceAffinity(stack: AnyRec$3): AiSurfaceAffinityFinding[];
|
|
1169
|
+
|
|
1170
|
+
declare const AI_SKILL_TOOL_UNRESOLVED = "ai-skill-tool-unresolved";
|
|
1171
|
+
type AiToolRefSeverity = 'error' | 'warning';
|
|
1172
|
+
interface AiToolRefFinding {
|
|
1173
|
+
/** Always `warning` — see the header for why this rule starts advisory. */
|
|
1174
|
+
severity: AiToolRefSeverity;
|
|
1175
|
+
/** Diagnostic rule id. */
|
|
1176
|
+
rule: string;
|
|
1177
|
+
/** Human-readable location, e.g. `skill "revenue_forecasting" · tools`. */
|
|
1178
|
+
where: string;
|
|
1179
|
+
/** Config path, e.g. `skills[3].tools[1]`. */
|
|
1180
|
+
path: string;
|
|
1181
|
+
/** What is wrong. */
|
|
1182
|
+
message: string;
|
|
1183
|
+
/** How to fix it. */
|
|
1184
|
+
hint: string;
|
|
1185
|
+
}
|
|
1186
|
+
type AnyRec$2 = Record<string, unknown>;
|
|
1187
|
+
/**
|
|
1188
|
+
* Validate every `skill.tools[]` reference in a stack. Returns findings
|
|
1189
|
+
* (empty = clean).
|
|
1190
|
+
*/
|
|
1191
|
+
declare function validateAiToolReferences(stack: AnyRec$2): AiToolRefFinding[];
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* [ADR-0063 §2] `stack.agents` is a platform-internal slot (issue #3820).
|
|
1195
|
+
*
|
|
1196
|
+
* ADR-0063 §2 withdrew tenant/app-package custom agents: the kernel ships
|
|
1197
|
+
* exactly two agents (`ask`, `build`), the surface the user is in binds one,
|
|
1198
|
+
* and third parties extend the platform by authoring **skills**, never
|
|
1199
|
+
* `*.agent.ts`. The `agent` metadata type carries the decision
|
|
1200
|
+
* (`allowRuntimeCreate: false, allowOrgOverride: false`), and the runtime
|
|
1201
|
+
* enforces it on both paths — `listAgents()` filters non-platform records out
|
|
1202
|
+
* of the catalog, and `loadAgent()` refuses them outright (cloud#904), so a
|
|
1203
|
+
* stack-authored agent 404s on chat and cannot be pinned via
|
|
1204
|
+
* `app.defaultAgent`.
|
|
1205
|
+
*
|
|
1206
|
+
* What was missing is the AUTHORING-time signal. `defineStack` still accepts
|
|
1207
|
+
* an `agents` array, so an app package could declare agents that parse,
|
|
1208
|
+
* validate, and build into the artifact — and then do nothing at runtime.
|
|
1209
|
+
* HotCRM shipped two of them for months. That is the ADR-0078 shape this rule
|
|
1210
|
+
* closes: loud at the producer, tolerant at the consumer (Prime Directive
|
|
1211
|
+
* #12).
|
|
1212
|
+
*
|
|
1213
|
+
* Severity is **warning**, not error, for one reason: the platform's own
|
|
1214
|
+
* packages legitimately author agent records, and this rule cannot tell a
|
|
1215
|
+
* platform package from an app package by reading the stack alone. A warning
|
|
1216
|
+
* that names the runtime consequence is honest for both readers; the runtime
|
|
1217
|
+
* is what actually gates. Deliberately NOT a Zod refine — an existing stack
|
|
1218
|
+
* must keep parsing (ADR-0078 non-goal #1).
|
|
1219
|
+
*/
|
|
1220
|
+
declare const AGENT_AUTHORING_WITHDRAWN = "agent-authoring-withdrawn";
|
|
1221
|
+
type AiAgentAuthoringSeverity = 'error' | 'warning';
|
|
1222
|
+
interface AiAgentAuthoringFinding {
|
|
1223
|
+
/** Always `warning` — the runtime is the gate; this is the authoring-time signal. */
|
|
1224
|
+
severity: AiAgentAuthoringSeverity;
|
|
1225
|
+
/** Diagnostic rule id. */
|
|
1226
|
+
rule: string;
|
|
1227
|
+
/** Human-readable location, e.g. `agent "sales_copilot"`. */
|
|
1228
|
+
where: string;
|
|
1229
|
+
/** Config path, e.g. `agents[0]`. */
|
|
1230
|
+
path: string;
|
|
1231
|
+
/** What is wrong. */
|
|
1232
|
+
message: string;
|
|
1233
|
+
/** How to fix it. */
|
|
1234
|
+
hint: string;
|
|
1235
|
+
}
|
|
1236
|
+
type AnyRec$1 = Record<string, unknown>;
|
|
1237
|
+
/**
|
|
1238
|
+
* Flag every agent declared in a stack. Returns findings (empty = clean,
|
|
1239
|
+
* which is what every app package should be).
|
|
1240
|
+
*/
|
|
1241
|
+
declare function validateAiAgentAuthoring(stack: AnyRec$1): AiAgentAuthoringFinding[];
|
|
1242
|
+
|
|
1243
|
+
type ReferenceIntegritySeverity = 'error' | 'warning';
|
|
1244
|
+
/**
|
|
1245
|
+
* The shape every rule in the suite already returns. Declared here so callers
|
|
1246
|
+
* can hold one type instead of a six-way union.
|
|
1247
|
+
*/
|
|
1248
|
+
interface ReferenceIntegrityFinding {
|
|
1249
|
+
/** `error` = the reference is dead; `warning` = it may resolve elsewhere, or the miss is inert. */
|
|
1250
|
+
severity: ReferenceIntegritySeverity;
|
|
1251
|
+
/** Diagnostic rule id (stable; used by allowlists and docs). */
|
|
1252
|
+
rule: string;
|
|
1253
|
+
/** Human-readable location. */
|
|
1254
|
+
where: string;
|
|
1255
|
+
/** Config path. */
|
|
1256
|
+
path: string;
|
|
1257
|
+
/** What is wrong. */
|
|
1258
|
+
message: string;
|
|
1259
|
+
/** How to fix it. */
|
|
1260
|
+
hint: string;
|
|
1261
|
+
}
|
|
1262
|
+
/** One member of the suite. `name` is the exported function's name — the id a wiring test can assert on. */
|
|
1263
|
+
interface ReferenceIntegrityRule {
|
|
1264
|
+
name: string;
|
|
1265
|
+
run: (stack: Record<string, unknown>) => ReferenceIntegrityFinding[];
|
|
1266
|
+
}
|
|
1267
|
+
/**
|
|
1268
|
+
* Every reference-integrity rule, in the order their findings are reported.
|
|
1269
|
+
*
|
|
1270
|
+
* ADDING A RULE: append it here and it runs on `validate`, `lint` and
|
|
1271
|
+
* `compile` at once. Do not re-wire the commands.
|
|
1272
|
+
*/
|
|
1273
|
+
declare const REFERENCE_INTEGRITY_RULES: readonly ReferenceIntegrityRule[];
|
|
1274
|
+
/**
|
|
1275
|
+
* Run every reference-integrity rule over a stack. Returns the concatenated
|
|
1276
|
+
* findings (empty = clean). Pure: no I/O, safe on both the schema-parsed stack
|
|
1277
|
+
* and the raw/normalized config the `lint` path carries.
|
|
1278
|
+
*/
|
|
1279
|
+
declare function validateReferenceIntegrity(stack: Record<string, unknown>): ReferenceIntegrityFinding[];
|
|
1280
|
+
|
|
559
1281
|
/**
|
|
560
1282
|
* [ADR-0090 D6] Access-matrix snapshot — authoring-time companion to the
|
|
561
1283
|
* runtime explain engine.
|
|
@@ -580,4 +1302,4 @@ declare function buildAccessMatrix(stack: AnyRec): AccessMatrix;
|
|
|
580
1302
|
*/
|
|
581
1303
|
declare function diffAccessMatrix(before: AccessMatrix, after: AccessMatrix): string[];
|
|
582
1304
|
|
|
583
|
-
export { APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER, APPROVAL_APPROVER_TYPE_DEPRECATED, APPROVAL_APPROVER_TYPE_UNKNOWN, APPROVAL_ESCALATION_REASSIGN_NO_TARGET, type ApprovalApproverFinding, type ApprovalApproverSeverity, CAPABILITY_REFERENCE_UNKNOWN, CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type CapabilityRefFinding, type CapabilityRefSeverity, type ExprIssue, FIELD_GROUP_EMPTY, FIELD_GROUP_UNDECLARED, FLOW_DRAFT_STATUS_AMBIGUOUS, FLOW_TRIGGER_UNKNOWN_OBJECT, FORM_COLSPAN_ABSOLUTE, FORM_FIELD_UNKNOWN, type FlowTriggerReadinessFinding, type FlowTriggerReadinessSeverity, type FormLayoutFinding, type FormLayoutSeverity, type JsxPageFinding, type JsxPageSeverity, LIST_VIEW_FILTERS_IN_VIEWS_MODE, type ListViewModeFinding, type ListViewModeSeverity, MEASURE_AGGREGATE_INCOHERENT, PAGE_SOURCE_CLASSNAME, type ReactPageFinding, type ReactPageSeverity, type ReactPropFinding, type ReactPropSeverity, type RecordTitleFinding, type RecordTitleSeverity, SECURITY_ANCHOR_HIGH_PRIVILEGE, SECURITY_BOOK_AUDIENCE_UNKNOWN_SET, SECURITY_DELEGATION_MISSING_REASON, SECURITY_EXTERNAL_WIDER, SECURITY_GRANT_EXPIRED_AT_AUTHORING, SECURITY_MASTER_DETAIL_UNGRANTED, SECURITY_OWD_ALIAS, SECURITY_OWD_UNSET, SECURITY_PRIVATE_NO_READSCOPE, SECURITY_ROLE_WORD, SECURITY_WILDCARD_VAMA, SEMANTIC_ROLE_FIELD_UNKNOWN, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type SecurityFinding, type SecuritySeverity, type SemanticRoleFinding, type SemanticRoleSeverity, type SourceStyleFinding, type SourceStyleSeverity, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, TITLE_FORMAT_RETIRED, TITLE_UNRESOLVABLE, VIEW_CONTAINER_SHAPE, VISIBILITY_ALIAS_DEPRECATED, VISIBILITY_ROOT_MISLAYERED, type ViewContainerFinding, type ViewContainerSeverity, type VisibilityFinding, type VisibilityLayer, type VisibilityOptions, type VisibilitySeverity, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, buildAccessMatrix, diffAccessMatrix, validateApprovalApprovers, validateCapabilityReferences, validateFlowTriggerReadiness, validateFormLayout, validateJsxPages, validateListViewMode, validatePageSourceStyling, validateReactPageProps, validateReactPages, validateRecordTitle, validateResponsiveStyles, validateSecurityPosture, validateSemanticRoles, validateStackExpressions, validateViewContainers, validateVisibilityPredicates, validateWidgetBindings };
|
|
1305
|
+
export { ACTION_NAME_UNDEFINED, AGENT_AUTHORING_WITHDRAWN, AI_SKILL_SURFACE_MISMATCH, AI_SKILL_TOOL_UNRESOLVED, APPROVAL_APPROVERS_MAY_RESOLVE_EMPTY, APPROVAL_APPROVER_CROSS_ORG_UNSUPPORTED, APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER, APPROVAL_APPROVER_TYPE_DEPRECATED, APPROVAL_APPROVER_TYPE_UNKNOWN, APPROVAL_DECISION_OUTPUTS_RESERVED, APPROVAL_ESCALATION_REASSIGN_NO_TARGET, APPROVAL_EXPRESSION_INVALID, APPROVAL_EXPRESSION_NO_EMPTY_POLICY, type ActionNameRefFinding, type ActionNameRefSeverity, type AiAgentAuthoringFinding, type AiAgentAuthoringSeverity, type AiSurfaceAffinityFinding, type AiSurfaceAffinitySeverity, type AiToolRefFinding, type AiToolRefSeverity, type ApprovalApproverFinding, type ApprovalApproverSeverity, CAPABILITY_REFERENCE_UNKNOWN, CHART_AXIS_NOT_SELECTED, CHART_CONFIG_MISSING, CHART_DATASET_UNKNOWN, CHART_DIMENSION_UNKNOWN, CHART_FIELD_UNKNOWN, CHART_MEASURE_UNKNOWN, type CapabilityRefFinding, type CapabilityRefSeverity, type ChartBindingFinding, type ChartBindingSeverity, DASHBOARD_ACTION_ROUTE_UNRESOLVED, DASHBOARD_ACTION_TARGET_UNDEFINED, DASHBOARD_FILTER_FIELD_UNKNOWN, type DashboardActionRefFinding, type DashboardActionRefSeverity, type ExprIssue, FIELD_GROUP_EMPTY, FIELD_GROUP_UNDECLARED, FILTER_TOKEN_UNKNOWN, FLOW_DRAFT_STATUS_AMBIGUOUS, FLOW_TEMPLATE_LOOKUP_TRAVERSAL, FLOW_TEMPLATE_UNKNOWN_FIELD, FLOW_TRIGGER_UNKNOWN_OBJECT, FLOW_UPDATE_READONLY_FIELD, FLOW_UPDATE_READONLY_WHEN_FIELD, FORM_COLSPAN_ABSOLUTE, FORM_FIELD_UNKNOWN, type FilterTokenFinding, type FilterTokenSeverity, type FlowTemplatePathFinding, type FlowTemplatePathSeverity, type FlowTriggerReadinessFinding, type FlowTriggerReadinessSeverity, type FormLayoutFinding, type FormLayoutSeverity, type JsxPageFinding, type JsxPageSeverity, LIST_VIEW_FILTERS_IN_VIEWS_MODE, type ListViewModeFinding, type ListViewModeSeverity, MEASURE_AGGREGATE_INCOHERENT, NAV_OBJECT_UNGRANTED, type NavAccessFinding, type NavAccessSeverity, OBJECT_REFERENCE_UNKNOWN, OBJECT_REFERENCE_UNREGISTERED_PLATFORM, ORG_AXIS_CROSS_ORG_BU_GRANT, ORG_AXIS_PERMISSION_INHERITANCE, type ObjectRefFinding, type ObjectRefSeverity, type OrgAxisFinding, type OrgAxisSeverity, PAGE_FIELD_UNKNOWN, PAGE_SOURCE_CLASSNAME, type PageFieldFinding, type PageFieldSeverity, REACT_CHART_AGGREGATE_INVALID, REACT_CHART_AXIS_UNKNOWN, REACT_CHART_FIELD_UNKNOWN, REFERENCE_INTEGRITY_RULES, type ReactPageFinding, type ReactPageSeverity, type ReactPropFinding, type ReactPropSeverity, type ReadonlyFlowWriteFinding, type ReadonlyFlowWriteSeverity, type RecordTitleFinding, type RecordTitleSeverity, type ReferenceIntegrityFinding, type ReferenceIntegrityRule, type ReferenceIntegritySeverity, SECURITY_ANCHOR_HIGH_PRIVILEGE, SECURITY_BOOK_AUDIENCE_UNKNOWN_SET, SECURITY_DELEGATION_MISSING_REASON, SECURITY_EXTERNAL_WIDER, SECURITY_GRANT_EXPIRED_AT_AUTHORING, SECURITY_MASTER_DETAIL_UNGRANTED, SECURITY_OWD_ALIAS, SECURITY_OWD_UNSET, SECURITY_PRIVATE_NO_READSCOPE, SECURITY_ROLE_WORD, SECURITY_WILDCARD_VAMA, SEED_INSERT_MODE_DUPLICATES_ON_REPLAY, SEED_VALUE_OUTSIDE_STATE_MACHINE, SEMANTIC_ROLE_FIELD_UNKNOWN, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type SecurityFinding, type SecuritySeverity, type SeedReplaySafetyFinding, type SeedReplaySafetySeverity, type SeedStateMachineFinding, type SeedStateMachineSeverity, type SemanticRoleFinding, type SemanticRoleSeverity, type SourceStyleFinding, type SourceStyleSeverity, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, TITLE_FORMAT_RETIRED, TITLE_UNRESOLVABLE, TRANSLATION_OPTION_KEY_UNKNOWN, TRANSLATION_TARGET_UNKNOWN, type TranslationRefFinding, type TranslationRefSeverity, VIEW_CONTAINER_SHAPE, VISIBILITY_ALIAS_DEPRECATED, VISIBILITY_ROOT_MISLAYERED, type ViewContainerFinding, type ViewContainerSeverity, type VisibilityFinding, type VisibilityLayer, type VisibilityOptions, type VisibilitySeverity, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, buildAccessMatrix, diffAccessMatrix, validateActionNameRefs, validateAiAgentAuthoring, validateAiSurfaceAffinity, validateAiToolReferences, validateApprovalApprovers, validateCapabilityReferences, validateChartBindings, validateDashboardActionRefs, validateFilterTokens, validateFlowTemplatePaths, validateFlowTriggerReadiness, validateFormLayout, validateJsxPages, validateListViewMode, validateNavAccess, validateObjectReferences, validateOrgAxisRedLines, validatePageFieldBindings, validatePageSourceStyling, validateReactPageProps, validateReactPages, validateReadonlyFlowWrites, validateRecordTitle, validateReferenceIntegrity, validateResponsiveStyles, validateSecurityPosture, validateSeedReplaySafety, validateSeedStateMachine, validateSemanticRoles, validateStackExpressions, validateTranslationReferences, validateViewContainers, validateVisibilityPredicates, validateWidgetBindings };
|