Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions packages/cli/test/union-fold-command-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,55 @@
* that fires on any `packages[]` at all — would satisfy the failing case alone.
* The pair asserts what the card actually claims: that the option-B stack is
* READ, not that it is rejected.
*
* ## ⚠️ [#18897] The refusal cases were satisfied by an IMPOSTOR — and the
* ## impostor is a SIBLING PASS that arrived after this file was written
*
* These three refusal cases claimed to pin `authoringRuleUnionStack` — the fold
* that makes the rule table's INPUT non-empty on an option-B stack. They could
* not. Since #18677 (`os validate`) and #18778 (`os lint`) all three doors ALSO
* run `runPerPackageAuthoringRules`, which judges each `packages[]` entry as its
* own stack. That pass sees this fixture's one package body, raises the SAME
* rule at the SAME path, and refuses with the same exit code. ⇒ `exit 1` +
* `contains(RULE)` + `contains(RULE_PATH)` is satisfied by EITHER mechanism, so
* the control could not tell the fold from its sibling.
*
* ⛔ Not reasoned about — measured by ablation, at `origin/main` 13d52947d8:
*
* ablation this file
* `authoringRuleUnionStack` never folds 6/6 GREEN
* `runPerPackageAuthoringRules` yields no findings 6/6 GREEN
* BOTH of the above 3 RED
*
* ⭐ Either mechanism alone kept every case green; only deleting both turned the
* three refusal cases red. That is what a control satisfied by something other
* than the mechanism it names looks like from the inside — green, and green for
* the wrong reason.
*
* ## What discriminates them: a PEDIGREE, ⛔ not a count and ⛔ not an exit code
*
* `runPerPackageAuthoringRules` prefixes the `where` of every finding IT raises
* with `package '<id>' — `; it owns that prefix, and three sibling files pin the
* same regex. The union run renders `where` bare. Measured on THIS fixture, same
* command, with only the fold's presence moving:
*
* fold intact • object "ob_order" · field "ghost": …
* fold ablated • package 'com.example.ob' — object "ob_order" · field "ghost": …
*
* So each refusal case now asserts the refusal carries NO per-package prefix —
* the finding is the UNION run's, which is the mechanism this file is about.
*
* ⚠️ A real falsifier — a fixture in which the impostor structurally CANNOT
* raise this finding — does not exist for this rule class, and that was measured
* rather than assumed: the per-package pass is a SUPERSET of the union run for
* reference rules (`utils/artifact-packages.ts`: "the per-package run is
* STRICTER"), because each body is judged with the artifact's own `packages[]`
* handed in as resolution context. A name no package provides therefore dangles
* in BOTH views, under every arrangement of packages. ⇒ here the pedigree is the
* whole discriminant, and the negative assertion is made load-bearing by the
* POSITIVE control at the foot of this file — a fixture whose finding really is
* per-package-only. Without that pair, "the prefix is absent" would be satisfied
* by a prefix this suite never produces at all.
*/

import { describe, expect, it } from 'vitest';
Expand All @@ -69,6 +118,15 @@ const AUTHORING_COMMANDS = ['validate', 'lint', 'build'] as const;
const RULE = 'object-reference-unknown';
const RULE_PATH = 'objects[0].fields.ghost.reference';

/**
* [#18897] The `where` prefix `runPerPackageAuthoringRules` puts on every
* finding IT raises — the one thing that tells the union run's finding apart
* from the per-package pass's copy of it. ⛔ Not this file's guess at a format:
* the pass owns the prefix, and `validate-/lint-per-package-authoring-parity`
* and `build-text-face-advisory-count` pin the identical regex.
*/
const PER_PACKAGE_WHERE = /package '[^']+' — /;

