feat(exclusion): identity classifier + git coverage gate primitives (no behavior change) #13
+850
−0
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What
First slice of
docs/EXCLUSION_SPEC.md— the identity classifier and the git coverage gate, as pure, additive helpers. Behavior-neutral: nothing in the archive flow calls them yet (same shape as PR #8's primitives-before-wiring slice). Wiring into the four member-set producers + reclaim re-gate follows in the next PR.Part of the settled staged-hybrid direction (Phase 1 = exclusion). Cardinal rule enforced throughout: it must be impossible to silently drop a data file — exclusion requires tier ∈ {EXCLUDE, OPTIONAL-opted-out} AND a positive git
COVEREDproof; every uncertain/error verdict → back up.Functions added to
archive.pycompile_exclude_spec(spec, exclude_optional)/classify_tier(arcname, compiled)— the 3-tier classifier with spec precedence: DATA allowlist first and un-overridable, then EXCLUDE, then OPTIONAL (first-listed match wins, disposition resolved against the per-asset opt-out), else DATA-default. Rejects bare-extension rules (\.json$,\.md$, …) in the EXCLUDE/OPTIONAL tiers at compile time — the spec's "never classify by extension" rule — while still allowing legitimately extension-based DATA rules (tabular/imagery).git_coverage_preconditions(coverage, repo_root, asset_subtree)— once-per-run fail-safe gate: repo +originpresent, origin not under a protected mount (e.g./depot), durable-remote attestation, no git-LFS, fresh fetch (with FETCH_HEAD-age fallback), clean asset subtree. Any failure → exclusion OFF for the whole run.git_file_verdict(repo_root, full_path, ctx)— the per-file proof (steps L/H/C/P/B/A) returningCOVERED | UNTRACKED | DIRTY | STALE | ERROR. OnlyCOVEREDpermits exclusion; an LFS pointer, a blob/disk size mismatch, an unpushed blob, an EOL-rewriting attribute, or any dirty/staged state all route to back-up.spec_sha256/_parse_durationhelpers (the resume-guard hash and24h/30m/… parsing).Imports stay inside the function bodies (Globus Compute /
dill, invariant #1); the compiled spec (regex objects) is local-only, the raw dict is what crosses the Compute boundary.Tests —
tests/test_exclusion_primitives.py(+39)greenhouse_climate_2026-06.json→ DATA, its…_metadata.jsontwin → EXCLUDE via the lookahead), the status-prefix rule, OPTIONAL first-match + opt-out, and the bare-extension guard.Suite 60 → 99 green (
python3 -m unittest discover -s tests).Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
🤖 Generated with Claude Code