* fix(#2723): reconcile emitted manifest families as a set, not a shared count EXPECTED_MANIFEST_COUNT was a single literal 19 asserted against both the baseline (built at the base ref) and the current tree (built at PR HEAD). Those sides legitimately differ by one family whenever a PR adds or removes a runtime, so no value satisfied both: 19 rejected the current side, 20 rejected the baseline side. Every runtime-adding PR was hard-blocked. Replace the shared literal with three independent signals - the derived family set, the recorded fixture set, and the families present at the base ref - reconciled as sets in both directions. A family may appear or vanish only when the diff plausibly touches the runtime registry, and the failure names the family rather than a count. An absolute floor catches the uniformly shrunken universe a same-count self-check passes vacuously. Found by tracing #2005 (Qoder runtime) through the gate during the ADR-2719 dual-run window. * fix(#2723): read the baseline family set from the ref, not HEAD's registry Review found three defects in the first cut. Blocker: baselineManifestsAtRef enumerated MANIFEST_FAMILIES, which is imported at module load and therefore describes PR HEAD. A runtime REMOVED by the PR is already absent from that list, so the base ref was never asked for it, the baseline silently omitted a family that genuinely existed, and the dropped-family check could never fire in production - while its unit tests passed, because they inject the baseline directly. Enumerate from the ref with git ls-tree instead. Also: narrow the registry-signal set to the two surfaces that actually define the family set, since every extra path widens what excuses an unattributed delta; drop the ack bypass, which was a one-sided escape hatch making removals easier to wave through than additions; and gate the derived/fixtures inputs so malformed values return a verdict rather than an unhandled TypeError. * fix(#2723): filter prototype-shaped family names read from git output baselineFamilyNamesAtRef derives object keys from git ls-tree output rather than a trusted constant, so a fixture committed as __proto__.json would turn the manifests[name] assignment into a prototype write. Compared inline rather than through a Set, which is the form the prototype-pollution analysis recognizes. * fix(#2723): require an exact capability path depth and make the ref test hermetic The remote runner went red on both linux lanes with two real defects. The capability signal matched by prefix+suffix, so 'capabilities/capability.json' (no runtime segment) and 'capabilities/a/b/capability.json' (wrong depth) both attributed a family change and would have excused an unattributed delta. Anchored to an exact single-segment pattern. The ref-derivation test reached for this repo's root commit, which is not stable: the remote runner shallow-clones, so rev-list --max-parents=0 returns the grafted boundary carrying every fixture, and this repo has two root commits locally anyway. It now builds its own git repo containing a family absent from the current registry - the real discriminator, and one the root-commit version could never assert. Lint then caught a third: the test called t.after() without declaring t. * fix(#2723): stop asserting ref enumeration against the ambient checkout The remote runner returned [] for the repo's own HEAD while every hermetic temp-repo assertion in the same test passed. That is this function's documented behavior when git cannot read the ref - the runner works from a shallow clone under a bind-mounted workdir - so the assertion was testing the checkout rather than the code. Dropped it. The temp repo already proves the property that matters, and proves it more strongly: it contains a family absent from the current registry, which a registry-derived implementation could never report. The ambient path stays covered by the real-tree test, which skips explicitly when no base ref is resolvable. A git failure is not silently permissive downstream: baselineManifestsAtRef returns null on an empty family set and the real-tree test asserts the baseline is non-empty.
This commit is contained in:
@@ -44,9 +44,22 @@ const path = require('node:path');
|
||||
const REPO_ROOT = path.join(__dirname, '..', '..');
|
||||
const FIXTURES_DIR = path.join(REPO_ROOT, 'tests', 'fixtures', 'golden-install-parity');
|
||||
|
||||
/** Number of runtime manifests the guard expects to cover. Asserted, so a glob that
|
||||
* silently matches fewer files can never report a vacuous pass. */
|
||||
const EXPECTED_MANIFEST_COUNT = 19;
|
||||
const { MANIFEST_FAMILIES } = require('./install-shared.cjs');
|
||||
|
||||
/**
|
||||
* Number of runtime manifests the guard expects to cover. Asserted, so a glob that
|
||||
* silently matches fewer files can never report a vacuous pass.
|
||||
*
|
||||
* DERIVED, not a literal (#2723). It was `19`, and that same literal was also asserted
|
||||
* against the baseline built at the base ref — two trees that legitimately differ by one
|
||||
* family whenever a PR adds or removes a runtime, which made every such PR unpassable at
|
||||
* any value. Deriving it from the single `MANIFEST_FAMILIES` source keeps the
|
||||
* anti-vacuity property here (this tree's glob must match this tree's registry) while
|
||||
* leaving the cross-tree question to `reconcileFamilies`, which is set-based and
|
||||
* direction-aware. The absolute floor that a shrunken universe cannot satisfy lives with
|
||||
* the derivation as `MINIMUM_MANIFEST_FAMILIES`.
|
||||
*/
|
||||
const EXPECTED_MANIFEST_COUNT = MANIFEST_FAMILIES.length;
|
||||
|
||||
// ─── Emitted roots ────────────────────────────────────────────────────────────
|
||||
// Longest-first: `skills/gsd` (hermes category dir) must win over `skills` for
|
||||
|
||||
Reference in New Issue
Block a user