Skip to content

fix(server): purge imported v1 rows the v2 runtime never reads - #1723

Merged
donjor merged 1 commit into
hyprwsfrom
t3/compact-legacy-event-store
Oct 12, 2026
Merged

donjor merged 1 commit into
hyprwsfrom
t3/compact-legacy-event-store

Conversation

@donjor-agent

@donjor-agent donjor-agent Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

🤖 claude/anthropic claude-opus-5-5 (high)

Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On ugrindtime that dead data is most of a 12 GB database:

Rows Count Payload
V1 events 2.58M 3.18 GB, plus indexes
projection_thread_activities 1.81M 2.86 GB, no reader

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's ProjectionMaintenance.compactEventStore (pingdotgg/t3code#2829) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 thread.metadata-updated events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

Change

Code

  • New file: LegacyV1Purge.fork.ts
  • Hook: two lines in the V1 importer
  • When: after the background transcript import

Rows

  • Events: V1 rows of imported threads
  • Activities: whole table
  • Kept: V2, project, and pending-thread events

Pacing

  • Pages: 200 rows, 50 ms pause between
  • Failure: logged; the next startup resumes

Measured on a full copy of the live database

  • Live data: 12.09 GB to 3.08 GB
  • Page hold: p50 8 ms, p99 171 ms
  • Expected first run: about 25 min, background
  • Later runs: no-op

Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged Purged imported legacy v1 rows:

  1. Stop t3code.service
  2. Back up ~/.t3/userdata/statev2.sqlite
  3. Run sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM
  4. Start the service

Follow-ups

  • Growth: turn-item.updated adds ~260 MB/day
  • Markers: store outside events first

Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

Verification

  • New test: 1001-row purge keeps live rows
  • Mutation check: fails without import filter
  • Legacy tests: 10 of 10 pass
  • Typecheck: apps/server, exit 0
  • Fork CI: vp run fork:ci, exit 0
  • Not checked: a live server on this build

Claude Code, claude-opus-5-5.

Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
@rsi-software-agent

rsi-software-agent Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

🩺 Aftercare 060234f ⚠️ not reviewed: execution timeout

No reviewer result for 060234f.

⚠️ Sandbox agent job exceeded its 20 min execution timeout.

Your reply is kept; re-run the rsi:aftercare Check or add its label to retry.

Details
Head Result Time Check
060234f ⚠️ not reviewed: execution timeout 32 min run

@donjor
donjor merged commit 62482a0 into hyprws Oct 12, 2026
@donjor
donjor deleted the t3/compact-legacy-event-store branch October 12, 2026 09:26
donjor added a commit that referenced this pull request Oct 12, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 13, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 13, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 20, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 20, 2026
…#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor pushed a commit that referenced this pull request Oct 20, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 20, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 21, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 21, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 21, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 21, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 21, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 21, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 21, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 21, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 21, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 21, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 22, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 22, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 22, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 22, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 23, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 23, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 24, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 24, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 27, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 27, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 27, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
donjor added a commit that referenced this pull request Oct 27, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 27, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 27, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 28, 2026
## Problem

The V2 runtime never reads a thread's V1 events after its transcript import, yet nothing deletes them.
On `ugrindtime` that dead data is most of a 12 GB database:

| Rows | Count | Payload |
| --- | --- | --- |
| V1 events | 2.58M | 3.18 GB, plus indexes |
| `projection_thread_activities` | 1.81M | 2.86 GB, no reader |

Every page of it adds disk IO to checkpoints, backups, and cold reads.

Upstream's `ProjectionMaintenance.compactEventStore` (`pingdotgg#2829`) drops the same V1 events, but nothing calls it in production.
Its thread-state supersession would also delete the fork's legacy issue markers, which are V2 `thread.metadata-updated` events.
Losing a marker re-runs the issue import and undoes V2 unlinks.

## Change

### Code

- **New file:** `LegacyV1Purge.fork.ts`
- **Hook:** two lines in the V1 importer
- **When:** after the background transcript import

### Rows

- **Events:** V1 rows of imported threads
- **Activities:** whole table
- **Kept:** V2, project, and pending-thread events

### Pacing

- **Pages:** 200 rows, 50 ms pause between
- **Failure:** logged; the next startup resumes

### Measured on a full copy of the live database

- **Live data:** 12.09 GB to 3.08 GB
- **Page hold:** p50 8 ms, p99 171 ms
- **Expected first run:** about 25 min, background
- **Later runs:** no-op

## Reclaiming disk

The purge frees pages for reuse, so the file stops growing but does not shrink.
To shrink it once, after the purge has logged `Purged imported legacy v1 rows`:

1. Stop `t3code.service`
2. Back up `~/.t3/userdata/statev2.sqlite`
3. Run `sqlite3 ~/.t3/userdata/statev2.sqlite VACUUM`
4. Start the service

## Follow-ups

- **Growth:** `turn-item.updated` adds ~260 MB/day
- **Markers:** store outside events first

## Scope and approval

Refs #1720.
The maintainer chose this narrow purge over wiring upstream's compaction.

## Verification

- **New test:** 1001-row purge keeps live rows
- **Mutation check:** fails without import filter
- **Legacy tests:** 10 of 10 pass
- **Typecheck:** `apps/server`, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a live server on this build

Claude Code, claude-opus-5-5.

## Fork trailers

Squashes:

- 7595062 fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)
- d1395ce fixup! fix(server): purge imported v1 rows the v2 runtime never reads (#1723) (#1723)

Fork-Domain: upstream-fixes
Fork-Tier: bugfix
Fork-Upstreamable: yes
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 28, 2026
…ses (#1724)

## Problem

No fork release has published since 2026-10-11 22:26 UTC.
Upstream re-pointed its moving `android-nightly` tag, and plain `git fetch --tags` refuses to overwrite a tag:

```text
! [rejected] android-nightly -> android-nightly  (would clobber existing tag)
```

That fetch fails in release preflight and in the upstream sync mirror, so neither has run since.
#1721, #1722, and #1723 have no build.

## Change

- **Release preflight:** `git fetch --tags --force`
- **Sync mirror fetch:** `git fetch --tags --force`
- **Sync mirror push:** `push --tags --force`
- **Local `fork:sync`:** same fetch flag
- **Doc:** `fork-sync.md` fetch row

Fork tags never share a name with an upstream tag, so forcing only moves upstream-owned tags.
The `main` push stays unforced.

## Scope and approval

The maintainer asked to land #1723 and stage its nightly; this unblocks that release.

## Verification

- **Repro:** plain fetch rejected, exit 1
- **Fix:** forced fetch updates the tag, exit 0
- **Fork CI:** `vp run fork:ci`, exit 0
- **Not checked:** a release run on this head

Claude Code, claude-opus-5-5.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant