# PIR-2026-0055 - While registering an incident about itself, PipeRoll's operating agent pushed a hold-until-launch draft to the public registry; the force-push recovery left an immutable public reference to the withdrawn commit


**Disclosure**: A PipeRoll self-incident, drafted by the same Claude agent that caused it, per constitutional rule 4. Third failure in a chain: the seismograph's harm probes ([[PIR-2026-0054]]), the stale-clone force-push during that cleanup (0054's second failure), and this confidentiality failure - caused by the act of documenting 0054.

- `id`: PIR-2026-0055
- `title`: An AI agent tasked with drafting-and-holding a sensitive incident record treated "hold until launch" as a status field on the document rather than a constraint on where it may live, and followed the repository's normal contribution flow (push a branch, open a pull request) to a PUBLIC repository, exposing a pre-release draft weeks before the intended disclosure; the branch-delete and force-push recovery could not fully remove the reference, because a pull-request head ref is retained by the host and the force-push itself leaves an immutable public timeline event
- `date_occurred`: 2026-09-01
- `date_detected`: 2026-09-01 (same session, by the human operator, within minutes)
- `date_disclosed`: 2026-09-15 (published with the seismograph public launch, with 0054)
- `status`: corroborated

### The agent
- `agent_description`: The Claude (Fable 5) agent operating the PipeRoll ops session as the registry's editor. It had just been asked to draft an incident record and HOLD it until a future launch date, so the disclosure would not land during an outreach window.
- `operator_type`: individual (a single human operator directing the agent)
- `autonomy_level`: human-on-the-loop (the human was present and caught it, but the agent selected and executed the publish action with no visibility check)
- `model_stack`: Claude (Fable 5)
- `harness`: an agentic CLI with shell + git + host-API tools; the repo's documented flow is branch -> push -> pull request

### Authority
- `authority_scope`: write access to a public repository and its pull requests via an authenticated host CLI (push branches, open/close/reopen PRs, force-push)
- `funds_at_risk_usd`: 0
- `blast_radius`: public (a public repository; anyone could in principle have read the exposed content)

### The failure
- `root_cause`: operator-error (the instruction "hold until launch" was modeled as a document attribute - a draft status - instead of a placement rule; the agent then applied the repo's normal public contribution flow without checking the target repository was public); contributing: plain-error (the recovery sequence deepened the trace before reducing it)
- `failure_locus`: agent-reasoning (the category error about what "hold" constrains); harness contributing (the publish action had no guard requiring a visibility check for sensitive drafts)
- `exploitation_status`: in-wild-malfunction (no adversary; a self-inflicted disclosure)
- `mechanism`:
  1. Asked to draft a sensitive record and hold it, the agent wrote it with `status: draft` and pushed it as a branch, then opened a pull request - the repo's standard flow - without registering that this repository is public, so the draft became world-readable immediately.
  2. The human operator noticed within minutes and flagged the repository's visibility.
  3. First recovery (close the PR, delete the branch) did not remove the content: the host retains a pull request's head commit on a managed ref that branch deletion does not touch.
  4. Second recovery (restore the branch to the recorded head, reopen the PR, force-push to a harmless stub) moved the managed head ref onto the stub, cleaning the PR's default view and un-pinning the sensitive commit (making it garbage-collection-eligible rather than retained).
  5. But that force-push created an immutable, publicly visible timeline event that references the withdrawn commit. Timeline events cannot be edited or deleted by the operator; only host support can purge them.
- `adversary_present`: no

### Impact
- `severity`: near-miss (the exposed material contained no secrets and no harmful instructions - only a pre-release draft and category labels; the repository had zero forks and zero watchers; the content was never indexed or, as far as observable, retrieved by anyone)
- `direct_loss_usd`: 0
- `indirect_loss_usd`: 0 realized; the exposed asset was disclosure timing, not money
- `downtime`: none (the operator declined the one instant full-removal lever - taking the repository private - because on the host's free tier that would have taken the public site offline)
- `data_exposure`: a pre-release incident draft, briefly, to a zero-audience public repo; no secrets, no harmful content

### Detection and recovery
- `detected_by`: the human operator (within minutes, same session)
- `time_to_detect`: minutes
- `time_to_recover`: same session for the default-view cleanup; the immutable timeline reference persisted
- `remediation`: PR closed and head ref moved to a harmless stub; the sensitive commit un-pinned and left GC-eligible. A host-support purge of the residual reference was drafted but is NO LONGER PURSUED: with 0054 now disclosed publicly under the managed-disclosure decision, the withdrawn draft is simply an early version of a record we are publishing - there is nothing left to protect, and disclosure resolves the residual.
- `structural_fix`: "hold" is a PLACEMENT constraint, not a document-status field - held drafts live only in a private repo or a local file, never staged through a public repo's contribution flow. New doctrine: a visibility check precedes any publish of a sensitive draft; and prefer disclosure timelines that do not depend on suppressing an artifact, since suppression is unreliable on hosted platforms.
- `controls_that_worked`: the human-on-the-loop caught it in minutes; the repo's zero-audience state meant no realized exposure

### Evidence
- `telemetry_grade`: operator-logs (the git/host history of the push, close, reopen, and force-push is visible to the operator; the public timeline event is externally observable)
- `sources`:
  - the public pull-request timeline on the registry repository (externally observable that a force-push occurred; the withdrawn diff is not linked here by design)
  - https://github.com/piperoll/seismograph/blob/main/POSTMORTEM-2026-09.md (the operator's own post-mortem)
  - `independence`: weak - operator-disclosed; the one externally-observable element is the public force-push timeline event
- `confidence`: high (the operator has the full sequence and caused it)

### Verification / schema notes
- A "remediation caused a further incident" chain (0054's cleanup -> this) recurs; a first-class field for coupled failures may be warranted.
- This record is the clearest argument for the managed-disclosure decision on 0054: once you commit to disclosing, the confidentiality residual this record is about stops being a liability. Suppression was the fragile path; disclosure is the durable one.
- Companion: [[PIR-2026-0054]].
