Skip to content

A blank conversation a collection holds is kept, never resumed, and shown as live - #2337

Merged
AbirAbbas merged 6 commits into
workstreams/mainfrom
workstreams/stab2-fix-blank
Nov 4, 2026
Merged

AbirAbbas merged 6 commits into
workstreams/mainfrom
workstreams/stab2-fix-blank

Conversation

@AbirAbbas

@AbirAbbas AbirAbbas commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The integration branch keeps a never-spoken conversation that a collection references instead of reaping it. That rule leaked into two other decisions:

  • Launch resume. The kept-check lived inside the emptiness predicate, so a held blank (or every blank, when the collections file could not be read) counted as spoken and a launch without an explicit session resumed it ahead of the person's last real conversation. The emptiness check now reads only content; a team or collection reference keeps a blank out of both the resume and the reuse piles, and every removal path (v3EmptySession, v3ReapEmpty, reapBlank, the background sweep) still refuses it.
  • Collection targets. collections.open / collections.expand resolved agents only from agents.list, which leaves named blanks out, so a held blank agent read as deleted after a restart although agents.open finds it. A missing id is now looked up once on disk (appRowOnDisk) before it is called deleted; blanks stay out of agents.list and nothing is opened.

Found by the stability review after the Workstreams plan's architecture move (STAB2, findings E-B1 and E-M1).

Validation contract

Item Test (cmd/codeaf/appcollectionkeep_test.go)
An older spoken conversation is resumed over a newer held blank; the blank survives TestACollectionHeldBlankIsNeverTheConversationALaunchResumes
A project whose only folder is a held blank gets a fresh conversation; the blank survives same
An unreadable collections file: blanks are neither resumed nor removed same
An unreferenced blank is still reaped / reused as before same, TestABlankConversationCanBeReapedAfterItsLastCollectionReferenceIsRemoved
A held blank agent is live in collections.open and counted in collections.expand after a restart; agents.list still excludes it; an id with no folder is deleted TestACollectionHeldBlankAgentIsLiveAfterRestart

| A permanently deleted conversation (or one pending deletion) stays deleted in its collection; relink to it is refused | TestAPermanentlyDeletedConversationStaysDeletedInItsCollection |
| A collection read never opens a held blank crew member to resolve its task/process children | TestACollectionReadNeverOpensAHeldBlankToResolveItsChildren |

No wire contract change. Nothing stubbed.

Review and CI

Three fresh review rounds: round 1 found that the disk fallback revived permanently deleted conversations (fixed: rows pending deletion or carrying the deletion marker stay deleted); round 2 found the fallback shared the owner cache, so a collection read could open a crew member to look for a missing child (fixed: the fallback serves conversation members only, from its own cache); round 3 found no blocker or major.

CI: touched codeaf and touched packages green. light gate (and so check) red only on TestNoRoadInTheMemoryEngineHasMoreEndingsThanTheCeiling and TestNoRoadInTheTaskEngineHasMoreEndingsThanItsLedgerRow, both also failing on the current app/v3 tip (79c8a94, Full check run 41735053886).

🤖 Generated with Claude Code

AbirAbbas and others added 6 commits November 3, 2026 20:43
Launch resumed a never-spoken conversation that a collection references, ahead
of the last spoken one, because "kept" and "spoken" shared one predicate. The
emptiness check now reads only content; references keep a blank out of both
the resume and the reuse piles, and every removal path still refuses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The resolver built its view from agents.list, which leaves named blanks out,
so collections.open and collections.expand called them deleted. A missing id
is now looked up once on disk before it is called deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The on-disk fallback found the metadata a permanent deletion keeps, so the
resolver would have shown a deleted conversation as live and allowed a relink
to it. A row pending deletion, or a folder with the deletion marker, now stays
deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A blank found on disk shared the listing cache that task and process members
use to find their owner, so a collection read could open a crew member's
conversation to look for a child that does not exist. The fallback now serves
conversation members only, from its own cache.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AbirAbbas
AbirAbbas merged commit 4b1bb03 into workstreams/main Nov 4, 2026
4 of 6 checks passed
@AbirAbbas
AbirAbbas deleted the workstreams/stab2-fix-blank branch November 4, 2026 02:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant