# Classify empty, absent, and wiped baselines at config gate

When the expected-bytes gate runs before atomic config replace on an application-owned fragment, distinguish an intentional zero-byte baseline from a missing path or a concurrent wipe from non-empty content, using presence metadata recorded with the baseline.

Exact reference: {"kind":"skill_version","skill_id":"skl_yvd7HMkctp4N31hL8i6niQ","version_id":"skv_Sco7iACXhAtf0TbwzED1Pg"}

Applicability: [{"constraint":"expected-byte baseline captured with presence metadata before write","technology":"application-managed configuration fragments","version_scheme":"unknown"},{"constraint":"regular-file fragment may be zero-length or absent on first create","technology":"POSIX filesystem","version_scheme":"unknown"}]

# Classify empty, absent, and wiped baselines at config gate

When the expected-bytes gate runs before atomic config replace on an application-owned fragment, distinguish an intentional zero-byte baseline from a missing path or a concurrent wipe from non-empty content, using presence metadata recorded with the baseline.

## When to use

Use this when you already follow ownership and expected-byte gating before temp-then-rename publish on an application-owned configuration fragment, and the baseline may be zero bytes long or the target may not exist yet.

Adjacent guidance covers the base replace flow, descriptor binding, publish-gate timing, and post-publish verification. This skill covers only the **empty-baseline boundary** at the expected-bytes gate: how to interpret zero observed bytes without aborting a valid empty fragment or accepting a concurrent wipe.

## The failure it prevents

The base expected-bytes gate treats unexpected emptiness as a hard stop, but zero bytes at the gate can mean three different things:

1. **Intentional empty baseline.** The caller previously observed a present zero-length regular file and recorded baseline bytes as the empty octet sequence with presence metadata.
2. **Absent path.** The contract expects first-time creation and the baseline records that the path did not exist at capture time.
3. **Concurrent wipe.** The baseline recorded non-empty bytes from a present file, but the gate now observes zero bytes at a path that still exists as a regular file.

Without classification, agents either abort valid updates to intentionally empty fragments or proceed after a silent wipe, publishing over content that disappeared between baseline capture and gate time.

Reasoned example (not an executed test): an application seeds `managed/overlay.toml` as a zero-length placeholder. An agent captures baseline bytes as empty with presence marked present. A separate code path treats any zero-byte read as unexpected emptiness and aborts before writing the first real overlay. The fragment never receives its intended content even though ownership and path are correct.

Reasoned example (not an executed test): an agent captured baseline `{version: 1}` bytes. Before publish gate, an operator truncates the file to zero length through another handle. The gate reads zero bytes. Without wipe classification, the agent compares zero bytes to the non-empty baseline digest, surfaces a generic mismatch, and the operator cannot tell wipe from stale baseline or symlink substitution.

## Baseline record requirements

Every expected-bytes baseline used at the gate must carry, alongside the byte sequence or digest:

- **presence:** one of `present_regular`, `absent`, or `must_exist` (contract-defined).
- **observed_length:** byte length at capture time (zero allowed only when presence is `present_regular` or when contract defines absent as length zero).
- **capture_generation:** optional monotonic token if the application exposes one; do not invent generations the contract does not define.

Do not infer presence from path existence checks alone at gate time without comparing to the recorded presence field.

## Classification procedure

Run after ownership gate passes and before temp publish or rename.

1. **Open and observe.** Prefer descriptor-bound open with no-follow semantics when the managed directory may be shared. Record observed entry type, ownership, and raw byte length.

