# Re-run publish gates immediately before config rename

After writing a temp file for an application-owned config fragment, re-check ownership and expected bytes on the target path immediately before rename publish. Covers the TOCTOU window the base atomic-replace skill leaves open between first gate and publish.

Exact reference: {"kind":"skill_version","skill_id":"skl_4Lt6Tcb00Cjqidu2BZMwAA","version_id":"skv_-IUncIaR2Nhvzsl2_g-clQ"}

Applicability: [{"constraint":"temp-then-rename publish on one filesystem","technology":"application-managed configuration fragments","version_scheme":"unknown"},{"constraint":"expected-byte baseline captured at operation start","technology":"POSIX filesystem","version_scheme":"unknown"}]

# Re-run publish gates immediately before config rename

## When to use

Use this when you already follow the pattern of validating ownership and expected bytes, writing a same-filesystem temporary file, and publishing with rename. This skill covers only the **publish gate**: the second check on the target path that must happen **immediately before** rename, not at the start of the operation.

Reach for this when the temp write or ownership setup can take non-trivial time (large payload, slow disk, remote filesystem latency, or work between read and publish), or when another actor may edit the managed directory while you prepare the replacement.

## Assumes

The caller already:

- Confirms the target is an application-owned fragment inside a declared managed directory.
- Captures an expected-bytes baseline from a prior read in the same trusted session.
- Writes replacement content to a temporary file on the same filesystem.
- Sets temp ownership and mode to match the application contract.
- Treats rename as torn-read protection only, not writer compare-and-swap.

## The failure it prevents

A single upfront gate leaves a time-of-check to time-of-use window:

1. Writer reads target bytes and passes the expected-bytes gate.
2. Writer spends time building or syncing the temp file.
3. Another process or operator replaces the target with different bytes (or swaps the path).
4. Writer renames the temp over the target anyway, silently discarding the intervening edit.

The upfront gate correctly detected the baseline at step one. It does not prove the baseline still holds at step four.

Reasoned example (not an executed test): an agent reads a 2 KiB overlay, computes a replacement, spends thirty seconds validating schema, meanwhile the application hot-reloads a hotfix into the same fragment, then the agent publishes and overwrites the hotfix.

## Procedure

1. **Keep the baseline fixed.** The expected bytes compared at publish time are the same baseline captured at operation start. Do not refresh the baseline mid-operation unless you abort and restart the whole replace flow.

2. **Re-run ownership gate on the target path.** Immediately before rename, confirm again:
   - Path is still inside the managed directory.
   - Owner identity and mode still match the contract.
   - Entry is still a regular file (not a symlink, directory, or device).

3. **Re-run expected-bytes gate on the target path.** Read the target as raw bytes and compare to the fixed baseline. Any mismatch means a concurrent edit or path substitution occurred after the first gate.

4. **On publish-gate failure, fail closed.**
   - Do **not** rename.
   - Remove the temp file you created for this attempt.
   - Surface a concurrent-edit or stale-baseline outcome to the caller.
   - Do not retry rename against the new bytes without a fresh operation that captures a new baseline.

5. **On publish-gate success, rename once.** Perform a single same-filesystem rename from temp to target. Optionally re-read the published path to record a fresh baseline for the next operation.

## What this does not provide

- **Not writer compare-and-swap.** Two writers can both pass publish gates against the same baseline if they interleave reads before either renames. External serialization or a platform conditional primitive is still required when multiple authorized writers may contend. See the dual-writer boundary example below.
- **Not symlink-attack immunity by itself.** If the managed directory is attacker-influenced, pair this with open-by-descriptor or no-follow open semantics so stat and read target the same inode. That is a separate hardening step.
- **Not crash recovery for orphan temps.** A crash after temp write but before rename leaves an unpublished temp file. Cleaning or reconciling orphan temps on retry is a separate lifecycle concern.

## Boundary examples (reasoned, not executed)

These timelines illustrate limits of the publish gate. They are reasoning aids only; no race tests were run.

### Single external editor during temp preparation

An agent reads a 2 KiB overlay and captures baseline v1. While the agent validates schema for thirty seconds, the application hot-reloads a hotfix so the target becomes v2. Without a publish gate, rename would overwrite v2. With a publish gate, the expected-bytes check against v1 fails and rename is blocked.

### Dual authorized writers with caller retry

1. Writer A and Writer B both start against baseline v1.
2. Writer A passes the publish gate while the target still holds v1, renames, and the target becomes v2.
3. Writer B runs the publish gate; bytes are v2 but baseline is v1; B correctly aborts per step 4.
4. The caller retries Writer B **without a full operation restart**: B captures a new baseline v2 while still holding replacement bytes computed when the target was v1.
5. A third actor publishes v3 to the target.
6. Writer B runs the publish gate when the target still holds v2; the v2 baseline matches and the gate passes.
7. Writer B renames; the target becomes B content, overwriting v3.

What this shows:

- The publish gate behaved correctly at steps 3 and 6 against each baseline.
- Expected-bytes gating is not writer serialization and does not make rename a compare-and-swap.
- Caller retry that only refreshes the baseline without restarting the whole replace flow can reintroduce silent overwrite when other actors still publish between gate and rename or between retries.

Required response when step 3 or similar abort occurs: discard the attempt temp, surface the concurrent-edit outcome, and require the caller to **restart the entire replace operation** with explicit consent before capturing a new baseline. Do not treat re-baselining alone as sufficient retry.

## Failure policy

- Treat publish-gate mismatch as **abort**, not as permission to overwrite newer content.
- Never skip the second gate because the first gate already passed.
- Never widen the baseline at publish time to match newly observed bytes unless the operation is explicitly restarted with caller consent.
- Never auto-retry after abort by only refreshing the baseline; a retry must restart the full replace flow including recomputing replacement content against the current target.

## Claims and evidence

The publish-gate sequence follows from standard time-of-check to time-of-use reasoning applied to the temp-then-rename pattern described in existing atomic config replace guidance. The hotfix-overwrite and dual-writer retry timelines are reasoned examples only; no executed tests were run for this update.


## Supporting basis and limitations

Derived from maintenance conversation thr_vLC8S-SuuKqCl-1hDKxb_A sequences 1 and 2. The dual-writer retry timeline is reasoned interleaving only; no filesystem or concurrency tests were executed. The existing hotfix-overwrite example remains reasoned only as well.

## Change and rationale

Add a reasoned dual-writer plus caller-retry timeline under boundary examples, sharpening the not-writer-compare-and-swap limit and tying it to the existing fail-closed retry policy.

Maintenance reasoning on thread thr_vLC8S-SuuKqCl-1hDKxb_A showed the skill names the not-writer-CAS limit but only illustrates single-writer concurrent overwrite. A second timeline makes the caller auto-retry anti-pattern concrete: publish gate abort is correct, yet re-baselining without a full operation restart can still end in silent overwrite when multiple authorized writers or external editors contend.
