Skip to content

Commit a7163ea

Browse files
os-zhuangclaude
andauthored
feat(lint): the ADR-0078 completeness gate — Zod-valid but runtime-dead now fails at author time (#4547)
* feat(lint): the ADR-0078 completeness gate — Zod-valid but runtime-dead now fails at author time (#4544) An instance can be Zod-valid (gate 1 green), use only live properties (gate 2 green), and have a correctly-authored sibling proven to run (gate 3 green) — and still be dead, because it omits a config its consumer needs and the consumer silently no-ops. The founding case (cloud#687): an AI authored `{ type: 'summary' }` with no `summaryOperations`; the engine's index builder skips it, the field reads 0 forever, the dependent occupancy-rate formula is stuck at 0 — and the agent reported the work done, because every gate it could see was green. This is worse than the unknown-key hole #4001 just closed. There the author wrote a key we don't know, and the parse now rejects it with a prescription. Here every key is one we know, the schema is satisfied, nothing warns, and the author gets a success — false completion without anyone mistyping anything. The review step that catches a human's bare summary (seeing the field render 0) is exactly the step AI authoring removes. One shared predicate, every surface. Instance-completeness checks previously existed ONLY in cloud's AI-build graph-lint, so a stack authored with `os` + a coding assistant, an MCP agent, `os validate` in CI, or by hand got none of them (`formula_without_expression` existed nowhere in the framework). The judgement now lives in `@objectstack/spec/kernel`'s `checkFieldCompleteness` / `checkViewCompleteness` — sibling of `isIncoherentAggregate`, the ADR-0019 pattern — consumed by the new `@objectstack/lint` validator and registered as an author-time rule (28 -> 29), so `os build` / `os validate` / `os lint` / MCP / hand authoring are all covered. Cloud graph-lint can re-home its duplicates onto the same predicate rather than drifting from it. Every rule cites the runtime line that makes it true, because the completeness audit's scariest candidate (a "sharing rule fails open") collapsed on a three-file read, and #4001's last batches shipped four confidently wrong prescriptions before learning the same thing: field/summary-without-operations engine.ts `if (!d.summaryOperations) continue` error field/formula-without-expression engine.ts plans only fields that HAVE one error field/relationship-without-reference $expand `if (!referenceObject) continue` error field/choice-without-options record-validator.ts: empty list disables the error (select, radio) server-side value check entirely field/choice-without-options same branch, shared with free-form warning (checkboxes) view/layout-without-binding renderer falls back to literal default names warning (kanban, calendar, gantt) The deliberate NON-rules are pinned as hard as the rules. `multiselect` without options is NOT flagged: record-validator.ts says verbatim `// free-form (tags without options)`. The runtime blesses it as a mode, making it ADR-0078 case (3) "genuinely optional" — flagging it would be another false prescription, and the test is where that attempt fails first. `timeline` / `tree` views are out of v1 for the same reason: config schemas exist, renderer behaviour has not had its verification pass. Verify, then enforce — one shape at a time. It found a real one on its first run against a real app. `showcase_field_zoo.f_summary` was a bare `Field.summary({ label: 'Roll-up Summary' })` — one line below an `f_formula` that IS complete, in the object whose entire job is to show what each field type looks like. The canonical example of a roll-up in this repo computed nothing. It could not be fixed by adding `summaryOperations`: a roll-up aggregates a child into its parent, and the zoo is a leaf (`f_master_detail` makes it a child of `showcase_project`, and nothing is a child of the zoo). Removed, with the working examples named — `showcase_invoice.total` for the plain sum, `showcase_expense_report`'s `total_amount` / `approved_amount` for the `summaryOperations.filter` variant. The rule it broke was the file's own: "relationship types point at the other showcase objects so they have REAL targets". Verification: 19 predicate tests + 7 walk tests (both spellings of every collection — a gate that walks half the stack is this campaign's recurring "instrument reporting coverage it doesn't have"); CRM and Todo produce zero findings; showcase clean after the fix with its 60 coverage tests passing; full monorepo suite 132/132. Phase 1 of #4544. Phase 2 (the cloud authoring-path config-drop fix) is in the cloud repo; Phase 3 lands the Tier-B shapes one verification pass at a time. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY * chore(spec): regenerate the API surface snapshot for the ADR-0078 kernel exports The completeness gate adds nine kernel exports — `checkFieldCompleteness`, `checkViewCompleteness`, `CompletenessFinding`, the five rule-id constants and `FUNCTIONAL_COMPLETENESS_RULES`. `check:api-surface` reported them as `0 breaking (removed/narrowed), 9 added`: purely additive, which is what a new shared predicate should be. Snapshot regenerated so the gate agrees. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY * chore: lower the showcase i18n ratchet 452 -> 451 after removing the inert roll-up Removing `showcase_field_zoo.f_summary` took its `label: 'Roll-up Summary'` with it, so app-showcase declares one fewer untranslated string. The ratchet is bidirectional by design — an improvement that leaves the baseline stale would let a later regression back in under it — so the baseline moves down with the count. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 95fe777 commit a7163ea

11 files changed

Lines changed: 713 additions & 2 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/lint': minor
4+
'@objectstack/cli': minor
5+
---
6+
7+
The ADR-0078 completeness gate ships: a Zod-valid metadata instance that silently does nothing now fails at author time, on every authoring surface.
8+
9+
This closes the hole *between* the platform's existing gates. An instance can be Zod-valid (gate 1 green), use only *live* properties (gate 2 green), and a correctly-authored sibling can be proven to run (gate 3 green) — and still be dead, because it omits a config its consumer needs and the consumer silently no-ops. The founding case (cloud#687): an AI authored `{ type: 'summary' }` with no `summaryOperations`; the engine's index builder skips it, the field reads 0 forever, the dependent "occupancy rate" is stuck at 0 — and the agent reported the work done, because every gate it could see was green.
10+
11+
**Why this is worse than the unknown-key hole #4001 just closed.** There, the author wrote a key we don't know, and the parse now rejects it with a prescription. Here every key is one we know, the schema is satisfied, nothing warns, and the author gets a success. It manufactures false completion without the author mistyping anything — and the review step that catches a human's bare summary (seeing the field render `0`) is exactly the step AI authoring removes.
12+
13+
**One shared predicate, every surface — the ADR's core decision.** Instance-completeness checks previously existed *only* in cloud's AI-build graph-lint, so a stack authored with `os` + a coding assistant, an MCP agent, `os validate` in CI, or by hand got none of them (`formula_without_expression` existed nowhere in the framework). The judgement now lives in `@objectstack/spec/kernel`'s `checkFieldCompleteness` / `checkViewCompleteness` — sibling of `isIncoherentAggregate`, the ADR-0019 pattern — consumed by the new `@objectstack/lint` `validate-functional-completeness` and registered as an author-time rule (28 → 29), so `os build` / `os validate` / `os lint` / MCP / hand authoring are all covered. Cloud graph-lint can re-home its duplicate rules onto the same predicate rather than drifting from it.
14+
15+
**Every rule cites the runtime line that makes it true**, because the completeness audit's scariest candidate — a "sharing rule fails open and shares every record" — collapsed on a three-file read, and #4001's last two batches shipped four confidently wrong prescriptions before learning the same thing:
16+
17+
| rule | the silent skip | severity |
18+
|---|---|---|
19+
| `field/summary-without-operations` | `engine.ts``if (!d.summaryOperations) continue` | error |
20+
| `field/formula-without-expression` | `engine.ts` builds the formula plan only from fields that HAVE one | error |
21+
| `field/relationship-without-reference` | `$expand``if (!referenceObject) continue` | error |
22+
| `field/choice-without-options` (`select`, `radio`) | `record-validator.ts` — an empty option list disables server-side value validation | error |
23+
| `field/choice-without-options` (`checkboxes`) | same branch, but shared with free-form | warning |
24+
| `view/layout-without-binding` (`kanban`, `calendar`, `gantt`) | renderer falls back to literal default field names | warning |
25+
26+
**The deliberate NON-rules are pinned as hard as the rules.** `multiselect` without options is *not* flagged: `record-validator.ts` says verbatim `// free-form (tags without options)`. The runtime blesses it as a mode, which makes it ADR-0078 case (3) "genuinely optional" — flagging it would be another false prescription, and the test is where that attempt fails first. `timeline` / `tree` views are likewise out of v1: they have config schemas, but their renderer behaviour has not had its verification pass.
27+
28+
**It found a real one on its first run against a real app.** `showcase_field_zoo.f_summary` was a bare `Field.summary({ label: 'Roll-up Summary' })` — one line below an `f_formula` that *is* complete, in the object whose entire job is to show what each field type looks like. So the canonical example of a roll-up in this repo computed nothing. It could not be fixed by adding `summaryOperations`: a roll-up aggregates a child into its parent, and the zoo is a leaf (`f_master_detail` makes it a child of `showcase_project`, and nothing is a child of the zoo). Removed, with the working examples named — `showcase_invoice.total` for the plain sum, `showcase_expense_report.total_amount` / `approved_amount` for the `summaryOperations.filter` variant. The rule it broke was the file's own: "relationship types point at the other showcase objects so they have REAL targets."
29+
30+
Tracked in #4544. This is Phase 1; Phase 2 (the cloud authoring-path config-drop fix) is in the `cloud` repo, and Phase 3 lands the Tier-B shapes one verification pass at a time.

examples/app-showcase/src/data/objects/field-zoo.object.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,26 @@ export const FieldZoo = ObjectSchema.create({
131131
label: 'Formula (number × percent)',
132132
expression: cel`(record.f_number == null ? 0 : record.f_number) * (record.f_percent == null ? 0 : record.f_percent) / 100`,
133133
}),
134-
f_summary: Field.summary({ label: 'Roll-up Summary' }),
134+
// NO `summary` field here, deliberately — it is the one type this zoo
135+
// cannot demonstrate. A roll-up aggregates a CHILD object into its parent,
136+
// and the zoo is a leaf: `f_master_detail` below makes it a child of
137+
// `showcase_project`, and nothing is a child of the zoo. A `Field.summary`
138+
// with no `summaryOperations` is not a demo of the type — the engine's
139+
// summary index skips it, so it reads 0 forever.
140+
//
141+
// It sat here as exactly that until the ADR-0078 completeness gate flagged
142+
// it on its first run against a real app (#4544). Worth noting where it
143+
// was: in the object whose whole job is to show what each field type looks
144+
// like, one line below an `f_formula` that IS complete. The canonical
145+
// example of a roll-up in this repo computed nothing — and the rule it
146+
// broke was this file's own: "relationship types point at the other
147+
// showcase objects so they have REAL targets".
148+
//
149+
// `summary` stays covered stack-wide (`collectFieldTypes` walks every
150+
// object): `showcase_invoice.total` is the plain sum, and
151+
// `showcase_expense_report.total_amount` / `approved_amount` show the
152+
// `summaryOperations.filter` variant that rolls ONE child object into two
153+
// different totals.
135154
f_autonumber: Field.autonumber({ label: 'Auto Number' }),
136155

137156
// ── Embedded structured values (stored as JSON on the row) ───────────

packages/cli/src/lint/authoring-rules.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import {
7676
validateStackExpressions,
7777
validateListViewMode,
78+
validateFunctionalCompleteness,
7879
validateViewContainers,
7980
validateWidgetBindings,
8081
validateDashboardActionRefs,
@@ -229,6 +230,24 @@ export const AUTHORING_RULES: readonly AuthoringRule[] = [
229230
source: 'packages/lint/src/validate-list-view-mode.ts',
230231
run: (stack) => validateListViewMode(stack),
231232
},
233+
// [ADR-0078] A Zod-VALID instance that silently does nothing: a `summary`
234+
// with no `summaryOperations`, a `lookup` with no `reference`, a `select`
235+
// with no `options`. Every key is one we know, so #4001's unknown-key
236+
// rejection cannot see it, and the liveness ledger cannot either (it is
237+
// per-property; the properties ARE live). This is the gate between them.
238+
//
239+
// `gating` because the error-severity shapes are fully inert — the field
240+
// reads 0 forever while authoring reports success, which is the failure the
241+
// ADR was written for (cloud#687). Pre-parse so the findings survive an
242+
// unrelated schema error elsewhere in the stack.
243+
{
244+
name: 'validateFunctionalCompleteness',
245+
tier: 'gating',
246+
input: 'normalized',
247+
commands: ALL,
248+
source: 'packages/lint/src/validate-functional-completeness.ts',
249+
run: (stack) => validateFunctionalCompleteness(stack),
250+
},
232251
// A flat list-view object in `views: []` parses to an EMPTY container
233252
// (ViewSchema strips unknown keys): the schema step passes, zero views
234253
// register, and the Console renders nothing. Pre-parse for the same reason.

packages/lint/src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ export { validateStackExpressions } from './validate-expressions.js';
2828
export type { ExprIssue } from './validate-expressions.js';
2929

3030
export { validateListViewMode, LIST_VIEW_FILTERS_IN_VIEWS_MODE } from './validate-list-view-mode.js';
31+
32+
// [ADR-0078] The functional-completeness gate. All judgement lives in the shared
33+
// predicate in `@objectstack/spec/kernel` (sibling of `isIncoherentAggregate`),
34+
// so cloud graph-lint can re-home its duplicate rules onto the same source and
35+
// the AI-build path cannot drift from the framework.
36+
export { validateFunctionalCompleteness } from './validate-functional-completeness.js';
37+
export type {
38+
FunctionalCompletenessFinding,
39+
FunctionalCompletenessSeverity,
40+
} from './validate-functional-completeness.js';
3141
export type { ListViewModeFinding, ListViewModeSeverity } from './validate-list-view-mode.js';
3242
export {
3343
validateFlowTriggerReadiness,
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* Tests for the ADR-0078 completeness validator.
5+
*
6+
* The predicate's own rules are proven in
7+
* `@objectstack/spec`'s `functional-completeness.test.ts`; this file proves the
8+
* WALK — that the rules reach every place a field or list view can be authored,
9+
* in both collection spellings, with a usable location.
10+
*
11+
* That split matters here more than usual. This campaign's recurring finding is
12+
* instruments that report coverage they do not have, and a completeness gate
13+
* that walks half the stack is exactly that: green, and blind to the other half.
14+
*/
15+
16+
import { describe, expect, it } from 'vitest';
17+
18+
import { validateFunctionalCompleteness } from './validate-functional-completeness.js';
19+
20+
const bareSummary = { type: 'summary' };
21+
22+
describe('validateFunctionalCompleteness — the walk', () => {
23+
it('finds an inert field when objects and fields are ARRAYS', () => {
24+
const findings = validateFunctionalCompleteness({
25+
objects: [{ name: 'order', fields: [{ name: 'total', ...bareSummary }] }],
26+
});
27+
expect(findings).toHaveLength(1);
28+
expect(findings[0].rule).toBe('field/summary-without-operations');
29+
expect(findings[0].where).toBe('object "order" › fields.total');
30+
expect(findings[0].path).toBe('objects[0].fields[0].summaryOperations');
31+
});
32+
33+
it('finds the same field when objects and fields are name-keyed MAPS', () => {
34+
// Both spellings are authorable, and a walk that handles only one is the
35+
// half-blind instrument this suite exists to prevent.
36+
const findings = validateFunctionalCompleteness({
37+
objects: { order: { fields: { total: bareSummary } } },
38+
});
39+
expect(findings).toHaveLength(1);
40+
expect(findings[0].where).toBe('object "order" › fields.total');
41+
expect(findings[0].path).toBe('objects[0].fields.total.summaryOperations');
42+
});
43+
44+
it('carries the fix through as the hint', () => {
45+
const [f] = validateFunctionalCompleteness({
46+
objects: [{ name: 'o', fields: [{ name: 'rel', type: 'lookup' }] }],
47+
});
48+
expect(f.hint).toContain('reference');
49+
expect(f.severity).toBe('error');
50+
});
51+
52+
it('reports every inert field, not just the first', () => {
53+
const findings = validateFunctionalCompleteness({
54+
objects: [{
55+
name: 'order',
56+
fields: [
57+
{ name: 'total', type: 'summary' },
58+
{ name: 'rate', type: 'formula' },
59+
{ name: 'acct', type: 'lookup' },
60+
{ name: 'stage', type: 'select' },
61+
{ name: 'ok', type: 'text' },
62+
],
63+
}],
64+
});
65+
expect(findings.map((f) => f.rule).sort()).toEqual([
66+
'field/choice-without-options',
67+
'field/formula-without-expression',
68+
'field/relationship-without-reference',
69+
'field/summary-without-operations',
70+
]);
71+
});
72+
73+
it('walks list views in a container — both `list` and named `listViews`', () => {
74+
const findings = validateFunctionalCompleteness({
75+
views: [{
76+
object: 'task',
77+
list: { type: 'kanban' },
78+
listViews: { by_month: { type: 'calendar' } },
79+
}],
80+
});
81+
expect(findings.map((f) => f.path).sort()).toEqual([
82+
'views[0].list.kanban',
83+
'views[0].listViews.by_month.calendar',
84+
]);
85+
expect(findings.every((f) => f.severity === 'warning')).toBe(true);
86+
});
87+
88+
it('is silent on a complete stack', () => {
89+
expect(validateFunctionalCompleteness({
90+
objects: [{
91+
name: 'order',
92+
fields: [
93+
{ name: 'total', type: 'summary', summaryOperations: { object: 'line', field: 'amt', function: 'sum' } },
94+
{ name: 'acct', type: 'lookup', reference: 'account' },
95+
{ name: 'stage', type: 'select', options: [{ label: 'New', value: 'new' }] },
96+
{ name: 'tags', type: 'multiselect' },
97+
],
98+
}],
99+
views: [{ object: 'order', list: { type: 'grid' } }],
100+
})).toEqual([]);
101+
});
102+
103+
it('never throws on junk or partial stacks', () => {
104+
for (const junk of [
105+
undefined, null, 42, 'x', [], {},
106+
{ objects: 'nope' }, { objects: [null, 7] },
107+
{ objects: [{ name: 'o', fields: 'nope' }] },
108+
{ views: [{ list: null }] },
109+
{ views: 'nope' },
110+
]) {
111+
expect(() => validateFunctionalCompleteness(junk)).not.toThrow();
112+
}
113+
});
114+
});
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
//
3+
// [ADR-0078 Phase 1] The functional-completeness gate — `validate-functional-
4+
// completeness`, the validator the ADR names and, until now, the one it said
5+
// did not exist.
6+
//
7+
// A pure `(stack) => Finding[]` rule (ADR-0019). All judgement lives in the
8+
// SHARED predicate — `@objectstack/spec/kernel`'s `checkFieldCompleteness` /
9+
// `checkViewCompleteness`, the sibling of `isIncoherentAggregate` that cloud
10+
// graph-lint is meant to re-home onto — so this file is only the walk: where
11+
// fields and list views live in a stack, and how a predicate finding becomes a
12+
// lint finding with a location. If a rule seems wrong, fix the predicate (and
13+
// its runtime citation), never this walk.
14+
//
15+
// Why this closes a real hole: instance-completeness checks existed only in
16+
// cloud's AI-build graph-lint, so a stack authored via `os` + a coding
17+
// assistant, an MCP agent, `os validate` in CI, or a hand author got NONE of
18+
// them (`formula_without_expression` existed nowhere in the framework). One
19+
// predicate, every surface — the ADR's core decision.
20+
//
21+
// Runs on the NORMALIZED (pre-parse) stack like validate-list-view-mode: the
22+
// findings must reach the author even when an unrelated schema error would
23+
// stop the parse, and nothing here depends on parse-time defaults.
24+
25+
import {
26+
checkFieldCompleteness,
27+
checkViewCompleteness,
28+
type CompletenessFinding,
29+
} from '@objectstack/spec/kernel';
30+
31+
export type FunctionalCompletenessSeverity = 'error' | 'warning';
32+
33+
export interface FunctionalCompletenessFinding {
34+
severity: FunctionalCompletenessSeverity;
35+
/** Stable rule id from the shared predicate (e.g. `field/summary-without-operations`). */
36+
rule: string;
37+
/** Human-readable location, e.g. `object "order" › fields.total`. */
38+
where: string;
39+
/** Config path, e.g. `objects[2].fields.total.summaryOperations`. */
40+
path: string;
41+
message: string;
42+
hint: string;
43+
}
44+
45+
type AnyRec = Record<string, unknown>;
46+
47+
const isRec = (v: unknown): v is AnyRec => !!v && typeof v === 'object' && !Array.isArray(v);
48+
49+
/** Array-or-name-keyed-map collection → entries with a name and an index label. */
50+
function entriesOf(v: unknown): Array<{ name: string; def: AnyRec; key: string }> {
51+
if (Array.isArray(v)) {
52+
return v.flatMap((def, i) =>
53+
isRec(def) ? [{ name: String(def.name ?? i), def, key: `[${i}]` }] : [],
54+
);
55+
}
56+
if (isRec(v)) {
57+
return Object.entries(v).flatMap(([name, def]) =>
58+
isRec(def) ? [{ name, def: { name, ...def }, key: `.${name}` }] : [],
59+
);
60+
}
61+
return [];
62+
}
63+
64+
function push(
65+
out: FunctionalCompletenessFinding[],
66+
found: CompletenessFinding[],
67+
where: string,
68+
basePath: string,
69+
): void {
70+
for (const f of found) {
71+
out.push({
72+
severity: f.severity,
73+
rule: f.rule,
74+
where,
75+
path: `${basePath}.${f.path}`,
76+
message: f.message,
77+
hint: f.fix,
78+
});
79+
}
80+
}
81+
82+
/**
83+
* Walk every field definition and every list-view definition in the stack
84+
* through the shared completeness predicate.
85+
*/
86+
export function validateFunctionalCompleteness(stack: unknown): FunctionalCompletenessFinding[] {
87+
const out: FunctionalCompletenessFinding[] = [];
88+
if (!isRec(stack)) return out;
89+
90+
// ── Fields: objects[].fields (map or array) ─────────────────────────────
91+
for (const [oi, obj] of entriesOf(stack.objects).entries()) {
92+
for (const field of entriesOf(obj.def.fields)) {
93+
push(
94+
out,
95+
checkFieldCompleteness(field.def),
96+
`object "${obj.name}" › fields.${field.name}`,
97+
`objects[${oi}].fields${field.key}`,
98+
);
99+
}
100+
}
101+
102+
// ── List views: views[] containers → list / listViews.* ────────────────
103+
// (Form views carry no layout-binding contract; field completeness inside
104+
// objects is already covered above.)
105+
for (const [vi, container] of entriesOf(stack.views).entries()) {
106+
const where = container.def.object ? `view container "${container.name}"` : `view container [${vi}]`;
107+
if (isRec(container.def.list)) {
108+
push(out, checkViewCompleteness(container.def.list), `${where} › list`, `views[${vi}].list`);
109+
}
110+
for (const lv of entriesOf(container.def.listViews)) {
111+
push(
112+
out,
113+
checkViewCompleteness(lv.def),
114+
`${where} › listViews.${lv.name}`,
115+
`views[${vi}].listViews${lv.key}`,
116+
);
117+
}
118+
}
119+
120+
return out;
121+
}

packages/spec/api-surface.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,6 +1492,7 @@
14921492
"CompatibilityLevelSchema (const)",
14931493
"CompatibilityMatrixEntry (type)",
14941494
"CompatibilityMatrixEntrySchema (const)",
1495+
"CompletenessFinding (interface)",
14951496
"CustomizationOrigin (type)",
14961497
"CustomizationOriginSchema (const)",
14971498
"CustomizationPolicy (type)",
@@ -1569,6 +1570,11 @@
15691570
"ExecutionContextSchema (const)",
15701571
"ExtensionPoint (type)",
15711572
"ExtensionPointSchema (const)",
1573+
"FIELD_CHOICE_WITHOUT_OPTIONS (const)",
1574+
"FIELD_FORMULA_WITHOUT_EXPRESSION (const)",
1575+
"FIELD_RELATIONSHIP_WITHOUT_REFERENCE (const)",
1576+
"FIELD_SUMMARY_WITHOUT_OPERATIONS (const)",
1577+
"FUNCTIONAL_COMPLETENESS_RULES (const)",
15721578
"FieldChange (type)",
15731579
"FieldChangeSchema (const)",
15741580
"GetPackageRequest (type)",
@@ -1880,6 +1886,7 @@
18801886
"UpgradePlanSchema (const)",
18811887
"UpgradeSnapshot (type)",
18821888
"UpgradeSnapshotSchema (const)",
1889+
"VIEW_LAYOUT_WITHOUT_BINDING (const)",
18831890
"ValidationError (type)",
18841891
"ValidationErrorSchema (const)",
18851892
"ValidationResult (type)",
@@ -1889,6 +1896,8 @@
18891896
"VersionConstraint (type)",
18901897
"VersionConstraintSchema (const)",
18911898
"VulnerabilitySeverity (type)",
1899+
"checkFieldCompleteness (function)",
1900+
"checkViewCompleteness (function)",
18921901
"classifyRequiredCapability (function)",
18931902
"deriveNamespaceFromPackageId (function)",
18941903
"evaluateLockForDelete (function)",

0 commit comments

Comments
 (0)