/**
* The card's repro verbatim: no top-level `objects`, one `packages[]` entry
* carrying an object whose `ghost` lookup points at an object that does not
Expand Down Expand Up @@ -100,6 +158,73 @@ const optionBStack = (reference: string): Record<string, unknown> => ({
],
});

/**
* [#18897] The POSITIVE half of the pedigree pair: a project whose ONLY
* author-time finding is one the union run genuinely cannot see.
*
* `core` owns `ob_account`; `orders` owns the view that displays
* `ob_account.industry`. Folded into one union the field HAS a consumer and
* nothing is raised; judged per package, `core` declares a field nothing in
* `core` reads — so the survivor is the per-package pass's alone and carries its
* `where` prefix. It is the falsifier shape PR #18878 landed in
* `lint-per-package-authoring-parity.test.ts`, and it is here for one job: to
* prove that {@link PER_PACKAGE_WHERE} is a prefix this suite CAN observe, so
* the refusal cases' `toBe(false)` is a measurement and not the silence of a
* regex that never matches anything. ⛔ Do not remove the view to "simplify" it.
*/
const perPackageOnlyStack = (): Record<string, unknown> => {
const coreManifest = {
id: 'com.example.obflip.core', name: 'obflip core', namespace: 'ob',
version: '1.0.0', type: 'app', engines: { protocol: '^17' },
};
const coreObjects = [{
name: 'ob_account', label: 'Account', pluralLabel: 'Accounts', sharingModel: 'private',
fields: {
name: { name: 'name', type: 'text', label: 'Account Name', required: true },
industry: { name: 'industry', type: 'text', label: 'Industry' },
},
}];
const coreApps = [{
name: 'ob_crm', label: 'OB CRM',
navigation: [{
id: 'sales_group', type: 'group', label: 'Sales',
children: [{ id: 'nav_accounts', type: 'object', objectName: 'ob_account', label: 'Accounts' }],
}],
}];
const ordersManifest = {
id: 'com.example.obflip.orders', name: 'obflip orders', namespace: 'ob',
version: '1.0.0', type: 'module', engines: { protocol: '^17' },
dependencies: { 'com.example.obflip.core': '^1.0.0' },
};
const ordersObjects = [{
name: 'ob_order', label: 'Order', pluralLabel: 'Orders', sharingModel: 'private',
fields: {
name: { name: 'name', type: 'text', label: 'Order Number', required: true },
account: { name: 'account', type: 'lookup', label: 'Account', reference: 'ob_account' },
},
}];
const ordersViews = [
{
name: 'ob_account_list', label: 'Account List', object: 'ob_account',
list: { label: 'Account List', columns: ['name', 'industry'] },
},
{
name: 'ob_order_list', label: 'Order List', object: 'ob_order',
list: { label: 'Order List', columns: ['name', 'account'] },
},
];
return {
manifest: coreManifest,
objects: [...ordersObjects, ...coreObjects],
apps: [...coreApps],
views: [...ordersViews],
packages: [
{ manifest: { ...ordersManifest, objects: ordersObjects, views: ordersViews } },
{ manifest: { ...coreManifest, objects: coreObjects, apps: coreApps } },
],
};
};

interface Run {
code: number;
output: string;
Expand Down Expand Up @@ -152,6 +277,23 @@ describe('#17069 — os validate and os lint judge the option-B stack, not an em
`os ${command} named ${RULE} at a different path than the other doors — the three commands ` +
`must report one finding one way`,
).toContain(RULE_PATH);
// ⭐ [#18897] PEDIGREE. Everything above this line is satisfied by the
// per-package authoring pass, which raises the same rule at the same path
// on this one-package body and refuses with the same code — measured: with
// `authoringRuleUnionStack` ablated all six cases here stayed GREEN, and
// only ablating the per-package pass TOO turned these three red. The union
// run renders `where` bare; the per-package pass prefixes it. So the
// absence of that prefix is what makes this case a reading of the FOLD.
expect(
PER_PACKAGE_WHERE.test(run.output),
`os ${command} refused this stack through the PER-PACKAGE authoring pass, not through the ` +
`union fold this file pins: the finding carries ${String(PER_PACKAGE_WHERE)}, the prefix ` +
`runPerPackageAuthoringRules puts on its own findings. The fold is what makes the rule ` +
`table's INPUT non-empty on an option-B stack, and with it gone this command is refusing ` +
`for a reason #17069 did not buy. ⛔ Do not answer this by deleting the assertion — the ` +
`pedigree is the only thing here that can tell the two mechanisms apart.` +
`\n--- output ---\n${run.output}`,
).toBe(false);
},
180_000,
);
Expand All @@ -171,4 +313,34 @@ describe('#17069 — os validate and os lint judge the option-B stack, not an em
},
180_000,
);

it.each(AUTHORING_COMMANDS)(
'⭐ PEDIGREE CONTROL — os %s DOES render the per-package prefix when the finding is the pass\'s own',
(command) => {
// The other half of the pair above. A `toBe(false)` on a regex is only a
// measurement if the same suite can make it true; without this case an
// absent prefix and a prefix nothing ever emits read identically — which
// is the whole class of defect #18897 is about, one level up.
const run = runCommand(command, perPackageOnlyStack());
expect(
run.code,
`os ${command} exited ${run.code} on the per-package-only fixture. Its single finding is an ` +
`ADVISORY (field-no-consumers), so every door reports it and none of them fails on it.` +
`\n--- output ---\n${run.output}`,
).toBe(0);
expect(
PER_PACKAGE_WHERE.test(run.output),
`os ${command} raised no per-package-prefixed finding on a fixture whose only finding the ` +
`union run cannot see (core declares ob_account.industry; orders owns the view that ` +
`displays it). Either the pass stopped running on this door, or the prefix was re-spelled ` +
`— and in both cases the refusal cases above are asserting the absence of something this ` +
`suite no longer produces.\n--- output ---\n${run.output}`,
).toBe(true);
// …and it is that field, not some other advisory that happens to be
// prefixed: the pedigree names the member, never just the shape.
expect(run.output, `os ${command} prefixed a finding, but not the one this fixture is built on`)
.toContain('industry');
},
180_000,
);
});
Loading