Skip to content

fix(dwn-sdk-js): carry mutable visibility facts onto tombstone indexes#1012

Merged
LiranCohen merged 6 commits into
mainfrom
fix/tombstone-visibility-indexes
Jun 12, 2026
Merged

fix(dwn-sdk-js): carry mutable visibility facts onto tombstone indexes#1012
LiranCohen merged 6 commits into
mainfrom
fix/tombstone-visibility-indexes

Conversation

@LiranCohen

Copy link
Copy Markdown
Contributor

Summary

Implements the tombstone visibility facts stream of the sync replication-log plan (SDK phase item 8).

RecordsDelete.constructIndexes copied only immutable initial-write facts onto tombstone indexes, dropping the mutable query-visibility facts. As a result, tombstones of tagged permission records never matched the permission shadow filters ({ protocol: permissionsURI, tag.protocol: P }) and published-record tombstones never matched published: true queries and subscriptions.

  • constructIndexes(initialWrite, newestPreDeleteMessage): immutable descriptor/domain facts (protocol, protocolPath, recipient, contextId, schema, dateCreated, …) keep coming from the initial write; mutable facts — flattened tag.* (same Records.buildTagIndexes flattening the write path uses) and published — come from the newest message that existed immediately before the delete.
  • When the pre-delete newest message is an existing RecordsDelete (prune-of-deleted, or a tombstone displaced under the delete-wins lattice), the existing tombstone's visibility facts carry forward: a tombstone's descriptor carries neither tags nor published, so they are reconstructed from the newest retained RecordsWrite — the initial write — which is the same source the existing tombstone derived its own facts from.
  • Call sites: StorageController.performRecordsDelete passes the newestExistingMessage it already derives for its tombstone-lattice gate (covers both the handler path and resumable-task replay); the replication duplicate-repair path in dwn.ts derives the pre-delete newest message by excluding the already-stored delete itself, falling back to the initial write.

Changeset: patch on @enbox/dwn-sdk-js.

Test plan

  • A tagged permission record's tombstone matches the permission shadow-filter shape { protocol: permissionsURI, 'tag.protocol': P } and is the only match after deletion (handler spec)
  • A published record's tombstone matches published: true message-store filters and is delivered to a published: true RecordsSubscribe; an unpublished record's tombstone matches neither (handler spec)
  • Mutable facts come from the latest pre-delete update (tags changed red→blue, published flipped) while immutable facts (schema, dateCreated) still come from the initial write (handler + unit specs)
  • Prune of an already-deleted record carries the existing tombstone's visibility facts forward; the prune is the only matching tombstone (handler + unit specs)
  • A tombstone applying over a newer write (delete-wins) carries that displaced write's tags/published (handler spec)
  • bun run lint clean (15/15 packages)
  • bun run --filter @enbox/dwn-sdk-js build and bun run --filter @enbox/agent build pass
  • bun run test:node in packages/dwn-sdk-js: 1466 pass, 0 fail (113 files)

🤖 Generated with Claude Code

LiranCohen and others added 2 commits June 11, 2026 23:57
RecordsDelete.constructIndexes copied only immutable initial-write facts,
so tombstones of tagged permission records never matched the permission
shadow filters ({ protocol: permissionsURI, tag.protocol: P }) and
published-record tombstones never matched published: true subscriptions.

Tombstone indexes now take mutable query-visibility facts — flattened
tag.* (same flattening as the write path) and published — from the newest
message that existed immediately before the delete, while immutable
descriptor/domain facts keep coming from the initial write. When the
pre-delete newest message is an existing tombstone (prune-of-deleted, or
a tombstone displaced under the delete-wins lattice), its visibility
facts carry forward via the initial write it derived them from. The
replication duplicate-repair path in dwn.ts derives the same pre-delete
newest message by excluding the already-stored delete itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Node (bun test)

Package Line Coverage Status
agent 74.9% ⚠️ Below 96% target
api 75.3% ⚠️ Below 96% target
auth 25.9% ⚠️ Below 96% target
browser 100.0%
common 94.3% ⚠️ Below 96% target
crypto 99.7%
dids 98.9%
dwn-clients 26.3% ⚠️ Below 96% target
dwn-sdk-js 98.1%
dwn-server 59.9% ⚠️ Below 96% target
dwn-sql-store 91.2% ⚠️ Below 96% target

⚠️ Some packages are below the 96% coverage target. The report is informational and does not fail CI.

Coverage Report

Node coverage not available for this run.

Browser Coverage (informational)
Package Chromium Firefox WebKit
agent 81.9% 81.9% 81.9%
api 100.0% 100.0% 100.0%
browser 53.8% 53.8% 53.8%
common 94.0% 94.0% 94.0%
crypto 99.4% 99.4% 99.4%
dids 97.4% 97.4% 97.4%
dwn-sdk-js 93.0% 93.0% 93.0%

Browser coverage is informational only (subset of tests).

@LiranCohen

Copy link
Copy Markdown
Contributor Author

Rerunning the failed browser job: the Firefox dids/agent/api job failed before tests while downloading the workspace-build artifact with GitHub artifact API 403 (Failed to ListArtifacts). Chromium/WebKit variants and the rest of the matrix passed, so this is environmental rather than code-related.

@sonarqubecloud

Copy link
Copy Markdown

@LiranCohen LiranCohen merged commit a2bfa0d into main Jun 12, 2026
29 checks passed
@LiranCohen LiranCohen deleted the fix/tombstone-visibility-indexes branch June 12, 2026 16:59
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