@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.
@@ -0,0 +1,254 @@
1
+ type AnyRec = Record<string, unknown>;
2
+ /** The three commands that hold a stack to the same author-time bar. */
3
+ declare const AUTHORING_COMMANDS: readonly ["validate", "build", "lint"];
4
+ type AuthoringCommand = (typeof AUTHORING_COMMANDS)[number];
5
+ /**
6
+ * The authoring SURFACES this registry serves (#4463).
7
+ *
8
+ * - `cli` — `os validate` / `os build` / `os lint`. Which of the three is a
9
+ * separate axis ({@link AuthoringRule.commands}); every rule here runs on the
10
+ * `cli` surface, because that is where the registry was born.
11
+ * - `runtime-publish` — the metadata write path's PUBLISH gate: a
12
+ * `state: 'active'` `saveMetaItem`, and the draft→active promotion in
13
+ * `publishMetaItem`. Studio saves, REST `/meta` item CRUD and MCP/AI
14
+ * authoring all funnel through those two, so wiring the surface once covers
15
+ * all three doors (the maintainer ruling on #4463: one shared core, one
16
+ * runtime gate, not a gate per surface).
17
+ *
18
+ * Draft saves are deliberately NOT a surface: a draft is allowed to be a
19
+ * half-finished thing, and gating one would break the Studio editing loop for
20
+ * no safety gain — the draft cannot execute until it is published, and
21
+ * publishing runs this table (#4463 D1).
22
+ */
23
+ declare const AUTHORING_SURFACES: readonly ["cli", "runtime-publish"];
24
+ type AuthoringSurface = (typeof AUTHORING_SURFACES)[number];
25
+ /** `error` gates. `warning` advises. `info` is a suggestion (`os lint` grades it as one). */
26
+ type AuthoringSeverity = 'error' | 'warning' | 'info';
27
+ /**
28
+ * The one finding shape all three commands render. Rules whose own return type
29
+ * predates it are adapted at their registry entry, so the commands hold one
30
+ * type instead of a twenty-way union.
31
+ */
32
+ interface AuthoringFinding {
33
+ severity: AuthoringSeverity;
34
+ /** Stable diagnostic rule id (used by docs, allowlists and `--json` consumers). */
35
+ rule: string;
36
+ /** Human-readable location, e.g. `object "leave_request"`. */
37
+ where: string;
38
+ /** Config path, e.g. `objects[3].sharingModel`. */
39
+ path: string;
40
+ /** What is wrong. */
41
+ message: string;
42
+ /** How to fix it. */
43
+ hint: string;
44
+ }
45
+ /**
46
+ * `gating` = the rule can emit `severity: 'error'`, so it MUST run on all three
47
+ * commands. `advisory` = it never does, and may be scoped with a reason.
48
+ *
49
+ * The claim is not taken on trust: the wiring guard reads each `advisory` rule's
50
+ * own source and fails if it emits an `error`. That check is the reason the tier
51
+ * is worth declaring — #3760 promoted a `lintFlowPatterns` rule from advisory to
52
+ * gating, and nothing anywhere asked whether its command coverage should follow.
53
+ */
54
+ type AuthoringRuleTier = 'gating' | 'advisory';
55
+ /**
56
+ * Which tier of the stack a rule reads.
57
+ *
58
+ * - `normalized` — the `normalizeStackInput` output, BEFORE the Zod parse. The
59
+ * rules that need it check keys the parse strips (a flat list view in
60
+ * `views: []`, `userFilters` on an object list view, a `visibleOn` alias): by
61
+ * the time `result.data` exists the evidence is gone.
62
+ * - `parsed` — the post-parse stack, where defaults are filled and shapes are
63
+ * settled.
64
+ *
65
+ * `os lint` never parses (it is the cheap pre-flight; a schema error is
66
+ * `os validate`'s verdict to give), so it runs BOTH tiers on the normalized
67
+ * stack. Every rule here is written to tolerate that — it is what `os lint`
68
+ * already did for the reference-integrity suite and the security linter.
69
+ */
70
+ type AuthoringRuleInputTier = 'normalized' | 'parsed';
71
+ /** Per-run inputs a rule may need beyond the stack itself. */
72
+ interface AuthoringRuleContext {
73
+ /** ADR-0080 SDUI component manifest, when the project ships one. */
74
+ sduiManifest?: unknown;
75
+ }
76
+ interface AuthoringRule {
77
+ /** The exported function's name — the id the wiring guard asserts on. */
78
+ name: string;
79
+ tier: AuthoringRuleTier;
80
+ input: AuthoringRuleInputTier;
81
+ /** Which commands run it. Must be all three when `tier` is `gating`. */
82
+ commands: readonly AuthoringCommand[];
83
+ /** Repo-relative path to the rule's implementation (the guard verifies the tier claim against it). */
84
+ source: string;
85
+ /** REQUIRED when `commands` is not all three: why this rule is scoped. */
86
+ scopeReason?: string;
87
+ /**
88
+ * Which authoring surfaces run this rule (#4463). Always contains `'cli'`.
89
+ *
90
+ * Adding `'runtime-publish'` is what puts the rule on the metadata write
91
+ * path's publish gate; {@link runtimeTypes} then says which metadata types'
92
+ * writes it inspects. Leaving it off REQUIRES {@link surfaceReason} — the
93
+ * same discipline `scopeReason` applies to the command axis, for the same
94
+ * reason: the whole defect class #4409 and #4463 describe is coverage that
95
+ * narrowed silently.
96
+ */
97
+ surfaces: readonly AuthoringSurface[];
98
+ /**
99
+ * REQUIRED when `surfaces` includes `'runtime-publish'`: the SINGULAR
100
+ * metadata type names whose runtime write this rule inspects (e.g. `flow`).
101
+ *
102
+ * The runtime gate builds a per-write stack snapshot and only runs the rules
103
+ * that declare the written type, which is #4463 D2 option (c) expressed as
104
+ * data. Widening a rule to another type is a one-line edit here, not new
105
+ * wiring at the gate.
106
+ */
107
+ runtimeTypes?: readonly string[];
108
+ /** REQUIRED when `surfaces` omits `'runtime-publish'`: why the runtime gate does not run it. */
109
+ surfaceReason?: string;
110
+ run: (stack: AnyRec, ctx: AuthoringRuleContext) => readonly AuthoringFinding[];
111
+ }
112
+ /**
113
+ * `ExprIssue` is the one rule finding that carries no rule id of its own — it
114
+ * predates the `{ rule, path, hint }` shape every other rule settled on. Given
115
+ * one here so `os lint --json` and the docs can name it like any other.
116
+ */
117
+ declare const EXPRESSION_INVALID = "expression-invalid";
118
+ /**
119
+ * Every author-time rule the three commands share, in the order their findings
120
+ * are reported.
121
+ */
122
+ declare const AUTHORING_RULES: readonly AuthoringRule[];
123
+ /** The stack tiers a command has in hand when it runs the registry. */
124
+ interface AuthoringRuleRun extends AuthoringRuleContext {
125
+ /** `normalizeStackInput` output — pre-Zod-parse. Always required. */
126
+ normalized: AnyRec;
127
+ /**
128
+ * Post-Zod-parse stack. Omitted by `os lint`, which does not parse; `parsed`
129
+ * rules then read `normalized` (see `AuthoringRuleInputTier`).
130
+ */
131
+ parsed?: AnyRec;
132
+ }
133
+ /** The rules `command` runs, in registry order. */
134
+ declare function authoringRulesFor(command: AuthoringCommand): readonly AuthoringRule[];
135
+ /**
136
+ * Run every rule registered for `command` and return the concatenated findings
137
+ * (empty = clean).
138
+ *
139
+ * Findings are collected across ALL rules rather than short-circuiting at the
140
+ * first failing one. The commands used to exit at the first failing gate, which
141
+ * meant an author with three unrelated problems fixed them in three round trips
142
+ * and could not tell how deep the hole went. One report per run is also what
143
+ * makes the three commands comparable: same rules, same order, same output.
144
+ */
145
+ declare function runAuthoringRules(command: AuthoringCommand, run: AuthoringRuleRun): AuthoringFinding[];
146
+ /** Split findings into the gating set and the advisory set (`warning` + `info`). */
147
+ declare function splitBySeverity(findings: readonly AuthoringFinding[]): {
148
+ errors: AuthoringFinding[];
149
+ advisories: AuthoringFinding[];
150
+ };
151
+
152
+ /**
153
+ * The RUNTIME publish gate over the author-time rule registry (#4463).
154
+ *
155
+ * ## The hole this closes
156
+ *
157
+ * #4409/#4445 put 26 author-time rules behind one table and made `os validate`,
158
+ * `os build` and `os lint` run it by construction. All three are CLI commands.
159
+ * The metadata WRITE path — Studio's designer, REST `/meta` item CRUD, an
160
+ * MCP/AI author — reaches `saveMetaItem`, which ran a per-type Zod `safeParse`
161
+ * and nothing else. Zero of the 26 rules ran there. For a tenant that is not
162
+ * one weak door among four, it is the ONLY door: `os lint` cannot see a
163
+ * `sys_metadata` overlay row at all, so there was no command they could run
164
+ * instead.
165
+ *
166
+ * It also happens to be the door AI authors use. That is the axis the #4463
167
+ * ruling weighted highest: metadata written by a model is exactly the metadata
168
+ * most likely to be subtly wrong, and it was arriving through the one entrance
169
+ * with no checks on it.
170
+ *
171
+ * ## Shape
172
+ *
173
+ * This module is a GATE, not a rule engine. It owns no judgement: every finding
174
+ * it returns came from {@link AUTHORING_RULES}, the same array the three CLI
175
+ * commands run. Delete a rule from that table and this gate stops enforcing it
176
+ * in the same commit — which is the property the issue asked for, and the
177
+ * reason a second "runtime rule list" was never on the table.
178
+ *
179
+ * ## Why it evaluates DIFFERENTIALLY
180
+ *
181
+ * The rules are `(stack) => findings`. A runtime write is one ITEM. The gate
182
+ * therefore builds a per-write snapshot — the written item, plus the live
183
+ * registry's objects as resolution context — and runs the rules TWICE: once on
184
+ * the context alone, once with the item grafted in. Only findings the item
185
+ * ADDED are attributable to this write.
186
+ *
187
+ * That is not defensive padding, it is the D4 requirement made structural:
188
+ *
189
+ * - a tenant's existing `sys_metadata` rows may already violate a rule that did
190
+ * not exist when they were written, and the read path must keep serving them
191
+ * (ADR-0087's asymmetry). Gating on the absolute finding set would make an
192
+ * unrelated legacy row block every future save;
193
+ * - the context is resolution material, not subject matter. Without the
194
+ * subtraction, saving flow A would 422 because object B — untouched, already
195
+ * stored, possibly shipped in a package — has a bad predicate.
196
+ *
197
+ * The cost is two passes over a small in-memory snapshot, on a PUBLISH (not on
198
+ * a draft autosave). That is the correct place to spend it.
199
+ */
200
+
201
+ /** Everything the gate needs from the host runtime to build a snapshot. */
202
+ interface RuntimeStackContext {
203
+ /**
204
+ * The live object declarations (registry + tenant overlay), as authored.
205
+ *
206
+ * Objects are the resolution universe almost every rule needs: `record.<field>`
207
+ * in a CEL predicate, a flow node's target object, a template path. This is
208
+ * where the runtime is strictly BETTER informed than `os lint`, which sees one
209
+ * package's config file and has to hedge.
210
+ */
211
+ objects?: readonly unknown[];
212
+ }
213
+ /** One rule's verdict at the runtime surface, carrying which rule produced it. */
214
+ interface RuntimeGateResult {
215
+ /** Findings the written item ADDED, severity `error` — the reason to refuse the write. */
216
+ errors: AuthoringFinding[];
217
+ /** Findings the written item added at `warning` / `info`. Never blocks (#4463 P1). */
218
+ advisories: AuthoringFinding[];
219
+ /** Names of the registry rules that actually ran, in registry order. */
220
+ rulesRun: string[];
221
+ }
222
+ /**
223
+ * The rules the runtime publish gate runs for a write of `type` — read off
224
+ * {@link AUTHORING_RULES}, never a list of its own.
225
+ *
226
+ * @param type Singular metadata type name (`flow`, `object`, …).
227
+ */
228
+ declare function runtimeAuthoringRulesFor(type: string): readonly AuthoringRule[];
229
+ /** Every singular metadata type at least one rule gates at the runtime surface. */
230
+ declare function runtimeGatedTypes(): string[];
231
+ /** The stack key a metadata type occupies in a stack view, or null when unmapped. */
232
+ declare function stackKeyForType(type: string): string | null;
233
+ /**
234
+ * Judge one about-to-be-published metadata item against the shared registry.
235
+ *
236
+ * Returns an empty `errors` array when the item is clean OR when no rule gates
237
+ * its type — callers must not treat "no rules ran" as a failure, and
238
+ * `rulesRun` is there so a caller can tell the two apart.
239
+ *
240
+ * Pure: no I/O, no `process.env`, no logging. The escape hatch and the HTTP
241
+ * status live at the call site, where the request context is.
242
+ */
243
+ declare function runRuntimeAuthoringRules(args: {
244
+ /** Singular metadata type of the item being written. */
245
+ type: string;
246
+ /** The item body as it will be persisted. */
247
+ item: unknown;
248
+ /** Live resolution context from the host runtime. */
249
+ context?: RuntimeStackContext;
250
+ /** ADR-0080 SDUI manifest, when the host has one. */
251
+ sduiManifest?: unknown;
252
+ }): RuntimeGateResult;
253
+
254
+ export { AUTHORING_COMMANDS as A, EXPRESSION_INVALID as E, type RuntimeGateResult as R, AUTHORING_RULES as a, AUTHORING_SURFACES as b, type AuthoringCommand as c, type AuthoringFinding as d, type AuthoringRule as e, type AuthoringRuleContext as f, type AuthoringRuleInputTier as g, type AuthoringRuleRun as h, type AuthoringRuleTier as i, type AuthoringSeverity as j, type AuthoringSurface as k, type RuntimeStackContext as l, authoringRulesFor as m, runRuntimeAuthoringRules as n, runtimeAuthoringRulesFor as o, runtimeGatedTypes as p, stackKeyForType as q, runAuthoringRules as r, splitBySeverity as s };
@@ -0,0 +1,254 @@
1
+ type AnyRec = Record<string, unknown>;
2
+ /** The three commands that hold a stack to the same author-time bar. */
3
+ declare const AUTHORING_COMMANDS: readonly ["validate", "build", "lint"];
4
+ type AuthoringCommand = (typeof AUTHORING_COMMANDS)[number];
5
+ /**
6
+ * The authoring SURFACES this registry serves (#4463).
7
+ *
8
+ * - `cli` — `os validate` / `os build` / `os lint`. Which of the three is a
9
+ * separate axis ({@link AuthoringRule.commands}); every rule here runs on the
10
+ * `cli` surface, because that is where the registry was born.
11
+ * - `runtime-publish` — the metadata write path's PUBLISH gate: a
12
+ * `state: 'active'` `saveMetaItem`, and the draft→active promotion in
13
+ * `publishMetaItem`. Studio saves, REST `/meta` item CRUD and MCP/AI
14
+ * authoring all funnel through those two, so wiring the surface once covers
15
+ * all three doors (the maintainer ruling on #4463: one shared core, one
16
+ * runtime gate, not a gate per surface).
17
+ *
18
+ * Draft saves are deliberately NOT a surface: a draft is allowed to be a
19
+ * half-finished thing, and gating one would break the Studio editing loop for
20
+ * no safety gain — the draft cannot execute until it is published, and
21
+ * publishing runs this table (#4463 D1).
22
+ */
23
+ declare const AUTHORING_SURFACES: readonly ["cli", "runtime-publish"];
24
+ type AuthoringSurface = (typeof AUTHORING_SURFACES)[number];
25
+ /** `error` gates. `warning` advises. `info` is a suggestion (`os lint` grades it as one). */
26
+ type AuthoringSeverity = 'error' | 'warning' | 'info';
27
+ /**
28
+ * The one finding shape all three commands render. Rules whose own return type
29
+ * predates it are adapted at their registry entry, so the commands hold one
30
+ * type instead of a twenty-way union.
31
+ */
32
+ interface AuthoringFinding {
33
+ severity: AuthoringSeverity;
34
+ /** Stable diagnostic rule id (used by docs, allowlists and `--json` consumers). */
35
+ rule: string;
36
+ /** Human-readable location, e.g. `object "leave_request"`. */
37
+ where: string;
38
+ /** Config path, e.g. `objects[3].sharingModel`. */
39
+ path: string;
40
+ /** What is wrong. */
41
+ message: string;
42
+ /** How to fix it. */
43
+ hint: string;
44
+ }
45
+ /**
46
+ * `gating` = the rule can emit `severity: 'error'`, so it MUST run on all three
47
+ * commands. `advisory` = it never does, and may be scoped with a reason.
48
+ *
49
+ * The claim is not taken on trust: the wiring guard reads each `advisory` rule's
50
+ * own source and fails if it emits an `error`. That check is the reason the tier
51
+ * is worth declaring — #3760 promoted a `lintFlowPatterns` rule from advisory to
52
+ * gating, and nothing anywhere asked whether its command coverage should follow.
53
+ */
54
+ type AuthoringRuleTier = 'gating' | 'advisory';
55
+ /**
56
+ * Which tier of the stack a rule reads.
57
+ *
58
+ * - `normalized` — the `normalizeStackInput` output, BEFORE the Zod parse. The
59
+ * rules that need it check keys the parse strips (a flat list view in
60
+ * `views: []`, `userFilters` on an object list view, a `visibleOn` alias): by
61
+ * the time `result.data` exists the evidence is gone.
62
+ * - `parsed` — the post-parse stack, where defaults are filled and shapes are
63
+ * settled.
64
+ *
65
+ * `os lint` never parses (it is the cheap pre-flight; a schema error is
66
+ * `os validate`'s verdict to give), so it runs BOTH tiers on the normalized
67
+ * stack. Every rule here is written to tolerate that — it is what `os lint`
68
+ * already did for the reference-integrity suite and the security linter.
69
+ */
70
+ type AuthoringRuleInputTier = 'normalized' | 'parsed';
71
+ /** Per-run inputs a rule may need beyond the stack itself. */
72
+ interface AuthoringRuleContext {
73
+ /** ADR-0080 SDUI component manifest, when the project ships one. */
74
+ sduiManifest?: unknown;
75
+ }
76
+ interface AuthoringRule {
77
+ /** The exported function's name — the id the wiring guard asserts on. */
78
+ name: string;
79
+ tier: AuthoringRuleTier;
80
+ input: AuthoringRuleInputTier;
81
+ /** Which commands run it. Must be all three when `tier` is `gating`. */
82
+ commands: readonly AuthoringCommand[];
83
+ /** Repo-relative path to the rule's implementation (the guard verifies the tier claim against it). */
84
+ source: string;
85
+ /** REQUIRED when `commands` is not all three: why this rule is scoped. */
86
+ scopeReason?: string;
87
+ /**
88
+ * Which authoring surfaces run this rule (#4463). Always contains `'cli'`.
89
+ *
90
+ * Adding `'runtime-publish'` is what puts the rule on the metadata write
91
+ * path's publish gate; {@link runtimeTypes} then says which metadata types'
92
+ * writes it inspects. Leaving it off REQUIRES {@link surfaceReason} — the
93
+ * same discipline `scopeReason` applies to the command axis, for the same
94
+ * reason: the whole defect class #4409 and #4463 describe is coverage that
95
+ * narrowed silently.
96
+ */
97
+ surfaces: readonly AuthoringSurface[];
98
+ /**
99
+ * REQUIRED when `surfaces` includes `'runtime-publish'`: the SINGULAR
100
+ * metadata type names whose runtime write this rule inspects (e.g. `flow`).
101
+ *
102
+ * The runtime gate builds a per-write stack snapshot and only runs the rules
103
+ * that declare the written type, which is #4463 D2 option (c) expressed as
104
+ * data. Widening a rule to another type is a one-line edit here, not new
105
+ * wiring at the gate.
106
+ */
107
+ runtimeTypes?: readonly string[];
108
+ /** REQUIRED when `surfaces` omits `'runtime-publish'`: why the runtime gate does not run it. */
109
+ surfaceReason?: string;
110
+ run: (stack: AnyRec, ctx: AuthoringRuleContext) => readonly AuthoringFinding[];
111
+ }
112
+ /**
113
+ * `ExprIssue` is the one rule finding that carries no rule id of its own — it
114
+ * predates the `{ rule, path, hint }` shape every other rule settled on. Given
115
+ * one here so `os lint --json` and the docs can name it like any other.
116
+ */
117
+ declare const EXPRESSION_INVALID = "expression-invalid";
118
+ /**
119
+ * Every author-time rule the three commands share, in the order their findings
120
+ * are reported.
121
+ */
122
+ declare const AUTHORING_RULES: readonly AuthoringRule[];
123
+ /** The stack tiers a command has in hand when it runs the registry. */
124
+ interface AuthoringRuleRun extends AuthoringRuleContext {
125
+ /** `normalizeStackInput` output — pre-Zod-parse. Always required. */
126
+ normalized: AnyRec;
127
+ /**
128
+ * Post-Zod-parse stack. Omitted by `os lint`, which does not parse; `parsed`
129
+ * rules then read `normalized` (see `AuthoringRuleInputTier`).
130
+ */
131
+ parsed?: AnyRec;
132
+ }
133
+ /** The rules `command` runs, in registry order. */
134
+ declare function authoringRulesFor(command: AuthoringCommand): readonly AuthoringRule[];
135
+ /**
136
+ * Run every rule registered for `command` and return the concatenated findings
137
+ * (empty = clean).
138
+ *
139
+ * Findings are collected across ALL rules rather than short-circuiting at the
140
+ * first failing one. The commands used to exit at the first failing gate, which
141
+ * meant an author with three unrelated problems fixed them in three round trips
142
+ * and could not tell how deep the hole went. One report per run is also what
143
+ * makes the three commands comparable: same rules, same order, same output.
144
+ */
145
+ declare function runAuthoringRules(command: AuthoringCommand, run: AuthoringRuleRun): AuthoringFinding[];
146
+ /** Split findings into the gating set and the advisory set (`warning` + `info`). */
147
+ declare function splitBySeverity(findings: readonly AuthoringFinding[]): {
148
+ errors: AuthoringFinding[];
149
+ advisories: AuthoringFinding[];
150
+ };
151
+
152
+ /**
153
+ * The RUNTIME publish gate over the author-time rule registry (#4463).
154
+ *
155
+ * ## The hole this closes
156
+ *
157
+ * #4409/#4445 put 26 author-time rules behind one table and made `os validate`,
158
+ * `os build` and `os lint` run it by construction. All three are CLI commands.
159
+ * The metadata WRITE path — Studio's designer, REST `/meta` item CRUD, an
160
+ * MCP/AI author — reaches `saveMetaItem`, which ran a per-type Zod `safeParse`
161
+ * and nothing else. Zero of the 26 rules ran there. For a tenant that is not
162
+ * one weak door among four, it is the ONLY door: `os lint` cannot see a
163
+ * `sys_metadata` overlay row at all, so there was no command they could run
164
+ * instead.
165
+ *
166
+ * It also happens to be the door AI authors use. That is the axis the #4463
167
+ * ruling weighted highest: metadata written by a model is exactly the metadata
168
+ * most likely to be subtly wrong, and it was arriving through the one entrance
169
+ * with no checks on it.
170
+ *
171
+ * ## Shape
172
+ *
173
+ * This module is a GATE, not a rule engine. It owns no judgement: every finding
174
+ * it returns came from {@link AUTHORING_RULES}, the same array the three CLI
175
+ * commands run. Delete a rule from that table and this gate stops enforcing it
176
+ * in the same commit — which is the property the issue asked for, and the
177
+ * reason a second "runtime rule list" was never on the table.
178
+ *
179
+ * ## Why it evaluates DIFFERENTIALLY
180
+ *
181
+ * The rules are `(stack) => findings`. A runtime write is one ITEM. The gate
182
+ * therefore builds a per-write snapshot — the written item, plus the live
183
+ * registry's objects as resolution context — and runs the rules TWICE: once on
184
+ * the context alone, once with the item grafted in. Only findings the item
185
+ * ADDED are attributable to this write.
186
+ *
187
+ * That is not defensive padding, it is the D4 requirement made structural:
188
+ *
189
+ * - a tenant's existing `sys_metadata` rows may already violate a rule that did
190
+ * not exist when they were written, and the read path must keep serving them
191
+ * (ADR-0087's asymmetry). Gating on the absolute finding set would make an
192
+ * unrelated legacy row block every future save;
193
+ * - the context is resolution material, not subject matter. Without the
194
+ * subtraction, saving flow A would 422 because object B — untouched, already
195
+ * stored, possibly shipped in a package — has a bad predicate.
196
+ *
197
+ * The cost is two passes over a small in-memory snapshot, on a PUBLISH (not on
198
+ * a draft autosave). That is the correct place to spend it.
199
+ */
200
+
201
+ /** Everything the gate needs from the host runtime to build a snapshot. */
202
+ interface RuntimeStackContext {
203
+ /**
204
+ * The live object declarations (registry + tenant overlay), as authored.
205
+ *
206
+ * Objects are the resolution universe almost every rule needs: `record.<field>`
207
+ * in a CEL predicate, a flow node's target object, a template path. This is
208
+ * where the runtime is strictly BETTER informed than `os lint`, which sees one
209
+ * package's config file and has to hedge.
210
+ */
211
+ objects?: readonly unknown[];
212
+ }
213
+ /** One rule's verdict at the runtime surface, carrying which rule produced it. */
214
+ interface RuntimeGateResult {
215
+ /** Findings the written item ADDED, severity `error` — the reason to refuse the write. */
216
+ errors: AuthoringFinding[];
217
+ /** Findings the written item added at `warning` / `info`. Never blocks (#4463 P1). */
218
+ advisories: AuthoringFinding[];
219
+ /** Names of the registry rules that actually ran, in registry order. */
220
+ rulesRun: string[];
221
+ }
222
+ /**
223
+ * The rules the runtime publish gate runs for a write of `type` — read off
224
+ * {@link AUTHORING_RULES}, never a list of its own.
225
+ *
226
+ * @param type Singular metadata type name (`flow`, `object`, …).
227
+ */
228
+ declare function runtimeAuthoringRulesFor(type: string): readonly AuthoringRule[];
229
+ /** Every singular metadata type at least one rule gates at the runtime surface. */
230
+ declare function runtimeGatedTypes(): string[];
231
+ /** The stack key a metadata type occupies in a stack view, or null when unmapped. */
232
+ declare function stackKeyForType(type: string): string | null;
233
+ /**
234
+ * Judge one about-to-be-published metadata item against the shared registry.
235
+ *
236
+ * Returns an empty `errors` array when the item is clean OR when no rule gates
237
+ * its type — callers must not treat "no rules ran" as a failure, and
238
+ * `rulesRun` is there so a caller can tell the two apart.
239
+ *
240
+ * Pure: no I/O, no `process.env`, no logging. The escape hatch and the HTTP
241
+ * status live at the call site, where the request context is.
242
+ */
243
+ declare function runRuntimeAuthoringRules(args: {
244
+ /** Singular metadata type of the item being written. */
245
+ type: string;
246
+ /** The item body as it will be persisted. */
247
+ item: unknown;
248
+ /** Live resolution context from the host runtime. */
249
+ context?: RuntimeStackContext;
250
+ /** ADR-0080 SDUI manifest, when the host has one. */
251
+ sduiManifest?: unknown;
252
+ }): RuntimeGateResult;
253
+
254
+ export { AUTHORING_COMMANDS as A, EXPRESSION_INVALID as E, type RuntimeGateResult as R, AUTHORING_RULES as a, AUTHORING_SURFACES as b, type AuthoringCommand as c, type AuthoringFinding as d, type AuthoringRule as e, type AuthoringRuleContext as f, type AuthoringRuleInputTier as g, type AuthoringRuleRun as h, type AuthoringRuleTier as i, type AuthoringSeverity as j, type AuthoringSurface as k, type RuntimeStackContext as l, authoringRulesFor as m, runRuntimeAuthoringRules as n, runtimeAuthoringRulesFor as o, runtimeGatedTypes as p, stackKeyForType as q, runAuthoringRules as r, splitBySeverity as s };