Skip to content

feat(db): add harness ingress grants and retirement fences - #5655

Open
iscekic wants to merge 1 commit into
shared-agent-harness-3bb0-s5from
shared-agent-harness-3bb0-s6
Open

feat(db): add harness ingress grants and retirement fences#5655
iscekic wants to merge 1 commit into
shared-agent-harness-3bb0-s5from
shared-agent-harness-3bb0-s6

Conversation

@iscekic

@iscekic iscekic commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

No new behavior — This change prepares later chat features without enabling them.


Summary

quick_chat_messages adds provenance, server_projection_key, ingress_acknowledged_at, ingress_lease_token, and ingress_lease_expires_at; historical rows and old writers default to unacknowledged legacy messages. agent_harness_clients, agent_harness_conversation_grants, and agent_harness_invitation_results add revocable access records and conversation-lifetime invitation replay; agent_harness_conversation_registry and agent_harness_retirements preserve orphan discovery and permanent fences. Migration 0234 prepares this PostgreSQL storage without activating runtime delivery; old message identity, text, timestamps, and nullable, nonunique client_id remain unchanged.

Files
  • packages/db/src/schema.ts — Source, modified (+142 lines): adds partial indexes for unacknowledged legacy messages and lease expiry, without timestamp cutoffs. An index makes projection keys globally unique; a check requires keys for harness messages and forbids keys for legacy messages. Ingress and retirement leases require a token and expiry together. Browser/mobile registrations store server-derived session_binding references and versioned supported_tools, never bearer or refresh tokens. Grants link the user, client, thread, generation, expiry, and revocation; user IDs remain arbitrary text. Invitation results use (thread_id, operation_id) and store input_digest, invitation_id, and canonical_result containing invitationId, acceptInviteUrl, and pending emailStatus. Results have no invitation foreign key or expiry and cascade only with their thread. The registry stores nullable user/organization links for discovery, not authority. Retirements use (thread_id, generation), account_deleted or context_retired reasons, and an index for pending delivery. Generations default to zero and reject negatives. The registry and retirement records have no foreign keys, so cascades cannot remove them. Retirement acknowledgment ends retries but retains the fence.

anonymizeCloudUserData, used by softDeleteUser, now writes account_deleted retirement fences before removing chat payloads, including registry entries whose threads already disappeared. It uses the registered generation or zero for old threads, preserves existing fences on retry, and clears registry ownership links. It deletes clients, grants, messages, threads, and invitation results while retaining discovery identifiers; existing callers, deletion responses, and subscription checks stay unchanged.

Files
  • apps/web/src/lib/user/index.ts — Source, modified (+39/-11 lines): extends transactional cleanup and documents retained identifiers. It clears both user and organization links for registry rows matched by user ownership or thread ownership.

Jest roots now includes database tests alongside web tests, so continuous integration (CI) discovers both. The existing transforms, mappings, test selection, and setup hooks remain unchanged; this expands discovery without replacing the web suite.

Files
  • apps/web/jest.config.ts — Source, modified (+1 line): adds the database source root and explicitly retains the existing web root.

Tests: 2 files changed, 669 lines added. apps/web/src/lib/user/index.test.ts (modified, +239) and packages/db/src/agent-harness-schema.test.ts (added, +430) add account cleanup and ingress regression coverage.
Generated: 3 files changed, 40,479 lines added. packages/db/src/migrations/0234_agent_harness_ingress.sql (migration, added, +79), packages/db/src/migrations/meta/0234_snapshot.json (snapshot, added, +40,393), and packages/db/src/migrations/meta/_journal.json (journal, modified, +7).


Verification

No manual tests ran for this level. This level does not activate the runtime, and no isolated PostgreSQL test connection is approved.

Visual Changes

Visual Changes: N/A

Reviewer Notes

Human steps

  • before merge — Confirm PostgreSQL tests, account cleanup tests, and migration application pass in continuous integration (CI).
  • before merge — After the section passes its completion gate, merge the stack from the lowest level upward.
  • before merge — Apply generated migration 0234 before deploying the changed account cleanup or activating the later runtime.

This level requires no new environment values, secrets, or flag changes.

Scope and evidence

  • Repository: Kilo-Org/cloud.
  • Worktree: /Users/igor/Projects/.worktrees/shared-agent-harness-3bb0.
  • Range: shared-agent-harness-3bb0-s5...shared-agent-harness-3bb0-s6 (level 6 only).
  • The handoff reports five passing scoped checks and three passing pure artifact tests.

Notes

No manual runtime verification ran for this level. Full backend, browser, iOS, and Android verification remains required on the completed stack tip.

Real PostgreSQL tests, account cleanup tests, and migration application remain required in CI; local artifact tests do not prove database behavior.

Stacked PRs — merge bottom to top. Each level shows only its own diff.

