@objectstack/lint 17.0.0-rc.1 → 17.0.0-rc.2
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/CHANGELOG.md +688 -0
- package/dist/index.cjs +2597 -343
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +610 -108
- package/dist/index.d.ts +610 -108
- package/dist/index.js +2556 -340
- package/dist/index.js.map +1 -1
- package/dist/runtime-Cs64ShwN.d.cts +254 -0
- package/dist/runtime-Cs64ShwN.d.ts +254 -0
- package/dist/runtime.cjs +7740 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +1 -0
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +7733 -0
- package/dist/runtime.js.map +1 -0
- package/package.json +12 -6
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Manifest } from '@objectstack/sdui-parser';
|
|
2
2
|
import { AccessMatrix } from '@objectstack/spec/security';
|
|
3
|
+
export { A as AUTHORING_COMMANDS, a as AUTHORING_RULES, b as AUTHORING_SURFACES, c as AuthoringCommand, d as AuthoringFinding, e as AuthoringRule, f as AuthoringRuleContext, g as AuthoringRuleInputTier, h as AuthoringRuleRun, i as AuthoringRuleTier, j as AuthoringSeverity, k as AuthoringSurface, E as EXPRESSION_INVALID, R as RuntimeGateResult, l as RuntimeStackContext, m as authoringRulesFor, r as runAuthoringRules, n as runRuntimeAuthoringRules, o as runtimeAuthoringRulesFor, p as runtimeGatedTypes, s as splitBySeverity, q as stackKeyForType } from './runtime-Cs64ShwN.cjs';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Build-time dashboard widget binding diagnostics (issues #1719, #1721).
|
|
@@ -94,7 +95,7 @@ interface WidgetBindingFinding {
|
|
|
94
95
|
/** How to fix (or deliberately suppress) it. */
|
|
95
96
|
hint: string;
|
|
96
97
|
}
|
|
97
|
-
type AnyRec$
|
|
98
|
+
type AnyRec$C = Record<string, unknown>;
|
|
98
99
|
/**
|
|
99
100
|
* Validate every dashboard widget's dataset binding. Returns the list of
|
|
100
101
|
* findings (empty = clean). Caller decides how to surface them: `error`
|
|
@@ -102,7 +103,7 @@ type AnyRec$x = Record<string, unknown>;
|
|
|
102
103
|
* should fail validate/build; `warning` findings are advisory and must
|
|
103
104
|
* never fail the build on their own.
|
|
104
105
|
*/
|
|
105
|
-
declare function validateWidgetBindings(stack: AnyRec$
|
|
106
|
+
declare function validateWidgetBindings(stack: AnyRec$C): WidgetBindingFinding[];
|
|
106
107
|
|
|
107
108
|
interface ExprIssue {
|
|
108
109
|
where: string;
|
|
@@ -115,12 +116,56 @@ interface ExprIssue {
|
|
|
115
116
|
*/
|
|
116
117
|
severity?: 'error' | 'warning';
|
|
117
118
|
}
|
|
118
|
-
type AnyRec$
|
|
119
|
+
type AnyRec$B = Record<string, unknown>;
|
|
119
120
|
/**
|
|
120
121
|
* Validate every predicate in the stack. Returns the list of issues (empty =
|
|
121
122
|
* clean). Caller decides how to surface / whether to fail the build.
|
|
122
123
|
*/
|
|
123
|
-
declare function validateStackExpressions(stack: AnyRec$
|
|
124
|
+
declare function validateStackExpressions(stack: AnyRec$B): ExprIssue[];
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The corrective sentence, lifted **verbatim** from `unevaluableRuleError` in
|
|
128
|
+
* `packages/objectql/src/validation/rule-validator.ts` so the publish-time and
|
|
129
|
+
* runtime messages read identically — an author who hits one and then the other
|
|
130
|
+
* must not have to reconcile two phrasings of one rule (#4763).
|
|
131
|
+
*/
|
|
132
|
+
declare const NULL_GUARD_HINT: string;
|
|
133
|
+
interface NullGuardOptions {
|
|
134
|
+
/** Field names of the object that may hold `null` at evaluation time. */
|
|
135
|
+
nullableFields: ReadonlySet<string>;
|
|
136
|
+
/** Roots bound to the object's record shape. Defaults to `record`/`previous`. */
|
|
137
|
+
roots?: readonly string[];
|
|
138
|
+
}
|
|
139
|
+
interface NullGuardFinding {
|
|
140
|
+
/** The operand as written, e.g. `record.end_date`. */
|
|
141
|
+
operand: string;
|
|
142
|
+
/** The declared field the operand resolves to, e.g. `end_date`. */
|
|
143
|
+
field: string;
|
|
144
|
+
/** The operator with no null overload, e.g. `<`. */
|
|
145
|
+
operator: string;
|
|
146
|
+
/**
|
|
147
|
+
* True when the predicate "guards" this operand with `has()` and nothing
|
|
148
|
+
* else — the exact trap #4763 exists to reject. Used only to sharpen the
|
|
149
|
+
* message; the verdict is the same either way.
|
|
150
|
+
*/
|
|
151
|
+
hasOnlyGuard: boolean;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Find every ordering/arithmetic operand that resolves to a nullable declared
|
|
155
|
+
* field and is not dominated by a real null guard. Returns `[]` for anything
|
|
156
|
+
* that does not parse (syntax is reported by `validateExpression`, not here) —
|
|
157
|
+
* this pass never invents a second syntax verdict.
|
|
158
|
+
*/
|
|
159
|
+
declare function findUnguardedNullableOperands(source: string, opts: NullGuardOptions): NullGuardFinding[];
|
|
160
|
+
/**
|
|
161
|
+
* The publish-time message for one finding. Names the rule, the operand and the
|
|
162
|
+
* `!= null` fix (the three things the author needs), then closes with the
|
|
163
|
+
* verbatim runtime sentence so the two gates speak with one voice.
|
|
164
|
+
*
|
|
165
|
+
* @param subject How the site names itself, e.g. `validation rule 'end_after_start'`.
|
|
166
|
+
* @param objectName The object whose field list decided nullability.
|
|
167
|
+
*/
|
|
168
|
+
declare function nullGuardMessage(subject: string, objectName: string | undefined, finding: NullGuardFinding): string;
|
|
124
169
|
|
|
125
170
|
type ListViewModeSeverity = 'error' | 'warning';
|
|
126
171
|
interface ListViewModeFinding {
|
|
@@ -134,7 +179,7 @@ interface ListViewModeFinding {
|
|
|
134
179
|
hint: string;
|
|
135
180
|
}
|
|
136
181
|
declare const LIST_VIEW_FILTERS_IN_VIEWS_MODE = "list-view-filters-in-views-mode";
|
|
137
|
-
type AnyRec$
|
|
182
|
+
type AnyRec$A = Record<string, unknown>;
|
|
138
183
|
/**
|
|
139
184
|
* Flag ADR-0047 "views" mode violations on an object's built-in named views or a
|
|
140
185
|
* `defineView` default `list` / named `listViews`: `quickFilters`, or a `tabs`
|
|
@@ -144,7 +189,25 @@ type AnyRec$v = Record<string, unknown>;
|
|
|
144
189
|
*
|
|
145
190
|
* Feed the PRE-parse stack (normalizeStackInput output) — see file header.
|
|
146
191
|
*/
|
|
147
|
-
declare function validateListViewMode(stack: AnyRec$
|
|
192
|
+
declare function validateListViewMode(stack: AnyRec$A): ListViewModeFinding[];
|
|
193
|
+
|
|
194
|
+
type FunctionalCompletenessSeverity = 'error' | 'warning';
|
|
195
|
+
interface FunctionalCompletenessFinding {
|
|
196
|
+
severity: FunctionalCompletenessSeverity;
|
|
197
|
+
/** Stable rule id from the shared predicate (e.g. `field/summary-without-operations`). */
|
|
198
|
+
rule: string;
|
|
199
|
+
/** Human-readable location, e.g. `object "order" › fields.total`. */
|
|
200
|
+
where: string;
|
|
201
|
+
/** Config path, e.g. `objects[2].fields.total.summaryOperations`. */
|
|
202
|
+
path: string;
|
|
203
|
+
message: string;
|
|
204
|
+
hint: string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Walk every field definition and every list-view definition in the stack
|
|
208
|
+
* through the shared completeness predicate.
|
|
209
|
+
*/
|
|
210
|
+
declare function validateFunctionalCompleteness(stack: unknown): FunctionalCompletenessFinding[];
|
|
148
211
|
|
|
149
212
|
type FlowTriggerReadinessSeverity = 'error' | 'warning';
|
|
150
213
|
interface FlowTriggerReadinessFinding {
|
|
@@ -159,12 +222,12 @@ interface FlowTriggerReadinessFinding {
|
|
|
159
222
|
}
|
|
160
223
|
declare const FLOW_TRIGGER_UNKNOWN_OBJECT = "flow-trigger-unknown-object";
|
|
161
224
|
declare const FLOW_DRAFT_STATUS_AMBIGUOUS = "flow-draft-status-ambiguous";
|
|
162
|
-
type AnyRec$
|
|
225
|
+
type AnyRec$z = Record<string, unknown>;
|
|
163
226
|
/**
|
|
164
227
|
* Validate auto-launched flow trigger wiring against the stack definition.
|
|
165
228
|
* Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
166
229
|
*/
|
|
167
|
-
declare function validateFlowTriggerReadiness(stack: AnyRec$
|
|
230
|
+
declare function validateFlowTriggerReadiness(stack: AnyRec$z): FlowTriggerReadinessFinding[];
|
|
168
231
|
|
|
169
232
|
type FlowTemplatePathSeverity = 'error' | 'warning';
|
|
170
233
|
interface FlowTemplatePathFinding {
|
|
@@ -179,12 +242,12 @@ interface FlowTemplatePathFinding {
|
|
|
179
242
|
}
|
|
180
243
|
declare const FLOW_TEMPLATE_UNKNOWN_FIELD = "flow-template-unknown-field";
|
|
181
244
|
declare const FLOW_TEMPLATE_LOOKUP_TRAVERSAL = "flow-template-lookup-traversal";
|
|
182
|
-
type AnyRec$
|
|
245
|
+
type AnyRec$y = Record<string, unknown>;
|
|
183
246
|
/**
|
|
184
247
|
* Validate `{record.<path>}` template references across every record-change
|
|
185
248
|
* flow. Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
186
249
|
*/
|
|
187
|
-
declare function validateFlowTemplatePaths(stack: AnyRec$
|
|
250
|
+
declare function validateFlowTemplatePaths(stack: AnyRec$y): FlowTemplatePathFinding[];
|
|
188
251
|
|
|
189
252
|
type ReadonlyFlowWriteSeverity = 'error' | 'warning';
|
|
190
253
|
interface ReadonlyFlowWriteFinding {
|
|
@@ -199,12 +262,12 @@ interface ReadonlyFlowWriteFinding {
|
|
|
199
262
|
}
|
|
200
263
|
declare const FLOW_UPDATE_READONLY_FIELD = "flow-update-readonly-field";
|
|
201
264
|
declare const FLOW_UPDATE_READONLY_WHEN_FIELD = "flow-update-readonly-when-field";
|
|
202
|
-
type AnyRec$
|
|
265
|
+
type AnyRec$x = Record<string, unknown>;
|
|
203
266
|
/**
|
|
204
267
|
* Validate flow `update_record` writes against target-object readonly
|
|
205
268
|
* declarations. Pure and dependency-free; safe on pre- or post-parse stacks.
|
|
206
269
|
*/
|
|
207
|
-
declare function validateReadonlyFlowWrites(stack: AnyRec$
|
|
270
|
+
declare function validateReadonlyFlowWrites(stack: AnyRec$x): ReadonlyFlowWriteFinding[];
|
|
208
271
|
|
|
209
272
|
type ViewContainerSeverity = 'error' | 'warning';
|
|
210
273
|
interface ViewContainerFinding {
|
|
@@ -241,14 +304,14 @@ declare const STYLE_CLASSNAME_TAILWIND = "style-classname-tailwind";
|
|
|
241
304
|
declare const STYLE_RESPONSIVE_NO_BASE = "style-responsive-no-base";
|
|
242
305
|
declare const STYLE_UNKNOWN_CSS_PROPERTY = "style-unknown-css-property";
|
|
243
306
|
declare const STYLE_UNKNOWN_TOKEN = "style-unknown-token";
|
|
244
|
-
type AnyRec$
|
|
307
|
+
type AnyRec$w = Record<string, unknown>;
|
|
245
308
|
/**
|
|
246
309
|
* Validate every page's component tree for SDUI styling correctness (ADR-0065).
|
|
247
310
|
* Returns findings (empty = clean). `error` findings describe styles that are
|
|
248
311
|
* silently dropped and should fail validate/build; `warning` findings are
|
|
249
312
|
* advisory (typos, drift, footguns).
|
|
250
313
|
*/
|
|
251
|
-
declare function validateResponsiveStyles(stack: AnyRec$
|
|
314
|
+
declare function validateResponsiveStyles(stack: AnyRec$w): StyleFinding[];
|
|
252
315
|
|
|
253
316
|
type JsxPageSeverity = 'error' | 'warning';
|
|
254
317
|
interface JsxPageFinding {
|
|
@@ -261,8 +324,8 @@ interface JsxPageFinding {
|
|
|
261
324
|
message: string;
|
|
262
325
|
hint: string;
|
|
263
326
|
}
|
|
264
|
-
type AnyRec$
|
|
265
|
-
declare function validateJsxPages(stack: AnyRec$
|
|
327
|
+
type AnyRec$v = Record<string, unknown>;
|
|
328
|
+
declare function validateJsxPages(stack: AnyRec$v, opts?: {
|
|
266
329
|
manifest?: Manifest;
|
|
267
330
|
}): JsxPageFinding[];
|
|
268
331
|
|
|
@@ -275,8 +338,8 @@ interface ReactPageFinding {
|
|
|
275
338
|
message: string;
|
|
276
339
|
hint: string;
|
|
277
340
|
}
|
|
278
|
-
type AnyRec$
|
|
279
|
-
declare function validateReactPages(stack: AnyRec$
|
|
341
|
+
type AnyRec$u = Record<string, unknown>;
|
|
342
|
+
declare function validateReactPages(stack: AnyRec$u): ReactPageFinding[];
|
|
280
343
|
|
|
281
344
|
type ReactPropSeverity = 'error' | 'warning';
|
|
282
345
|
interface ReactPropFinding {
|
|
@@ -287,11 +350,12 @@ interface ReactPropFinding {
|
|
|
287
350
|
message: string;
|
|
288
351
|
hint: string;
|
|
289
352
|
}
|
|
290
|
-
type AnyRec$
|
|
353
|
+
type AnyRec$t = Record<string, unknown>;
|
|
291
354
|
declare const REACT_CHART_FIELD_UNKNOWN = "react-chart-field-unknown";
|
|
292
355
|
declare const REACT_CHART_AGGREGATE_INVALID = "react-chart-aggregate-invalid";
|
|
293
356
|
declare const REACT_CHART_AXIS_UNKNOWN = "react-chart-axis-unknown";
|
|
294
|
-
declare
|
|
357
|
+
declare const REACT_BLOCK_NEEDS_RECORD_CONTEXT = "react-block-needs-record-context";
|
|
358
|
+
declare function validateReactPageProps(stack: AnyRec$t): ReactPropFinding[];
|
|
295
359
|
|
|
296
360
|
type SourceStyleSeverity = 'error' | 'warning';
|
|
297
361
|
interface SourceStyleFinding {
|
|
@@ -303,8 +367,8 @@ interface SourceStyleFinding {
|
|
|
303
367
|
hint: string;
|
|
304
368
|
}
|
|
305
369
|
declare const PAGE_SOURCE_CLASSNAME = "page-source-className-tailwind";
|
|
306
|
-
type AnyRec$
|
|
307
|
-
declare function validatePageSourceStyling(stack: AnyRec$
|
|
370
|
+
type AnyRec$s = Record<string, unknown>;
|
|
371
|
+
declare function validatePageSourceStyling(stack: AnyRec$s): SourceStyleFinding[];
|
|
308
372
|
|
|
309
373
|
/**
|
|
310
374
|
* Build-time record-title diagnostics (ADR-0079).
|
|
@@ -348,14 +412,14 @@ interface RecordTitleFinding {
|
|
|
348
412
|
/** How to fix it. */
|
|
349
413
|
hint: string;
|
|
350
414
|
}
|
|
351
|
-
type AnyRec$
|
|
415
|
+
type AnyRec$r = Record<string, unknown>;
|
|
352
416
|
/**
|
|
353
417
|
* Validate every object's record-title declaration. Returns the list of
|
|
354
418
|
* findings (empty = clean). Both rules are advisory (`warning`): the caller
|
|
355
419
|
* must never fail the build on them alone — auto-provision + the `Record #<id>`
|
|
356
420
|
* floor guarantee a resolvable title at runtime.
|
|
357
421
|
*/
|
|
358
|
-
declare function validateRecordTitle(stack: AnyRec$
|
|
422
|
+
declare function validateRecordTitle(stack: AnyRec$r): RecordTitleFinding[];
|
|
359
423
|
|
|
360
424
|
/**
|
|
361
425
|
* Build-time semantic-role diagnostics (ADR-0085).
|
|
@@ -392,13 +456,13 @@ interface SemanticRoleFinding {
|
|
|
392
456
|
/** How to fix it. */
|
|
393
457
|
hint: string;
|
|
394
458
|
}
|
|
395
|
-
type AnyRec$
|
|
459
|
+
type AnyRec$q = Record<string, unknown>;
|
|
396
460
|
/**
|
|
397
461
|
* Validate every object's semantic-role pointers. Returns the list of
|
|
398
462
|
* findings (empty = clean). Advisory only — the caller must never fail the
|
|
399
463
|
* build on these alone.
|
|
400
464
|
*/
|
|
401
|
-
declare function validateSemanticRoles(stack: AnyRec$
|
|
465
|
+
declare function validateSemanticRoles(stack: AnyRec$q): SemanticRoleFinding[];
|
|
402
466
|
|
|
403
467
|
/**
|
|
404
468
|
* Build-time form-layout diagnostics (#2578).
|
|
@@ -441,12 +505,12 @@ interface FormLayoutFinding {
|
|
|
441
505
|
/** How to fix it. */
|
|
442
506
|
hint: string;
|
|
443
507
|
}
|
|
444
|
-
type AnyRec$
|
|
508
|
+
type AnyRec$p = Record<string, unknown>;
|
|
445
509
|
/**
|
|
446
510
|
* Validate authored form-view layout. Returns findings (empty = clean).
|
|
447
511
|
* Advisory only — the caller must never fail the build on these alone.
|
|
448
512
|
*/
|
|
449
|
-
declare function validateFormLayout(stack: AnyRec$
|
|
513
|
+
declare function validateFormLayout(stack: AnyRec$p): FormLayoutFinding[];
|
|
450
514
|
|
|
451
515
|
/**
|
|
452
516
|
* Build-time conditional-visibility diagnostics (ADR-0089 D3b).
|
|
@@ -508,7 +572,7 @@ interface VisibilityFinding {
|
|
|
508
572
|
/** How to fix it. */
|
|
509
573
|
hint: string;
|
|
510
574
|
}
|
|
511
|
-
type AnyRec$
|
|
575
|
+
type AnyRec$o = Record<string, unknown>;
|
|
512
576
|
/**
|
|
513
577
|
* Validate conditional-visibility keys across authored views and pages.
|
|
514
578
|
*
|
|
@@ -523,7 +587,7 @@ type AnyRec$j = Record<string, unknown>;
|
|
|
523
587
|
* `*.view.ts` / `*.page.ts` surfaces (so a `data.`-rooted predicate is flagged). The
|
|
524
588
|
* alias-deprecated check is layer-agnostic.
|
|
525
589
|
*/
|
|
526
|
-
declare function validateVisibilityPredicates(stack: AnyRec$
|
|
590
|
+
declare function validateVisibilityPredicates(stack: AnyRec$o, opts?: VisibilityOptions): VisibilityFinding[];
|
|
527
591
|
|
|
528
592
|
declare const CAPABILITY_REFERENCE_UNKNOWN = "capability-reference-unknown";
|
|
529
593
|
type CapabilityRefSeverity = 'error' | 'warning';
|
|
@@ -541,12 +605,12 @@ interface CapabilityRefFinding {
|
|
|
541
605
|
/** How to fix it. */
|
|
542
606
|
hint: string;
|
|
543
607
|
}
|
|
544
|
-
type AnyRec$
|
|
608
|
+
type AnyRec$n = Record<string, unknown>;
|
|
545
609
|
/**
|
|
546
610
|
* Validate every capability reference in a stack. Returns findings (empty =
|
|
547
611
|
* clean). Advisory only — callers must not fail the build on these alone.
|
|
548
612
|
*/
|
|
549
|
-
declare function validateCapabilityReferences(stack: AnyRec$
|
|
613
|
+
declare function validateCapabilityReferences(stack: AnyRec$n): CapabilityRefFinding[];
|
|
550
614
|
|
|
551
615
|
declare const APPROVAL_APPROVER_NOT_MEMBERSHIP_TIER = "approval-approver-not-membership-tier";
|
|
552
616
|
declare const APPROVAL_APPROVER_TYPE_DEPRECATED = "approval-approver-type-deprecated";
|
|
@@ -571,12 +635,12 @@ interface ApprovalApproverFinding {
|
|
|
571
635
|
/** How to fix it. */
|
|
572
636
|
hint: string;
|
|
573
637
|
}
|
|
574
|
-
type AnyRec$
|
|
638
|
+
type AnyRec$m = Record<string, unknown>;
|
|
575
639
|
/**
|
|
576
640
|
* Validate the approvers of every Approval node in the stack's flows.
|
|
577
641
|
* Returns findings (empty = clean).
|
|
578
642
|
*/
|
|
579
|
-
declare function validateApprovalApprovers(stack: AnyRec$
|
|
643
|
+
declare function validateApprovalApprovers(stack: AnyRec$m): ApprovalApproverFinding[];
|
|
580
644
|
|
|
581
645
|
type SeedReplaySafetySeverity = 'error' | 'warning';
|
|
582
646
|
interface SeedReplaySafetyFinding {
|
|
@@ -590,7 +654,7 @@ interface SeedReplaySafetyFinding {
|
|
|
590
654
|
hint: string;
|
|
591
655
|
}
|
|
592
656
|
declare const SEED_INSERT_MODE_DUPLICATES_ON_REPLAY = "seed-insert-mode-duplicates-on-replay";
|
|
593
|
-
type AnyRec$
|
|
657
|
+
type AnyRec$l = Record<string, unknown>;
|
|
594
658
|
/**
|
|
595
659
|
* Flag every seed dataset declared with `mode: 'insert'` — the one non-idempotent
|
|
596
660
|
* mode, which duplicates its rows on every replay boot (framework#3434). Returns
|
|
@@ -600,7 +664,7 @@ type AnyRec$g = Record<string, unknown>;
|
|
|
600
664
|
* Reads `stack.data` (the `SeedSchema[]` fixtures). Safe on any shape — a stack
|
|
601
665
|
* with no `data` array yields no findings.
|
|
602
666
|
*/
|
|
603
|
-
declare function validateSeedReplaySafety(stack: AnyRec$
|
|
667
|
+
declare function validateSeedReplaySafety(stack: AnyRec$l): SeedReplaySafetyFinding[];
|
|
604
668
|
|
|
605
669
|
type SeedStateMachineSeverity = 'warning';
|
|
606
670
|
interface SeedStateMachineFinding {
|
|
@@ -614,7 +678,7 @@ interface SeedStateMachineFinding {
|
|
|
614
678
|
hint: string;
|
|
615
679
|
}
|
|
616
680
|
declare const SEED_VALUE_OUTSIDE_STATE_MACHINE = "seed-value-outside-state-machine";
|
|
617
|
-
type AnyRec$
|
|
681
|
+
type AnyRec$k = Record<string, unknown>;
|
|
618
682
|
/**
|
|
619
683
|
* Flag every seed record whose `state_machine`-governed field carries a value
|
|
620
684
|
* the machine does not declare (framework#3433 follow-up). Returns the findings
|
|
@@ -627,7 +691,7 @@ type AnyRec$f = Record<string, unknown>;
|
|
|
627
691
|
* unresolved `cel` Expression envelope, a number) is skipped: it cannot be
|
|
628
692
|
* statically compared to the declared-state set.
|
|
629
693
|
*/
|
|
630
|
-
declare function validateSeedStateMachine(stack: AnyRec$
|
|
694
|
+
declare function validateSeedStateMachine(stack: AnyRec$k): SeedStateMachineFinding[];
|
|
631
695
|
|
|
632
696
|
declare const SECURITY_OWD_UNSET = "security-owd-unset";
|
|
633
697
|
declare const SECURITY_OWD_ALIAS = "security-owd-alias";
|
|
@@ -654,7 +718,7 @@ interface SecurityFinding {
|
|
|
654
718
|
/** How to fix it. */
|
|
655
719
|
hint: string;
|
|
656
720
|
}
|
|
657
|
-
type AnyRec$
|
|
721
|
+
type AnyRec$j = Record<string, unknown>;
|
|
658
722
|
/**
|
|
659
723
|
* Validate the security posture of a stack. Returns findings (empty = clean).
|
|
660
724
|
* `error` findings gate the build in `os compile`; `info` is advisory.
|
|
@@ -662,7 +726,7 @@ type AnyRec$e = Record<string, unknown>;
|
|
|
662
726
|
* `opts.nowMs` injects the clock for the ADR-0091 authoring-time expiry rule
|
|
663
727
|
* (tests); production callers omit it.
|
|
664
728
|
*/
|
|
665
|
-
declare function validateSecurityPosture(stack: AnyRec$
|
|
729
|
+
declare function validateSecurityPosture(stack: AnyRec$j, opts?: {
|
|
666
730
|
nowMs?: number;
|
|
667
731
|
}): SecurityFinding[];
|
|
668
732
|
|
|
@@ -796,13 +860,13 @@ interface DashboardActionRefFinding {
|
|
|
796
860
|
/** How to fix it. */
|
|
797
861
|
hint: string;
|
|
798
862
|
}
|
|
799
|
-
type AnyRec$
|
|
863
|
+
type AnyRec$i = Record<string, unknown>;
|
|
800
864
|
/**
|
|
801
865
|
* Validate every dashboard header / widget action reference in a stack. Returns
|
|
802
866
|
* findings (empty = clean). `script`/`modal` dead targets are errors; `url`
|
|
803
867
|
* unresolved routes are warnings.
|
|
804
868
|
*/
|
|
805
|
-
declare function validateDashboardActionRefs(stack: AnyRec$
|
|
869
|
+
declare function validateDashboardActionRefs(stack: AnyRec$i): DashboardActionRefFinding[];
|
|
806
870
|
|
|
807
871
|
/**
|
|
808
872
|
* Build-time filter-placeholder diagnostics (issue #3574).
|
|
@@ -900,14 +964,208 @@ interface ObjectRefFinding {
|
|
|
900
964
|
/** How to fix it. */
|
|
901
965
|
hint: string;
|
|
902
966
|
}
|
|
903
|
-
type AnyRec$
|
|
967
|
+
type AnyRec$h = Record<string, unknown>;
|
|
904
968
|
/**
|
|
905
969
|
* Validate every object-name reference on the surfaces listed in the module
|
|
906
970
|
* header. Returns findings (empty = clean).
|
|
907
971
|
*/
|
|
908
|
-
declare function validateObjectReferences(stack: AnyRec$
|
|
972
|
+
declare function validateObjectReferences(stack: AnyRec$h): ObjectRefFinding[];
|
|
973
|
+
|
|
974
|
+
type ReferenceIntegritySeverity = 'error' | 'warning';
|
|
975
|
+
/**
|
|
976
|
+
* The shape every rule in the suite already returns. Declared here so callers
|
|
977
|
+
* can hold one type instead of a six-way union.
|
|
978
|
+
*/
|
|
979
|
+
interface ReferenceIntegrityFinding {
|
|
980
|
+
/** `error` = the reference is dead; `warning` = it may resolve elsewhere, or the miss is inert. */
|
|
981
|
+
severity: ReferenceIntegritySeverity;
|
|
982
|
+
/** Diagnostic rule id (stable; used by allowlists and docs). */
|
|
983
|
+
rule: string;
|
|
984
|
+
/** Human-readable location. */
|
|
985
|
+
where: string;
|
|
986
|
+
/** Config path. */
|
|
987
|
+
path: string;
|
|
988
|
+
/** What is wrong. */
|
|
989
|
+
message: string;
|
|
990
|
+
/** How to fix it. */
|
|
991
|
+
hint: string;
|
|
992
|
+
}
|
|
993
|
+
/** One member of the suite. `name` is the exported function's name — the id a wiring test can assert on. */
|
|
994
|
+
interface ReferenceIntegrityRule {
|
|
995
|
+
name: string;
|
|
996
|
+
run: (stack: Record<string, unknown>) => ReferenceIntegrityFinding[];
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Every reference-integrity rule, in the order their findings are reported.
|
|
1000
|
+
*
|
|
1001
|
+
* ADDING A RULE: append it here and it runs on `validate`, `lint` and
|
|
1002
|
+
* `compile` at once. Do not re-wire the commands.
|
|
1003
|
+
*/
|
|
1004
|
+
declare const REFERENCE_INTEGRITY_RULES: readonly ReferenceIntegrityRule[];
|
|
1005
|
+
/**
|
|
1006
|
+
* Run every reference-integrity rule over a stack. Returns the concatenated
|
|
1007
|
+
* findings (empty = clean). Pure: no I/O, safe on both the schema-parsed stack
|
|
1008
|
+
* and the raw/normalized config the `lint` path carries.
|
|
1009
|
+
*/
|
|
1010
|
+
declare function validateReferenceIntegrity(stack: Record<string, unknown>): ReferenceIntegrityFinding[];
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* [ADR-0072 — reference resolvability] App-navigation targets that are not
|
|
1014
|
+
* object names: `page`, `report`, `dashboard`.
|
|
1015
|
+
*
|
|
1016
|
+
* ## The hole this closes is inside an EXISTING check, not a missing one
|
|
1017
|
+
*
|
|
1018
|
+
* `defineStack`'s `validateCrossReferences` already validates these three
|
|
1019
|
+
* (`stack.zod.ts`, the "Validate app navigation → object/dashboard/page/report
|
|
1020
|
+
* references" block). But each of the three is guarded on the collection being
|
|
1021
|
+
* non-empty:
|
|
1022
|
+
*
|
|
1023
|
+
* ```ts
|
|
1024
|
+
* if (nav.type === 'page' && typeof nav.pageName === 'string'
|
|
1025
|
+
* && pageNames.size > 0 && !pageNames.has(nav.pageName)) { … }
|
|
1026
|
+
* ```
|
|
1027
|
+
*
|
|
1028
|
+
* So a stack that declares **no `pages` at all** has its page-nav check
|
|
1029
|
+
* silently switched off, and `{ type: 'page', pageName: 'anything' }` sails
|
|
1030
|
+
* through. That is precisely the state a stack is in when the target was never
|
|
1031
|
+
* written — the most likely way to get here, not the least.
|
|
1032
|
+
*
|
|
1033
|
+
* Note the asymmetry the guard creates. The `object` arm of the same block has
|
|
1034
|
+
* no size gate: it errors unless the item carries `requiresObject`, an
|
|
1035
|
+
* EXPLICIT opt-in to "another package provides this". Objects therefore say so
|
|
1036
|
+
* out loud; pages, reports and dashboards get an implicit exemption that
|
|
1037
|
+
* depends on an unrelated property of the stack.
|
|
1038
|
+
*
|
|
1039
|
+
* This rule restores the coverage with the ADR-0072 severity posture rather
|
|
1040
|
+
* than by tightening the parse-time throw — a throw has no escape hatch for a
|
|
1041
|
+
* legitimately cross-package page, and ADR-0072 D1's rule is that one dead
|
|
1042
|
+
* finding costs more than a missed one.
|
|
1043
|
+
*
|
|
1044
|
+
* ## Severity: warning, and why it is not error
|
|
1045
|
+
*
|
|
1046
|
+
* `validate-object-references` can say ERROR for an unresolved *object*
|
|
1047
|
+
* because it resolves against a curated `PLATFORM_PROVIDED_OBJECT_NAMES`
|
|
1048
|
+
* registry — it knows which cross-package names are real. No such registry
|
|
1049
|
+
* exists for pages, reports or dashboards, so "unresolved" genuinely cannot be
|
|
1050
|
+
* distinguished from "provided by a package we cannot see from here".
|
|
1051
|
+
* Advisory is the honest ceiling. When `defineStack`'s own check is live (the
|
|
1052
|
+
* collection is non-empty) it still hard-fails first; this rule is what speaks
|
|
1053
|
+
* when that check has switched itself off.
|
|
1054
|
+
*
|
|
1055
|
+
* ## Deliberately NOT covered — each verified, not assumed
|
|
1056
|
+
*
|
|
1057
|
+
* - **`action`** (`actionDef.actionName`) — already owned by
|
|
1058
|
+
* `validate-action-name-refs`, which walks app navigation explicitly. Adding
|
|
1059
|
+
* it here would double-report the same finding.
|
|
1060
|
+
* - **`component`** (`componentRef`) — verified a NON-rule. An unregistered ref
|
|
1061
|
+
* does NOT fail silently: `ComponentNavView` renders a named diagnostic
|
|
1062
|
+
* ("Component not registered … Ensure the plugin that provides this surface
|
|
1063
|
+
* is installed and has called `registerAppComponent()`"), and the registry
|
|
1064
|
+
* exists precisely so plugin-provided surfaces may legitimately be absent.
|
|
1065
|
+
* Flagging it would break valid plugin nav and prescribe a fix for something
|
|
1066
|
+
* already reported better at runtime.
|
|
1067
|
+
* - **`url`** — external by definition; nothing to resolve against.
|
|
1068
|
+
*/
|
|
1069
|
+
|
|
1070
|
+
type NavTargetRefSeverity = 'error' | 'warning';
|
|
1071
|
+
type NavTargetRefFinding = ReferenceIntegrityFinding;
|
|
1072
|
+
/** Emitted when a nav item targets a page/report/dashboard the stack cannot resolve. */
|
|
1073
|
+
declare const NAV_TARGET_UNRESOLVED = "nav-target-unresolved";
|
|
1074
|
+
declare function validateNavTargetRefs(stack: unknown): NavTargetRefFinding[];
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* [ADR-0061 — searchable set] `searchableFields` entries must name a field the
|
|
1078
|
+
* object actually has — and, on a list view, one the runtime will agree to scan.
|
|
1079
|
+
*
|
|
1080
|
+
* `searchableFields` is `z.array(z.string())` in both `object.zod.ts` and the
|
|
1081
|
+
* list-view schema, so nothing checks that an entry resolves to anything. Rename
|
|
1082
|
+
* a field and the old name stays behind: Zod-valid, shipped, and pointing at a
|
|
1083
|
+
* column that no longer exists.
|
|
1084
|
+
*
|
|
1085
|
+
* ── Why a stale entry is not merely inert ────────────────────────────────
|
|
1086
|
+
*
|
|
1087
|
+
* The engine tolerates it. `resolveSearchFields` (`@objectstack/objectql`)
|
|
1088
|
+
* filters the declaration down to fields that exist —
|
|
1089
|
+
* `searchableFields?.filter((f) => all[f])` — so a stale name is dropped
|
|
1090
|
+
* without a word. That tolerance is what makes the drift invisible, and it
|
|
1091
|
+
* fails in the direction nobody expects:
|
|
1092
|
+
*
|
|
1093
|
+
* - Some entries stale → `$search` quietly scans a NARROWER set than the
|
|
1094
|
+
* object declares. Records that should match do not, and the response is
|
|
1095
|
+
* indistinguishable from "no such record".
|
|
1096
|
+
* - EVERY entry stale → the filtered set is empty, so resolution falls
|
|
1097
|
+
* through to the AUTO-DEFAULT (name/title + short-text fields). A
|
|
1098
|
+
* declaration whose entire purpose is to CHOOSE the searchable set ends up
|
|
1099
|
+
* selecting a set the author never wrote — the same "asked narrower,
|
|
1100
|
+
* answered wider" inversion #4226 closed on the projection axis.
|
|
1101
|
+
*
|
|
1102
|
+
* And it does not stay quiet downstream. objectui's list search echoes
|
|
1103
|
+
* `schema.searchableFields` verbatim as the `$searchFields` override, so once
|
|
1104
|
+
* the REST read path validates that override against the object (#4254), a
|
|
1105
|
+
* stale declaration the engine had been silently skipping becomes a `400
|
|
1106
|
+
* INVALID_FIELD` on every list search for that object — a request-time break
|
|
1107
|
+
* whose cause is an authoring typo made long before.
|
|
1108
|
+
*
|
|
1109
|
+
* Hence `error`, not the advisory level the other field-existence rules use
|
|
1110
|
+
* (`page-field-unknown`, `form-field-unknown`, `semantic-role-field-unknown`
|
|
1111
|
+
* are all warnings). Those describe a consumer that SKIPS an unknown name and
|
|
1112
|
+
* renders the rest; this one describes a declaration that either selects the
|
|
1113
|
+
* wrong set or refuses the request outright. It is the same call
|
|
1114
|
+
* `validate-flow-template-paths` makes for a filter-position token: gating when
|
|
1115
|
+
* the miss widens the query rather than shrinking the page.
|
|
1116
|
+
*
|
|
1117
|
+
* ── What is checked ──────────────────────────────────────────────────────
|
|
1118
|
+
*
|
|
1119
|
+
* 1. EXISTENCE, on every surface (`searchable-field-unknown`): an entry that
|
|
1120
|
+
* resolves to no field at all is drift, whatever declared it.
|
|
1121
|
+
*
|
|
1122
|
+
* 2. RUNTIME ADMISSIBILITY, on view-level narrowings only
|
|
1123
|
+
* (`searchable-field-unsearchable`, #4830): a list view's
|
|
1124
|
+
* `searchableFields` is echoed verbatim by clients as the `$searchFields`
|
|
1125
|
+
* override, and the #4254 ingress gate
|
|
1126
|
+
* (`assertSearchFieldsAreSearchable`, `@objectstack/metadata-protocol`)
|
|
1127
|
+
* refuses any entry outside the object's server-resolved allowed set — so
|
|
1128
|
+
* ONE lookup-typed entry 400s EVERY toolbar search on that list, for every
|
|
1129
|
+
* role, and until #4830 `compile`/`validate` passed it in silence. The
|
|
1130
|
+
* allowed set here is computed by the very function the runtime gate and
|
|
1131
|
+
* the engine consult — {@link resolveSearchFieldResolution}
|
|
1132
|
+
* (`@objectstack/spec/data`) — never by a second copy of its type list, so
|
|
1133
|
+
* linter, gate and engine cannot drift apart (the same one-source move
|
|
1134
|
+
* #4254 made between gate and engine).
|
|
1135
|
+
*
|
|
1136
|
+
* The OBJECT's own `searchableFields` stays existence-only: the runtime's
|
|
1137
|
+
* declared branch filters by existence, never by type, so a json or lookup
|
|
1138
|
+
* column declared THERE is a choice the engine executes (a `$contains` over
|
|
1139
|
+
* the raw column), not a 400. Flagging it would reject metadata the runtime
|
|
1140
|
+
* accepts — the false finding that makes authors stop trusting the linter
|
|
1141
|
+
* (ADR-0072 D1).
|
|
1142
|
+
*
|
|
1143
|
+
* Three skips keep false positives near zero (ADR-0072 D1):
|
|
1144
|
+
*
|
|
1145
|
+
* 1. An object this stack does not define. It may come from another package,
|
|
1146
|
+
* and a field map we cannot see cannot be judged (the same skip the
|
|
1147
|
+
* page/flow/widget rules take).
|
|
1148
|
+
* 2. An object that declares no field map at all — external objects and
|
|
1149
|
+
* datasource-introspected schemas whose columns are resolved at runtime.
|
|
1150
|
+
* 3. Registry-injected system columns, which exist at runtime but never
|
|
1151
|
+
* appear in authored `fields` — the package-shared `SYSTEM_FIELDS`
|
|
1152
|
+
* (`system-fields.ts`), derived from the spec's own declarations rather
|
|
1153
|
+
* than hand-copied (#4330). The admissibility check also skips them:
|
|
1154
|
+
* their runtime field metadata (type, hidden) is registry-owned and not
|
|
1155
|
+
* visible here, and judging a column we cannot see risks the false
|
|
1156
|
+
* positive this list exists to avoid. (Cost asymmetry: a system column
|
|
1157
|
+
* the runtime would refuse — `created_by` in a view's narrowing — is a
|
|
1158
|
+
* missed finding, not a wrong one.)
|
|
1159
|
+
*
|
|
1160
|
+
* Dotted paths are NOT skipped here, unlike every sibling rule. Elsewhere
|
|
1161
|
+
* `owner_id.name` is left alone because the query engine resolves the traversal;
|
|
1162
|
+
* search does not — `resolveSearchFields` matches the field map by exact string,
|
|
1163
|
+
* so a dotted entry is dropped exactly like a typo. Skipping it would exempt the
|
|
1164
|
+
* one wrong spelling most likely to be borrowed from `select`/`sort`.
|
|
1165
|
+
*/
|
|
909
1166
|
|
|
910
1167
|
declare const SEARCHABLE_FIELD_UNKNOWN = "searchable-field-unknown";
|
|
1168
|
+
declare const SEARCHABLE_FIELD_UNSEARCHABLE = "searchable-field-unsearchable";
|
|
911
1169
|
type SearchableFieldSeverity = 'error' | 'warning';
|
|
912
1170
|
interface SearchableFieldFinding {
|
|
913
1171
|
/** Always `error` — a stale entry narrows, widens or refuses the search (see module note). */
|
|
@@ -923,7 +1181,19 @@ interface SearchableFieldFinding {
|
|
|
923
1181
|
/** How to fix it. */
|
|
924
1182
|
hint: string;
|
|
925
1183
|
}
|
|
926
|
-
|
|
1184
|
+
/**
|
|
1185
|
+
* Which runtime judgment applies to the declaration being checked:
|
|
1186
|
+
*
|
|
1187
|
+
* - `'canonical'` — the object's own `searchableFields`. The runtime honors
|
|
1188
|
+
* any entry that exists (existence-filtered, never type-filtered), so only
|
|
1189
|
+
* existence is checked.
|
|
1190
|
+
* - `'narrowing'` — a list view's `searchableFields` (metadata or react
|
|
1191
|
+
* surface). Clients echo it as the `$searchFields` override, which the
|
|
1192
|
+
* #4254 ingress gate intersects with the object's allowed set — entries the
|
|
1193
|
+
* runtime would refuse are flagged (#4830).
|
|
1194
|
+
*/
|
|
1195
|
+
type SearchableFieldRole = 'canonical' | 'narrowing';
|
|
1196
|
+
type AnyRec$g = Record<string, unknown>;
|
|
927
1197
|
/**
|
|
928
1198
|
* Validate every `searchableFields` declaration in the stack — the object's own
|
|
929
1199
|
* (the canonical set, ADR-0061) and the list views that narrow it. Returns
|
|
@@ -934,7 +1204,7 @@ type AnyRec$b = Record<string, unknown>;
|
|
|
934
1204
|
* `validate-react-page-props` — the gate that already parses that source —
|
|
935
1205
|
* runs the same `checkSearchableFieldList` core on it (#4329).
|
|
936
1206
|
*/
|
|
937
|
-
declare function validateSearchableFields(stack: AnyRec$
|
|
1207
|
+
declare function validateSearchableFields(stack: AnyRec$g): SearchableFieldFinding[];
|
|
938
1208
|
|
|
939
1209
|
declare const ACTION_NAME_UNDEFINED = "action-name-undefined";
|
|
940
1210
|
type ActionNameRefSeverity = 'error' | 'warning';
|
|
@@ -952,12 +1222,84 @@ interface ActionNameRefFinding {
|
|
|
952
1222
|
/** How to fix it. */
|
|
953
1223
|
hint: string;
|
|
954
1224
|
}
|
|
955
|
-
type AnyRec$
|
|
1225
|
+
type AnyRec$f = Record<string, unknown>;
|
|
956
1226
|
/**
|
|
957
1227
|
* Validate every name-bound action reference in a stack. Returns findings
|
|
958
1228
|
* (empty = clean).
|
|
959
1229
|
*/
|
|
960
|
-
declare function validateActionNameRefs(stack: AnyRec$
|
|
1230
|
+
declare function validateActionNameRefs(stack: AnyRec$f): ActionNameRefFinding[];
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* [ADR-0078 Phase 3 — Tier-A `action-locations`] An action nobody placed.
|
|
1234
|
+
*
|
|
1235
|
+
* `locations` is an action's placement declaration. An action that omits it —
|
|
1236
|
+
* and that no view names in `bulkActions` / `bulkActionDefs` / `rowActions` —
|
|
1237
|
+
* has no surface at all: it parses, it publishes, Setup lists it, and no user
|
|
1238
|
+
* can ever click it. ADR-0078 names this shape in its opening paragraph ("a
|
|
1239
|
+
* `summary` with no `summaryOperations`; **an `action` with no `locations`**;
|
|
1240
|
+
* … Each parses, 'renders', reports success — and does nothing") and Phase 3
|
|
1241
|
+
* asks for exactly this rule, one verified shape at a time.
|
|
1242
|
+
*
|
|
1243
|
+
* The renderer half is now unambiguous: objectui#3142 collapsed four
|
|
1244
|
+
* disagreeing renderers onto one predicate — an action renders at a location
|
|
1245
|
+
* only if it DECLARES that location. Before that, `action:bar` and the record
|
|
1246
|
+
* header showed an undeclared action *everywhere*, which is what made this
|
|
1247
|
+
* shape look alive; it is measurably inert as of objectui 17.1.
|
|
1248
|
+
*
|
|
1249
|
+
* ## What is NOT flagged, and why
|
|
1250
|
+
*
|
|
1251
|
+
* **`locations: []` — a deliberate headless action.** `content/docs/ui/
|
|
1252
|
+
* actions.mdx` ("Headless actions: declare it, then hide it") documents the
|
|
1253
|
+
* empty array as a first-class shape: the action stays callable over REST /
|
|
1254
|
+
* MCP / AI and keeps its capability gate, param contract and audit trail,
|
|
1255
|
+
* while claiming no UI surface. ADR-0110 D3 refuses an *undeclared* handler,
|
|
1256
|
+
* so a headless declaration is the only legal way to expose such an action —
|
|
1257
|
+
* flagging it would fight that ADR. The distinction this rule draws is
|
|
1258
|
+
* therefore between an author who said "nowhere, deliberately" (`[]`) and one
|
|
1259
|
+
* who never said anything at all (key absent).
|
|
1260
|
+
*
|
|
1261
|
+
* **Actions a view places by NAME.** Naming an action in a list view's
|
|
1262
|
+
* `bulkActions` or `bulkActionDefs` IS its placement — the selection bar is
|
|
1263
|
+
* driven by the view, never by `locations` (that is what the retired
|
|
1264
|
+
* `action.bulkEnabled` tombstone prescribes, and what objectui#3139's
|
|
1265
|
+
* aggregate bulk mode relies on: an action that only makes sense over a
|
|
1266
|
+
* selection has no single-record location by construction). `rowActions` is
|
|
1267
|
+
* exempted on the same zero-false-positive posture (ADR-0072 D1): it is the
|
|
1268
|
+
* same field pair on the same container, and an author who named an action
|
|
1269
|
+
* there has stated an intent — a name that resolves to nothing is already
|
|
1270
|
+
* `action-name-undefined`'s job, not this rule's.
|
|
1271
|
+
*
|
|
1272
|
+
* Scope note: this rule asks only "did anyone place this action?". It
|
|
1273
|
+
* deliberately does NOT check that a declared location is one a renderer
|
|
1274
|
+
* actually serves, nor that a view's named action belongs to that view's
|
|
1275
|
+
* object — distinct classes with their own rules. Cross-package placement (a
|
|
1276
|
+
* view in another installed package naming this action) is the one legitimate
|
|
1277
|
+
* miss, which is why this is a **warning**: like every other "declared but
|
|
1278
|
+
* does nothing" finding in this package (`validateSemanticRoles`,
|
|
1279
|
+
* `lintLivenessProperties`), it is high-signal and never fatal.
|
|
1280
|
+
*/
|
|
1281
|
+
declare const ACTION_NO_PLACEMENT = "action-no-placement";
|
|
1282
|
+
type ActionLocationsSeverity = 'error' | 'warning';
|
|
1283
|
+
interface ActionLocationsFinding {
|
|
1284
|
+
/** Always `warning` — cross-package placement is a legitimate miss. */
|
|
1285
|
+
severity: ActionLocationsSeverity;
|
|
1286
|
+
/** Diagnostic rule id. */
|
|
1287
|
+
rule: string;
|
|
1288
|
+
/** Human-readable location, e.g. `action "crm_convert_lead"`. */
|
|
1289
|
+
where: string;
|
|
1290
|
+
/** Config path, e.g. `actions[2]` or `objects[0].actions[1]`. */
|
|
1291
|
+
path: string;
|
|
1292
|
+
/** What is wrong. */
|
|
1293
|
+
message: string;
|
|
1294
|
+
/** How to fix it. */
|
|
1295
|
+
hint: string;
|
|
1296
|
+
}
|
|
1297
|
+
type AnyRec$e = Record<string, unknown>;
|
|
1298
|
+
/**
|
|
1299
|
+
* Flag every action that declares no placement and that no view places by
|
|
1300
|
+
* name. Returns findings (empty = clean).
|
|
1301
|
+
*/
|
|
1302
|
+
declare function validateActionLocations(stack: AnyRec$e): ActionLocationsFinding[];
|
|
961
1303
|
|
|
962
1304
|
/**
|
|
963
1305
|
* Shared page-component traversal for the lint rules that inspect
|
|
@@ -983,7 +1325,7 @@ declare function validateActionNameRefs(stack: AnyRec$a): ActionNameRefFinding[]
|
|
|
983
1325
|
* author never wrote, so those pages are skipped here and covered by
|
|
984
1326
|
* `validate-jsx-pages` / `validate-react-page-props` instead.
|
|
985
1327
|
*/
|
|
986
|
-
type AnyRec$
|
|
1328
|
+
type AnyRec$d = Record<string, unknown>;
|
|
987
1329
|
|
|
988
1330
|
/**
|
|
989
1331
|
* [ADR-0078 — completeness] Field-reference integrity for page components
|
|
@@ -1057,7 +1399,7 @@ interface PageFieldFinding {
|
|
|
1057
1399
|
hint: string;
|
|
1058
1400
|
}
|
|
1059
1401
|
|
|
1060
|
-
declare function validatePageFieldBindings(stack: AnyRec$
|
|
1402
|
+
declare function validatePageFieldBindings(stack: AnyRec$d): PageFieldFinding[];
|
|
1061
1403
|
|
|
1062
1404
|
/**
|
|
1063
1405
|
* [ADR-0021 — semantic layer] Chart-binding integrity for the surfaces the
|
|
@@ -1114,7 +1456,7 @@ interface ChartBindingFinding {
|
|
|
1114
1456
|
hint: string;
|
|
1115
1457
|
}
|
|
1116
1458
|
|
|
1117
|
-
declare function validateChartBindings(stack: AnyRec$
|
|
1459
|
+
declare function validateChartBindings(stack: AnyRec$d): ChartBindingFinding[];
|
|
1118
1460
|
|
|
1119
1461
|
declare const NAV_OBJECT_UNGRANTED = "nav-object-ungranted";
|
|
1120
1462
|
type NavAccessSeverity = 'error' | 'warning';
|
|
@@ -1132,12 +1474,12 @@ interface NavAccessFinding {
|
|
|
1132
1474
|
/** How to fix it. */
|
|
1133
1475
|
hint: string;
|
|
1134
1476
|
}
|
|
1135
|
-
type AnyRec$
|
|
1477
|
+
type AnyRec$c = Record<string, unknown>;
|
|
1136
1478
|
/**
|
|
1137
1479
|
* Validate that every object a stack's navigation exposes is readable by at
|
|
1138
1480
|
* least one permission set the stack declares. Returns findings (empty = clean).
|
|
1139
1481
|
*/
|
|
1140
|
-
declare function validateNavAccess(stack: AnyRec$
|
|
1482
|
+
declare function validateNavAccess(stack: AnyRec$c): NavAccessFinding[];
|
|
1141
1483
|
|
|
1142
1484
|
declare const TRANSLATION_TARGET_UNKNOWN = "translation-target-unknown";
|
|
1143
1485
|
declare const TRANSLATION_OPTION_KEY_UNKNOWN = "translation-option-key-unknown";
|
|
@@ -1156,12 +1498,12 @@ interface TranslationRefFinding {
|
|
|
1156
1498
|
/** How to fix it. */
|
|
1157
1499
|
hint: string;
|
|
1158
1500
|
}
|
|
1159
|
-
type AnyRec$
|
|
1501
|
+
type AnyRec$b = Record<string, unknown>;
|
|
1160
1502
|
/**
|
|
1161
1503
|
* Validate every reference a translation bundle makes against the metadata it
|
|
1162
1504
|
* claims to translate. Returns findings (empty = clean).
|
|
1163
1505
|
*/
|
|
1164
|
-
declare function validateTranslationReferences(stack: AnyRec$
|
|
1506
|
+
declare function validateTranslationReferences(stack: AnyRec$b): TranslationRefFinding[];
|
|
1165
1507
|
|
|
1166
1508
|
/**
|
|
1167
1509
|
* [ADR-0064 §3] Skill ↔ agent surface affinity (issue #3820).
|
|
@@ -1206,12 +1548,12 @@ interface AiSurfaceAffinityFinding {
|
|
|
1206
1548
|
/** How to fix it. */
|
|
1207
1549
|
hint: string;
|
|
1208
1550
|
}
|
|
1209
|
-
type AnyRec$
|
|
1551
|
+
type AnyRec$a = Record<string, unknown>;
|
|
1210
1552
|
/**
|
|
1211
1553
|
* Validate every in-stack agent→skill binding against the ADR-0064 §3 surface
|
|
1212
1554
|
* affinity contract. Returns findings (empty = clean).
|
|
1213
1555
|
*/
|
|
1214
|
-
declare function validateAiSurfaceAffinity(stack: AnyRec$
|
|
1556
|
+
declare function validateAiSurfaceAffinity(stack: AnyRec$a): AiSurfaceAffinityFinding[];
|
|
1215
1557
|
|
|
1216
1558
|
declare const AI_SKILL_TOOL_UNRESOLVED = "ai-skill-tool-unresolved";
|
|
1217
1559
|
type AiToolRefSeverity = 'error' | 'warning';
|
|
@@ -1229,12 +1571,12 @@ interface AiToolRefFinding {
|
|
|
1229
1571
|
/** How to fix it. */
|
|
1230
1572
|
hint: string;
|
|
1231
1573
|
}
|
|
1232
|
-
type AnyRec$
|
|
1574
|
+
type AnyRec$9 = Record<string, unknown>;
|
|
1233
1575
|
/**
|
|
1234
1576
|
* Validate every `skill.tools[]` reference in a stack. Returns findings
|
|
1235
1577
|
* (empty = clean).
|
|
1236
1578
|
*/
|
|
1237
|
-
declare function validateAiToolReferences(stack: AnyRec$
|
|
1579
|
+
declare function validateAiToolReferences(stack: AnyRec$9): AiToolRefFinding[];
|
|
1238
1580
|
|
|
1239
1581
|
/**
|
|
1240
1582
|
* [ADR-0063 §2] `stack.agents` is a platform-internal slot (issue #3820).
|
|
@@ -1279,12 +1621,12 @@ interface AiAgentAuthoringFinding {
|
|
|
1279
1621
|
/** How to fix it. */
|
|
1280
1622
|
hint: string;
|
|
1281
1623
|
}
|
|
1282
|
-
type AnyRec$
|
|
1624
|
+
type AnyRec$8 = Record<string, unknown>;
|
|
1283
1625
|
/**
|
|
1284
1626
|
* Flag every agent declared in a stack. Returns findings (empty = clean,
|
|
1285
1627
|
* which is what every app package should be).
|
|
1286
1628
|
*/
|
|
1287
|
-
declare function validateAiAgentAuthoring(stack: AnyRec$
|
|
1629
|
+
declare function validateAiAgentAuthoring(stack: AnyRec$8): AiAgentAuthoringFinding[];
|
|
1288
1630
|
|
|
1289
1631
|
type HookBodyWriteSeverity = 'warning';
|
|
1290
1632
|
interface HookBodyWriteFinding {
|
|
@@ -1336,7 +1678,7 @@ interface BodyWritePatternExclusion {
|
|
|
1336
1678
|
declare const HOOK_BODY_WRITE_PATTERN_IDS: readonly string[];
|
|
1337
1679
|
/** Ledger shapes this rule leaves alone, each with its reason. */
|
|
1338
1680
|
declare const HOOK_BODY_WRITE_EXCLUSIONS: readonly BodyWritePatternExclusion[];
|
|
1339
|
-
type AnyRec$
|
|
1681
|
+
type AnyRec$7 = Record<string, unknown>;
|
|
1340
1682
|
/** One statically-extracted field write found in an L2 body. */
|
|
1341
1683
|
interface ExtractedHookBodyWrite {
|
|
1342
1684
|
/** Which {@link HOOK_BODY_WRITE_PATTERNS} entry matched. */
|
|
@@ -1381,7 +1723,7 @@ declare function extractHookBodyWriteSet(source: string): ExtractedHookBodyWrite
|
|
|
1381
1723
|
* Validate L2 hook-body writes against target-object field declarations.
|
|
1382
1724
|
* Pure `(stack) => Finding[]` (ADR-0019); safe on pre- or post-parse stacks.
|
|
1383
1725
|
*/
|
|
1384
|
-
declare function validateHookBodyWrites(stack: AnyRec$
|
|
1726
|
+
declare function validateHookBodyWrites(stack: AnyRec$7): HookBodyWriteFinding[];
|
|
1385
1727
|
|
|
1386
1728
|
type ActionBodyWriteSeverity = 'warning';
|
|
1387
1729
|
interface ActionBodyWriteFinding {
|
|
@@ -1423,12 +1765,12 @@ declare const ACTION_BODY_WRITE_EXCLUSIONS: readonly BodyWritePatternExclusion[]
|
|
|
1423
1765
|
declare const ACTION_BODY_WRITE_PATTERNS: readonly HookBodyWritePattern[];
|
|
1424
1766
|
/** The subset the discarded-record-write check sees. */
|
|
1425
1767
|
declare const ACTION_RECORD_WRITE_PATTERNS: readonly HookBodyWritePattern[];
|
|
1426
|
-
type AnyRec$
|
|
1768
|
+
type AnyRec$6 = Record<string, unknown>;
|
|
1427
1769
|
/**
|
|
1428
1770
|
* Validate L2 action-body writes against target-object field declarations.
|
|
1429
1771
|
* Pure `(stack) => Finding[]` (ADR-0019); safe on pre- or post-parse stacks.
|
|
1430
1772
|
*/
|
|
1431
|
-
declare function validateActionBodyWrites(stack: AnyRec$
|
|
1773
|
+
declare function validateActionBodyWrites(stack: AnyRec$6): ActionBodyWriteFinding[];
|
|
1432
1774
|
|
|
1433
1775
|
type FlowNodeWriteSeverity = 'error';
|
|
1434
1776
|
interface FlowNodeWriteFinding {
|
|
@@ -1468,51 +1810,13 @@ interface FlowWriteNodeDeferral {
|
|
|
1468
1810
|
* Deleting this array would turn that forced decision back into a default.
|
|
1469
1811
|
*/
|
|
1470
1812
|
declare const FLOW_WRITE_NODE_TYPES_DEFERRED: readonly FlowWriteNodeDeferral[];
|
|
1471
|
-
type AnyRec$
|
|
1813
|
+
type AnyRec$5 = Record<string, unknown>;
|
|
1472
1814
|
/**
|
|
1473
1815
|
* Validate flow write-node `fields` keys against the target object's declared
|
|
1474
1816
|
* fields. Pure `(stack) => Finding[]` (ADR-0019); safe on pre- or post-parse
|
|
1475
1817
|
* stacks.
|
|
1476
1818
|
*/
|
|
1477
|
-
declare function validateFlowNodeWrites(stack: AnyRec$
|
|
1478
|
-
|
|
1479
|
-
type ReferenceIntegritySeverity = 'error' | 'warning';
|
|
1480
|
-
/**
|
|
1481
|
-
* The shape every rule in the suite already returns. Declared here so callers
|
|
1482
|
-
* can hold one type instead of a six-way union.
|
|
1483
|
-
*/
|
|
1484
|
-
interface ReferenceIntegrityFinding {
|
|
1485
|
-
/** `error` = the reference is dead; `warning` = it may resolve elsewhere, or the miss is inert. */
|
|
1486
|
-
severity: ReferenceIntegritySeverity;
|
|
1487
|
-
/** Diagnostic rule id (stable; used by allowlists and docs). */
|
|
1488
|
-
rule: string;
|
|
1489
|
-
/** Human-readable location. */
|
|
1490
|
-
where: string;
|
|
1491
|
-
/** Config path. */
|
|
1492
|
-
path: string;
|
|
1493
|
-
/** What is wrong. */
|
|
1494
|
-
message: string;
|
|
1495
|
-
/** How to fix it. */
|
|
1496
|
-
hint: string;
|
|
1497
|
-
}
|
|
1498
|
-
/** One member of the suite. `name` is the exported function's name — the id a wiring test can assert on. */
|
|
1499
|
-
interface ReferenceIntegrityRule {
|
|
1500
|
-
name: string;
|
|
1501
|
-
run: (stack: Record<string, unknown>) => ReferenceIntegrityFinding[];
|
|
1502
|
-
}
|
|
1503
|
-
/**
|
|
1504
|
-
* Every reference-integrity rule, in the order their findings are reported.
|
|
1505
|
-
*
|
|
1506
|
-
* ADDING A RULE: append it here and it runs on `validate`, `lint` and
|
|
1507
|
-
* `compile` at once. Do not re-wire the commands.
|
|
1508
|
-
*/
|
|
1509
|
-
declare const REFERENCE_INTEGRITY_RULES: readonly ReferenceIntegrityRule[];
|
|
1510
|
-
/**
|
|
1511
|
-
* Run every reference-integrity rule over a stack. Returns the concatenated
|
|
1512
|
-
* findings (empty = clean). Pure: no I/O, safe on both the schema-parsed stack
|
|
1513
|
-
* and the raw/normalized config the `lint` path carries.
|
|
1514
|
-
*/
|
|
1515
|
-
declare function validateReferenceIntegrity(stack: Record<string, unknown>): ReferenceIntegrityFinding[];
|
|
1819
|
+
declare function validateFlowNodeWrites(stack: AnyRec$5): FlowNodeWriteFinding[];
|
|
1516
1820
|
|
|
1517
1821
|
/**
|
|
1518
1822
|
* [ADR-0090 D6] Access-matrix snapshot — authoring-time companion to the
|
|
@@ -1529,13 +1833,211 @@ declare function validateReferenceIntegrity(stack: Record<string, unknown>): Ref
|
|
|
1529
1833
|
* AI may draft grants freely; it cannot silently change who can do what.
|
|
1530
1834
|
*/
|
|
1531
1835
|
|
|
1532
|
-
type AnyRec = Record<string, unknown>;
|
|
1836
|
+
type AnyRec$4 = Record<string, unknown>;
|
|
1533
1837
|
/** Build the sorted access matrix for a normalized stack. */
|
|
1534
|
-
declare function buildAccessMatrix(stack: AnyRec): AccessMatrix;
|
|
1838
|
+
declare function buildAccessMatrix(stack: AnyRec$4): AccessMatrix;
|
|
1535
1839
|
/**
|
|
1536
1840
|
* Semantic diff between two matrices — human-review lines, empty = identical.
|
|
1537
1841
|
* Ordered: removals, additions, then per-entry bit/scope changes.
|
|
1538
1842
|
*/
|
|
1539
1843
|
declare function diffAccessMatrix(before: AccessMatrix, after: AccessMatrix): string[];
|
|
1540
1844
|
|
|
1541
|
-
|
|
1845
|
+
/**
|
|
1846
|
+
* Build-time lint for flow authoring ANTI-PATTERNS — metadata that is valid
|
|
1847
|
+
* (passes schema + expression checks) but is semantically a footgun at runtime.
|
|
1848
|
+
* Most are emitted as WARNINGS: they guide the author (very often an AI
|
|
1849
|
+
* generating templates) toward the robust pattern without failing the build on
|
|
1850
|
+
* a technically-legal construct.
|
|
1851
|
+
*
|
|
1852
|
+
* A finding carrying `severity: 'error'` FAILS the build. The bar is: **no
|
|
1853
|
+
* reading of the author's metadata does what it says, deterministically, on
|
|
1854
|
+
* every run.** Warning about such a shape is just a slower way of finding out.
|
|
1855
|
+
* That covers two kinds, and only these:
|
|
1856
|
+
*
|
|
1857
|
+
* - **The runtime refuses.** {@link FLOW_RUNAS_UNSCOPED} — a user-less trigger
|
|
1858
|
+
* with `runAs:'user'` has no identity to scope to, so the data operation is
|
|
1859
|
+
* refused outright (#3760).
|
|
1860
|
+
* - **The declaration is inert and the route silently differs from what is
|
|
1861
|
+
* written.** {@link FLOW_BRANCH_LABEL_UNMATCHED} — a decision computes a
|
|
1862
|
+
* branch no out-edge carries, so the branch is discarded and every out-edge
|
|
1863
|
+
* is considered instead. {@link FLOW_DEFAULT_EDGE_WITH_CONDITION} — an edge
|
|
1864
|
+
* that is both the default and conditional; the condition wins and the
|
|
1865
|
+
* marker routes nothing. Neither *fails*; both are wrong every time, and
|
|
1866
|
+
* silently, which is worse (#4414).
|
|
1867
|
+
*
|
|
1868
|
+
* The bar is deliberately about *provability*, not severity of consequence. A
|
|
1869
|
+
* shape with a legitimate reading stays a warning even when it is usually a
|
|
1870
|
+
* mistake — {@link FLOW_DECISION_UNCONDITIONAL_BRANCH} is normally a guard that
|
|
1871
|
+
* does not guard, but a decision with one guarded and one unconditional out-edge
|
|
1872
|
+
* is a legal "maybe notify, always continue" fan-out, and
|
|
1873
|
+
* {@link FLOW_MULTIPLE_DEFAULT_EDGES} can genuinely mean "when nothing matched,
|
|
1874
|
+
* do both". Failing a customer's build on a shape we cannot prove wrong is a
|
|
1875
|
+
* worse trade than letting the warning be ignored.
|
|
1876
|
+
*
|
|
1877
|
+
* #1874 — time-relative rules via record-change date-EQUALITY. A start-node
|
|
1878
|
+
* trigger condition like `end_date == daysFromNow(60)` on a `record-*` trigger
|
|
1879
|
+
* only fires if the record happens to be written on that exact day; the robust
|
|
1880
|
+
* shape is a daily SCHEDULE trigger + a range query. We flag the equality form
|
|
1881
|
+
* specifically (range operators `>=`/`<=` are not flagged — they're the building
|
|
1882
|
+
* block of the correct pattern), keeping false positives near zero.
|
|
1883
|
+
*/
|
|
1884
|
+
interface FlowLintFinding {
|
|
1885
|
+
where: string;
|
|
1886
|
+
message: string;
|
|
1887
|
+
hint: string;
|
|
1888
|
+
rule: string;
|
|
1889
|
+
/**
|
|
1890
|
+
* `'error'` FAILS the build; `'warning'` (the default when absent) prints and
|
|
1891
|
+
* continues. Most rules here flag a technically-legal footgun and stay
|
|
1892
|
+
* advisory. A rule is only promoted to `'error'` when the shape it flags is a
|
|
1893
|
+
* *guaranteed* runtime failure — then a warning would just be a slower way of
|
|
1894
|
+
* finding out (#3760).
|
|
1895
|
+
*
|
|
1896
|
+
* `os build` and `os validate` both filter on this field, so promoting a rule
|
|
1897
|
+
* gates both surfaces at once — neither can report clean while the other
|
|
1898
|
+
* rejects the same stack (#3782).
|
|
1899
|
+
*/
|
|
1900
|
+
severity?: 'error' | 'warning';
|
|
1901
|
+
}
|
|
1902
|
+
type AnyRec$3 = Record<string, unknown>;
|
|
1903
|
+
declare const FLOW_TIME_RELATIVE_ANTIPATTERN = "flow-time-relative-antipattern";
|
|
1904
|
+
declare const FLOW_DATE_EQUALITY_FILTER = "flow-date-equality-filter";
|
|
1905
|
+
declare const FLOW_PHANTOM_AGGREGATION = "flow-phantom-aggregation";
|
|
1906
|
+
declare const FLOW_DOUBLE_BRACE_INTERP = "flow-double-brace-interpolation";
|
|
1907
|
+
declare const FLOW_BARE_DOLLAR_REF = "flow-bare-dollar-reference";
|
|
1908
|
+
declare const FLOW_APPROVAL_REVISE_DEAD_END = "flow-approval-revise-dead-end";
|
|
1909
|
+
declare const FLOW_APPROVAL_REVISE_UNMARKED_BACKEDGE = "flow-approval-revise-unmarked-backedge";
|
|
1910
|
+
declare const FLOW_APPROVAL_REVISE_DISABLED = "flow-approval-revise-disabled";
|
|
1911
|
+
/**
|
|
1912
|
+
* #3760 — renamed from `flow-schedule-runas-unscoped`. The old id named the
|
|
1913
|
+
* *schedule*, which was never the boundary: the rule is about a trigger that
|
|
1914
|
+
* resolves NO USER, and a schedule is only the most obvious such trigger.
|
|
1915
|
+
*/
|
|
1916
|
+
declare const FLOW_RUNAS_UNSCOPED = "flow-runas-unscoped";
|
|
1917
|
+
declare const FLOW_ERROR_LABEL_NOT_FAULT = "flow-error-label-not-fault";
|
|
1918
|
+
/** #4414 — the four ways a decision's declared branching fails to route. */
|
|
1919
|
+
declare const FLOW_BRANCH_LABEL_UNMATCHED = "flow-branch-label-unmatched";
|
|
1920
|
+
declare const FLOW_DECISION_UNCONDITIONAL_BRANCH = "flow-decision-unconditional-branch";
|
|
1921
|
+
declare const FLOW_DEFAULT_EDGE_WITH_CONDITION = "flow-default-edge-with-condition";
|
|
1922
|
+
declare const FLOW_MULTIPLE_DEFAULT_EDGES = "flow-multiple-default-edges";
|
|
1923
|
+
/** #4414 — `config.condition` on a node whose executor never reads it. */
|
|
1924
|
+
declare const FLOW_INERT_NODE_CONDITION = "flow-inert-node-condition";
|
|
1925
|
+
/**
|
|
1926
|
+
* Lint every flow's start node for known authoring anti-patterns. Returns a
|
|
1927
|
+
* (possibly empty) list of advisory findings — never throws, never fails a build.
|
|
1928
|
+
*/
|
|
1929
|
+
declare function lintFlowPatterns(stack: AnyRec$3): FlowLintFinding[];
|
|
1930
|
+
|
|
1931
|
+
interface LivenessLintFinding {
|
|
1932
|
+
where: string;
|
|
1933
|
+
message: string;
|
|
1934
|
+
hint: string;
|
|
1935
|
+
rule: string;
|
|
1936
|
+
}
|
|
1937
|
+
declare const LIVENESS_DEAD_PROPERTY = "liveness-dead-property";
|
|
1938
|
+
declare const LIVENESS_EXPERIMENTAL_PROPERTY = "liveness-experimental-property";
|
|
1939
|
+
type AnyRec$2 = Record<string, unknown>;
|
|
1940
|
+
/**
|
|
1941
|
+
* Lint the compiled stack for authored properties the liveness ledger flags as
|
|
1942
|
+
* misleading. Advisory only — returns findings, never throws. Covers every
|
|
1943
|
+
* governed metadata type: objects (incl. `enable.*`) and their fields walk
|
|
1944
|
+
* bespoke nesting; the remaining types are flat stack collections. Container
|
|
1945
|
+
* properties fan out over arrays (each flow node, each dataset measure). The
|
|
1946
|
+
* mechanism stays ledger-driven — coverage grows by marking more entries
|
|
1947
|
+
* `authorWarn` rather than touching this code.
|
|
1948
|
+
*/
|
|
1949
|
+
declare function lintLivenessProperties(stack: AnyRec$2): LivenessLintFinding[];
|
|
1950
|
+
|
|
1951
|
+
interface AutonumberLintFinding {
|
|
1952
|
+
where: string;
|
|
1953
|
+
message: string;
|
|
1954
|
+
hint: string;
|
|
1955
|
+
rule: string;
|
|
1956
|
+
severity: 'error' | 'warning';
|
|
1957
|
+
}
|
|
1958
|
+
type AnyRec$1 = Record<string, unknown>;
|
|
1959
|
+
declare const AUTONUMBER_UNKNOWN_FIELD = "autonumber-references-unknown-field";
|
|
1960
|
+
declare const AUTONUMBER_OPTIONAL_FIELD = "autonumber-references-optional-field";
|
|
1961
|
+
declare const AUTONUMBER_SELF_REFERENCE = "autonumber-references-self";
|
|
1962
|
+
declare const AUTONUMBER_LITERAL_TOKEN = "autonumber-unrecognized-token";
|
|
1963
|
+
/**
|
|
1964
|
+
* Lint every `autonumber` field's format for unresolvable / fragile `{field}`
|
|
1965
|
+
* interpolation. Returns a (possibly empty) list of findings; never throws.
|
|
1966
|
+
*/
|
|
1967
|
+
declare function lintAutonumberFormats(stack: AnyRec$1): AutonumberLintFinding[];
|
|
1968
|
+
|
|
1969
|
+
interface ViewRefFinding {
|
|
1970
|
+
where: string;
|
|
1971
|
+
message: string;
|
|
1972
|
+
hint: string;
|
|
1973
|
+
rule: string;
|
|
1974
|
+
severity: 'error' | 'warning';
|
|
1975
|
+
}
|
|
1976
|
+
type AnyRec = Record<string, any>;
|
|
1977
|
+
declare const VIEW_KEY_COLLISION = "view-key-collision";
|
|
1978
|
+
declare const VIEW_REF_FORM_TARGET_MISSING = "view-ref-form-target-missing";
|
|
1979
|
+
declare const VIEW_REF_FORM_TARGET_KIND = "view-ref-form-target-kind";
|
|
1980
|
+
declare function lintViewRefs(stack: AnyRec): ViewRefFinding[];
|
|
1981
|
+
|
|
1982
|
+
/**
|
|
1983
|
+
* Data-model best-practice lint rules.
|
|
1984
|
+
*
|
|
1985
|
+
* These rules encode the relationship / master-detail / roll-up conventions the
|
|
1986
|
+
* platform ships (see the objectstack-data and objectstack-ui skills, ADR-0035).
|
|
1987
|
+
* They run over the normalized object set and flag anti-patterns that an
|
|
1988
|
+
* author — human OR an AI generator — commonly produces. They are intentionally
|
|
1989
|
+
* heuristic: structural problems are `error`, likely-wrong choices are
|
|
1990
|
+
* `warning`, and "you probably want this" nudges are `suggestion`. None of them
|
|
1991
|
+
* block on a judgement call.
|
|
1992
|
+
*
|
|
1993
|
+
* The same rules double as the automated rubric for the metadata-generation
|
|
1994
|
+
* eval (see `score.ts`): a generated stack scores well exactly when it is
|
|
1995
|
+
* schema-valid AND lint-clean here.
|
|
1996
|
+
*/
|
|
1997
|
+
type Severity = 'error' | 'warning' | 'suggestion';
|
|
1998
|
+
interface LintIssue {
|
|
1999
|
+
severity: Severity;
|
|
2000
|
+
rule: string;
|
|
2001
|
+
message: string;
|
|
2002
|
+
path: string;
|
|
2003
|
+
fix?: string;
|
|
2004
|
+
}
|
|
2005
|
+
declare const UNIQUE_DOUBLE_DECLARATION = "unique/double-declaration";
|
|
2006
|
+
/**
|
|
2007
|
+
* R10 — the same column carries BOTH a field-level `unique: true` and an
|
|
2008
|
+
* object-level single-column unique index (#3991).
|
|
2009
|
+
*
|
|
2010
|
+
* The two spellings are deliberately different (see `IndexSchema`): field-level
|
|
2011
|
+
* `unique: true` is tenant-scoped since #3696 — it materializes as
|
|
2012
|
+
* `(organization_id, col)`, unique *within* the tenant — while a declared index
|
|
2013
|
+
* is materialized over exactly the columns listed, i.e. platform-wide. Both are
|
|
2014
|
+
* legitimate on their own; together on one column they are never right:
|
|
2015
|
+
*
|
|
2016
|
+
* - On a tenant-scoped object they CONTRADICT. The stricter one wins
|
|
2017
|
+
* physically, so the global index enforces uniqueness and the tenant
|
|
2018
|
+
* composite becomes a constraint nothing can ever trip. One of the two
|
|
2019
|
+
* intents the author wrote is silently discarded.
|
|
2020
|
+
* - On a tenancy-less object they are exactly REDUNDANT — both describe the
|
|
2021
|
+
* same single-column unique index, under the same generated name.
|
|
2022
|
+
*
|
|
2023
|
+
* Tenancy is deliberately NOT inferred here: `organization_id` is injected by
|
|
2024
|
+
* the kernel at registration rather than authored, so an authoring-time guess
|
|
2025
|
+
* would be wrong half the time. The combination is worth flagging either way,
|
|
2026
|
+
* and the message names both readings so the author picks the one they meant.
|
|
2027
|
+
*
|
|
2028
|
+
* A field declared `unique: 'global'` is exempt: it already says
|
|
2029
|
+
* platform-wide, so the declared index restates the same intent rather than
|
|
2030
|
+
* contradicting it (still redundant, but not a silent loss of meaning).
|
|
2031
|
+
*
|
|
2032
|
+
* Advisory. The resulting stack is well-defined — the cost is an intent that
|
|
2033
|
+
* never takes effect, not a broken artifact — so this never fails a build.
|
|
2034
|
+
*/
|
|
2035
|
+
declare function lintUniqueDeclarations(objects: any[]): LintIssue[];
|
|
2036
|
+
/**
|
|
2037
|
+
* Lint the relationship / data-modeling conventions across the full object set.
|
|
2038
|
+
* Pure and deterministic — safe to call from both the `lint` command and the
|
|
2039
|
+
* metadata-generation scorer.
|
|
2040
|
+
*/
|
|
2041
|
+
declare function lintDataModel(objects: any[]): LintIssue[];
|
|
2042
|
+
|
|
2043
|
+
export { ACTION_BODY_WRITE_EXCLUSIONS, ACTION_BODY_WRITE_PATTERNS, ACTION_BODY_WRITE_PATTERN_IDS, ACTION_BODY_WRITE_UNKNOWN_FIELD, ACTION_NAME_UNDEFINED, ACTION_NO_PLACEMENT, ACTION_RECORD_WRITE_DISCARDED, ACTION_RECORD_WRITE_PATTERNS, ACTION_RECORD_WRITE_PATTERN_IDS, 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, AUTONUMBER_LITERAL_TOKEN, AUTONUMBER_OPTIONAL_FIELD, AUTONUMBER_SELF_REFERENCE, AUTONUMBER_UNKNOWN_FIELD, type ActionBodyWriteExclusion, type ActionBodyWriteFinding, type ActionBodyWriteSeverity, type ActionLocationsFinding, type ActionLocationsSeverity, type ActionNameRefFinding, type ActionNameRefSeverity, type AiAgentAuthoringFinding, type AiAgentAuthoringSeverity, type AiSurfaceAffinityFinding, type AiSurfaceAffinitySeverity, type AiToolRefFinding, type AiToolRefSeverity, type ApprovalApproverFinding, type ApprovalApproverSeverity, type AutonumberLintFinding, type BodyWritePatternExclusion, 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, type ExtractedHookBodyWrite, type ExtractedHookBodyWriteSet, FIELD_GROUP_EMPTY, FIELD_GROUP_UNDECLARED, FILTER_TOKEN_UNKNOWN, FLOW_APPROVAL_REVISE_DEAD_END, FLOW_APPROVAL_REVISE_DISABLED, FLOW_APPROVAL_REVISE_UNMARKED_BACKEDGE, FLOW_BARE_DOLLAR_REF, FLOW_BRANCH_LABEL_UNMATCHED, FLOW_DATE_EQUALITY_FILTER, FLOW_DECISION_UNCONDITIONAL_BRANCH, FLOW_DEFAULT_EDGE_WITH_CONDITION, FLOW_DOUBLE_BRACE_INTERP, FLOW_DRAFT_STATUS_AMBIGUOUS, FLOW_ERROR_LABEL_NOT_FAULT, FLOW_INERT_NODE_CONDITION, FLOW_MULTIPLE_DEFAULT_EDGES, FLOW_NODE_WRITE_UNKNOWN_FIELD, FLOW_PHANTOM_AGGREGATION, FLOW_RUNAS_UNSCOPED, FLOW_TEMPLATE_LOOKUP_TRAVERSAL, FLOW_TEMPLATE_UNKNOWN_FIELD, FLOW_TIME_RELATIVE_ANTIPATTERN, FLOW_TRIGGER_UNKNOWN_OBJECT, FLOW_UPDATE_READONLY_FIELD, FLOW_UPDATE_READONLY_WHEN_FIELD, FLOW_WRITE_NODE_TYPES, FLOW_WRITE_NODE_TYPES_DEFERRED, FORM_COLSPAN_ABSOLUTE, FORM_FIELD_UNKNOWN, type FilterTokenFinding, type FilterTokenSeverity, type FlowLintFinding, type FlowNodeWriteFinding, type FlowNodeWriteSeverity, type FlowTemplatePathFinding, type FlowTemplatePathSeverity, type FlowTriggerReadinessFinding, type FlowTriggerReadinessSeverity, type FlowWriteNodeDeferral, type FormLayoutFinding, type FormLayoutSeverity, type FunctionalCompletenessFinding, type FunctionalCompletenessSeverity, HOOK_BODY_WRITE_EXCLUSIONS, HOOK_BODY_WRITE_PATTERNS, HOOK_BODY_WRITE_PATTERN_IDS, HOOK_BODY_WRITE_UNKNOWN_FIELD, type HookBodyWriteFinding, type HookBodyWritePattern, type HookBodyWriteSeverity, type JsxPageFinding, type JsxPageSeverity, LIST_VIEW_FILTERS_IN_VIEWS_MODE, LIVENESS_DEAD_PROPERTY, LIVENESS_EXPERIMENTAL_PROPERTY, type LintIssue, type ListViewModeFinding, type ListViewModeSeverity, type LivenessLintFinding, MEASURE_AGGREGATE_INCOHERENT, NAV_OBJECT_UNGRANTED, NAV_TARGET_UNRESOLVED, NULL_GUARD_HINT, type NavAccessFinding, type NavAccessSeverity, type NavTargetRefFinding, type NavTargetRefSeverity, type NullGuardFinding, type NullGuardOptions, 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_BLOCK_NEEDS_RECORD_CONTEXT, 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, SEARCHABLE_FIELD_UNKNOWN, SEARCHABLE_FIELD_UNSEARCHABLE, 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 SearchableFieldFinding, type SearchableFieldRole, type SearchableFieldSeverity, type SecurityFinding, type SecuritySeverity, type SeedReplaySafetyFinding, type SeedReplaySafetySeverity, type SeedStateMachineFinding, type SeedStateMachineSeverity, type SemanticRoleFinding, type SemanticRoleSeverity, type Severity, 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, UNIQUE_DOUBLE_DECLARATION, VIEW_CONTAINER_SHAPE, VIEW_KEY_COLLISION, VIEW_REF_FORM_TARGET_KIND, VIEW_REF_FORM_TARGET_MISSING, VISIBILITY_ALIAS_DEPRECATED, VISIBILITY_ROOT_MISLAYERED, type ViewContainerFinding, type ViewContainerSeverity, type ViewRefFinding, type VisibilityFinding, type VisibilityLayer, type VisibilityOptions, type VisibilitySeverity, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, buildAccessMatrix, diffAccessMatrix, extractHookBodyWriteSet, extractHookBodyWrites, findUnguardedNullableOperands, lintAutonumberFormats, lintDataModel, lintFlowPatterns, lintLivenessProperties, lintUniqueDeclarations, lintViewRefs, nullGuardMessage, validateActionBodyWrites, validateActionLocations, validateActionNameRefs, validateAiAgentAuthoring, validateAiSurfaceAffinity, validateAiToolReferences, validateApprovalApprovers, validateCapabilityReferences, validateChartBindings, validateDashboardActionRefs, validateFilterTokens, validateFlowNodeWrites, validateFlowTemplatePaths, validateFlowTriggerReadiness, validateFormLayout, validateFunctionalCompleteness, validateHookBodyWrites, validateJsxPages, validateListViewMode, validateNavAccess, validateNavTargetRefs, validateObjectReferences, validateOrgAxisRedLines, validatePageFieldBindings, validatePageSourceStyling, validateReactPageProps, validateReactPages, validateReadonlyFlowWrites, validateRecordTitle, validateReferenceIntegrity, validateResponsiveStyles, validateSearchableFields, validateSecurityPosture, validateSeedReplaySafety, validateSeedStateMachine, validateSemanticRoles, validateStackExpressions, validateTranslationReferences, validateViewContainers, validateVisibilityPredicates, validateWidgetBindings };
|