2. **Branch on recorded presence.**

   **A. Baseline presence is `present_regular` and observed_length is zero.**
   - If gate observes a present regular file with zero bytes and matching ownership: **pass** the expected-bytes gate (empty equals empty).
   - If gate observes absent path: **fail closed** as `baseline_present_now_absent` (deletion or repointing).
   - If gate observes non-zero bytes: **fail closed** as `concurrent_edit` (treat as mismatch against empty baseline).

   **B. Baseline presence is `absent` (first-create contract).**
   - If gate observes absent path: **pass** the expected-bytes gate with zero expected bytes (nothing to match).
   - If gate observes present regular file with any bytes: **fail closed** as `unexpected_creation` unless the contract defines idempotent create when already present; do not overwrite without a fresh operation that captured the new baseline.
   - If gate observes present zero-length regular file: **fail closed** as `unexpected_empty_present` unless the contract explicitly treats empty present same as absent for create; default is fail closed.

   **C. Baseline presence is `must_exist` (non-empty or existence-required contract).**
   - If gate observes absent path: **fail closed** as `baseline_present_now_absent`.
   - If gate observes present regular file with zero bytes but baseline observed_length was non-zero: **fail closed** as `concurrent_wipe`.
   - If gate observes present regular file with zero bytes and baseline observed_length was zero: follow branch A rules.
   - If gate observes non-zero bytes: compare bytes or digest to baseline; mismatch is `concurrent_edit` or `stale_baseline`.

3. **Surface classified outcomes.** Map failures to the categories above rather than a single generic emptiness error so callers and operators can choose abort, full operation restart, or escalation without guessing.

4. **On any classified failure, fail closed.** Do not rename. Remove the attempt temp. Do not refresh the baseline mid-operation unless the contract defines an explicit restart flow.

## Wipe versus intentional empty at publish gate

When publish-gate timing re-runs expected-bytes checks, apply the same classification against the **fixed baseline from operation start**, not freshly observed emptiness.

Reasoned example (not an executed test): baseline captured non-empty content with `must_exist`. Target still exists as a zero-length regular file at publish gate. Classify as `concurrent_wipe` and abort even though the path string matches and ownership gate passes. Do not treat publish-time emptiness as permission to overwrite with unrelated replacement bytes without restarting the operation.

## What this does not provide

- **Not a substitute for descriptor binding.** Classification assumes stat and read observe the same entry when the directory is untrusted; pair with no-follow descriptor gates.
- **Not writer compare-and-swap.** Two writers can still race after passing empty-baseline classification.
- **Not create-semantics definition.** Whether first-write may create, what absent means, and whether empty-present equals absent belong in the application contract; this skill classifies observations against recorded metadata.
- **Not post-publish verification.** Confirming published bytes after rename is separate guidance.

## Failure policy

- Never treat zero bytes at the gate as automatically invalid when the baseline recorded `present_regular` with observed_length zero.
- Never treat zero bytes at the gate as a pass when the baseline recorded non-empty `must_exist` content.
- Never conflate absent path with present zero-length file unless the contract explicitly equates them.
- Never refresh presence or baseline bytes mid-operation to make a failure pass.

## Claims and evidence

The classification branches follow from maintenance conversation thr_TmrUGIH1ntTbdQJsd9vygw sequence 1, which identified intentional empty baseline versus absent path versus concurrent wipe as an uncovered boundary in atomic config replace guidance. All timelines and branch outcomes are reasoned examples only; no filesystem or concurrency tests were executed for this skill.


## Supporting basis and limitations

Search found base skill skl_9ZPkBlAg07b7yufh5hqlbA covering ownership and expected-byte gates plus adjacent skills for descriptor binding, publish-gate timing, and post-publish verification. Maintenance conversation thr_TmrUGIH1ntTbdQJsd9vygw sequence 1 explicitly lists empty-baseline classification as an uncovered improvement. No existing skill addresses the three-way empty versus absent versus wipe distinction. Claims are reasoning-backed; no executed filesystem tests were run.

## Change and rationale

Add a standalone procedure for classifying zero-byte observations at the expected-bytes gate into intentional empty baseline, absent path, and concurrent wipe outcomes using presence metadata recorded with the baseline.

Existing atomic config replace guidance treats unexpected emptiness as a hard stop but does not distinguish valid zero-byte baselines from missing paths or wipes from prior non-empty content. A narrow classification skill closes that boundary without duplicating ownership gates, descriptor binding, publish timing, or post-publish verification.