Runtime verification (E2E, user advocacy, simplify) runs on the tip PR over every level.
Every level keeps its own checks, its own bot review, and its own threads; each one is answered on its own PR.
Each level is its own deliverable: it builds and passes its own checks alone.
A finding on a level is repaired on that level, then carried upward with stack.sh forward.

  1. shared-agent-harness-3bb0chore(agent-harness): register workspaces and enforce CI boundaries #5632
  2. shared-agent-harness-3bb0-s2feat(agent-harness): define portable domain and snapshots #5637
  3. shared-agent-harness-3bb0-s3feat(agent-harness): define commands tools and permission policy #5639
  4. shared-agent-harness-3bb0-s4feat(agent-harness): share client state and cursor recovery #5643
  5. shared-agent-harness-3bb0-s5feat(agent-harness): persist command intents and execution receipts #5647
  6. shared-agent-harness-3bb0-s6feat(db): add harness ingress grants and retirement fences #5655 ← this PR
  7. shared-agent-harness-3bb0-s7feat(agent-harness): deliver legacy history and project durable text #5659
  8. shared-agent-harness-3bb0-s8feat(agent-harness): authorize durable grants and registered clients #5662
  9. shared-agent-harness-3bb0-s9feat(agent-harness): fence retirement and retry payload cleanup #5667
  10. shared-agent-harness-3bb0-s10feat(agent-harness): persist authoritative state in SQLite #5675
  11. shared-agent-harness-3bb0-s11feat(agent-harness): admit durable runs and revisioned commands #5678
  12. shared-agent-harness-3bb0-s12feat(agent-harness): recover queued runs and stream checkpointed steps #5688
  13. shared-agent-harness-3bb0-s13feat(agent-harness): resolve interactions and dispatch tools sequentially #5693 (tip)

Comment thread packages/db/src/schema.ts
},
table => [
index('IDX_quick_chat_messages_thread_created_at').on(table.thread_id, table.created_at),
uniqueIndex('quick_chat_messages_server_projection_uidx').on(table.server_projection_key),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Unique index on nullable server_projection_key is not partial

quick_chat_messages_server_projection_uidx indexes every row, including the NULL keys required for legacy messages. After this additive migration every existing row is legacy with a NULL key, so the unique index is a full-table btree that enforces nothing until harness projections exist. Follow the existing nullable unique-index pattern (for example UQ_kilocode_users_openrouter_upstream_safety_identifier) and restrict it to non-null keys. Declare .concurrently() on the schema index, regenerate, then wrap the generated CREATE UNIQUE INDEX CONCURRENTLY with the COMMIT; / BEGIN; statement-breakpoint pair from packages/db/AGENTS.md.

Suggested change
uniqueIndex('quick_chat_messages_server_projection_uidx').on(table.server_projection_key),
uniqueIndex('quick_chat_messages_server_projection_uidx').on(table.server_projection_key).where(sql`${table.server_projection_key} IS NOT NULL`).concurrently(),

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread packages/db/src/schema.ts
// A lease never acknowledges import. No timestamp watermark can exclude a late commit.
index('IDX_quick_chat_messages_pending_ingress')
.on(table.thread_id, table.created_at, table.id)
.where(sql`${table.provenance} = 'legacy' AND ${table.ingress_acknowledged_at} IS NULL`),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Indexes on existing quick_chat_messages are not concurrent

IDX_quick_chat_messages_pending_ingress and IDX_quick_chat_messages_ingress_lease are built on an already-created table. Their predicates match every current row (provenance = 'legacy' AND ingress_acknowledged_at IS NULL), so a non-concurrent CREATE INDEX takes a write lock for the full build. Add .concurrently() here and on the lease index .where(...) below, regenerate, then insert the COMMIT; / BEGIN; wrappers required by packages/db/AGENTS.md.

Suggested change
.where(sql`${table.provenance} = 'legacy' AND ${table.ingress_acknowledged_at} IS NULL`),
.where(sql`${table.provenance} = 'legacy' AND ${table.ingress_acknowledged_at} IS NULL`).concurrently(),

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/db/src/schema.ts 11125 Unique index on nullable server_projection_key is not partial
packages/db/src/schema.ts 11129 Indexes on existing quick_chat_messages are not concurrent
Files Reviewed (6 files)
  • apps/web/jest.config.ts - 0 issues
  • apps/web/src/lib/user/index.test.ts - 0 issues
  • apps/web/src/lib/user/index.ts - 0 issues
  • packages/db/src/agent-harness-schema.test.ts - 0 issues
  • packages/db/src/migrations/0234_agent_harness_ingress.sql - 0 issues
  • packages/db/src/schema.ts - 2 issues

Fix these issues in Kilo Cloud


Reviewed by grok-4.6 · Input: 295.4K · Output: 27.5K · Cached: 1.1M

Review guidance: REVIEW.md from base branch shared-agent-harness-3bb0-s5

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