## Update the batch boundary marker

Write `.pinappai/last-applied.json` at the repo root. This is the boundary
marker for PinAppAI's iteration loop — every batch that applies changes to
source overwrites it with that batch's timestamp; every `/changes/` regeneration
reads it to scope "what changed since the last batch was applied." Without this
step, the next `/changes/` regeneration would re-include this batch's changes as
though they were new content for review.

Use the actual current system time at run completion — run
`date -u +%Y-%m-%dT%H:%M:%SZ` (or your stack's equivalent) and substitute
literally. **No placeholders.**

### If `.pinappai/last-applied.json` does NOT exist yet (first install / bootstrap)

Create the directory if needed (`mkdir -p .pinappai`), then write the file with a
`note` field that explains the bootstrap context:

    {
      "last_applied_at": "<current UTC ISO 8601 timestamp>",
      "note": "Bootstrap — installed at <run-context, e.g. 'repo setup' / 'first install'>"
    }

### If `.pinappai/last-applied.json` already exists (every subsequent batch)

Overwrite it with the current run's timestamp + a one-line summary of what this
batch did:

    {
      "last_applied_at": "<current UTC ISO 8601 timestamp>",
      "bundle_summary": "<short summary, e.g. '12 applied, 1 blocked, 0 unclear, 0 skipped'>"
    }

The previous file's content is no longer needed once this batch supersedes it —
the `/changes/` generator on the next iteration reads ONLY the latest
`last_applied_at` and uses it as the "since" boundary for `git log`. The
overwrite is intentional — with ONE exception, below.

### If this batch lands WITHOUT a `/changes/` page (apply's Case-A "n")

When an Apply batch edits source but the user declines to generate the
`/changes/` page (Case A answered `n`), the batch is applied yet **unreviewed**
— no page, no `register_change_items`, no review chip. A plain marker overwrite
would tell the next `/changes/` generation "this batch is settled", stranding it
forever. Instead, the marker MUST record the unreviewed range:

    {
      "last_applied_at": "<current UTC ISO 8601 timestamp>",
      "bundle_summary": "<short summary>",
      "changes_page_pending": true,
      "batch_base_sha": "<output of `git rev-parse HEAD`, captured BEFORE the landing commit>"
    }

`batch_base_sha` is the parent of the landing commit, so a later
`git log <batch_base_sha>..HEAD` INCLUDES this batch. Two rules:

- **If the existing marker already carries `changes_page_pending: true`**
  (a previous batch was also declined), PRESERVE its `batch_base_sha` —
  never advance it. The oldest unreviewed base wins, so every declined
  batch stays inside the pending range.
- **Whoever generates the `/changes/` page next** (a standalone
  `/pinappai:generate-changes-page` run, or a later apply's Case-A `Y`)
  clears both fields when rewriting the marker — the pending debt is paid.

### Always: include the marker file in your "Affected files" list

The marker file change must land in the **same commit** (or at least the same
push) as the source-edit changes from this run. If the human picks a commit
strategy from the landing-chooser block, the marker file goes in alongside the
other affected files. Don't leave it uncommitted in the working tree — that
splits the iteration boundary across commits and makes the next `/changes/`
regeneration's diff range non-deterministic.
