Skip to content

test(discovery): enforce manifest invariants in CI - #59

Closed
pengyuzhang wants to merge 5 commits into
mainfrom
pr/03-manifest-checks
Closed

test(discovery): enforce manifest invariants in CI#59
pengyuzhang wants to merge 5 commits into
mainfrom
pr/03-manifest-checks

Conversation

@pengyuzhang

Copy link
Copy Markdown
Collaborator

Stacked on #58.

Three checks that are properties of the manifest rather than of a machine, plus the workflow job that runs them. They take milliseconds and need no VM, so the expensive instrument never has to be the thing that discovers a typo.

The checks

Every catalog entry has a manifest row. The one that keeps the inventory honest as the catalog grows. A catalog entry with no row is a tool the collector claims to recognize and that nothing ever verifies — adding one should fail CI until somebody adds the row. This single check does more than any process rule.

Every id is unique and every series contiguous. A gap is almost always a deleted row rather than a deliberate hole; a duplicate silently makes one of the two rows unscoreable.

Every {{canary:x}} has a declared x, and every declared canary is planted. An undeclared canary is worse than a missing one — it gets planted, never searched for, and the run reports a clean redaction check it never made.

The catalog is an input

The harness does not read the collector's tree, so --catalog is passed in. A run given no catalog prints not checked rather than reporting a pass: a check that did not run is not a check that passed, and the difference matters when this gates a merge.

Once adr_discovery/catalog.json is on main, the CI step becomes --catalog adr_discovery/catalog.json and the coverage check starts gating.

Unresolved vendor sources are reported, not failed

57 app-installer and vendor-binary descriptors still have no download URL. That blocks one entry each; it does not invalidate the manifest, so it prints and moves on.

Verification

$ python3 -m tests.manifest_check
manifest: 120 entries
  mac    110 applicable
  linux  105 applicable
  win    103 applicable
  catalog: not checked (pass --catalog path/to/catalog.json)
  sources: 57 vendor descriptors unresolved
check: passed

$ python3 -m unittest discover -s tests -t . -q
Ran 14 tests in 0.010s
OK

Turns the inventory in tests/README.md into data the harness can execute:
every row becomes an entry with a stable id, the platforms it applies to, the
block that describes how it arrives, and the fields the collector is expected
to get right about it.

TOML rather than YAML so the file keeps its comments - the manifest is
reviewed like code, and the reasoning beside an entry is most of its value -
and so the loader needs nothing but the standard library.

Four entry shapes cover all 120 rows, distinguished by which block an entry
carries: install, declare, create or state. The recipe family is derived from
that block rather than declared beside it, so the two can never disagree about
how an entry is executed.

Validation happens at load: an unpinned package, a variant naming a base that
does not apply on its platform, or an unknown install method fails immediately
rather than twenty minutes into a VM run.
Three properties of the manifest that need no VM, and so belong in ordinary
per-commit CI beside the fast tests rather than in the expensive instrument.

Every catalog entry has a manifest row. This is the one that keeps the
inventory honest over time: a catalog entry nothing verifies is a tool the
collector claims to recognize and that nothing ever checks, so adding one
should fail CI until somebody adds the row.

Every id is unique and every series contiguous. A gap is almost always a
deleted row rather than a deliberate hole, and a duplicate id silently makes
one of the two rows unscoreable.

Every canary referenced is declared, and every canary declared is planted. An
undeclared canary is worse than a missing one: it is planted, never searched
for, and the run then reports a clean redaction check it never made.

The catalog is an input rather than a path this package goes looking for - the
harness treats the collector as a black box - and a run given no catalog says
the coverage check did not run rather than reporting it passed.
lghupan
lghupan previously approved these changes Aug 23, 2026
@pengyuzhang
pengyuzhang changed the base branch from pr/02-manifest to main August 23, 2026 06:48
@pengyuzhang
pengyuzhang dismissed lghupan’s stale review August 23, 2026 06:48

The base branch was changed.

# Conflicts:
#	Discovery/tests/manifest.py
#	Discovery/tests/test_manifest.py
@pengyuzhang
pengyuzhang deleted the pr/03-manifest-checks branch August 23, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants