Skip to content

Phase 5: tags, documents, search, and aliases - #196

Merged
dezren39 merged 32 commits into
mainfrom
phase-5
Oct 12, 2026
Merged

dezren39 merged 32 commits into
mainfrom
phase-5

Conversation

@dezren39

Copy link
Copy Markdown
Member

Phase 5 of the id design.

  • P5.1 observed-remove tags, with the tag inside the signed header; P5.2 tag index on tuple keys; P5.3 compaction of claims and clears (closes Phase 5: compaction for tag clears #184); Phase 5: tag event bodies must travel with the event #182 tag body in the event.
  • P5.4 documents as signed events with content hashes; P5.5 search over live claims; P5.6 removal by the document's author, content kept (decision 4); P5.7 aliases as tag claims with contested display and prefixes.
  • Tag value limit stays at 512 bytes (decided by the header decoder; owner to confirm).
  • Store format v8 (no migration). The property failures found on the phase-5 tip were a bug in the test generator (fixed in 0f3b7ea), not in the fold.

Full run on the merged tree: 1479 passed, 9 ignored, 1 failed. The failure is serve_tests::test_world_module_shared_over_iroh_and_web_presentations (#190), which also fails on the phase-3 tip.

Open, in issues: #185 who may clear a claim, #160 user subject, #183 persisted tag index, #195 what removal does to new content (keep vs hide). Not run here: just crash-gate, nix checks.

Tags are claims: tag.set names a subject (any event ID), a name and an
optional value, and tag.clear names the claims it removes. Both are signed
events with the kind in the header and the body committed by hash.

A clear removes a named claim only when the claim is in the clear's causal
past: the transitive closure of its after hashes and backlink. Concurrent
adds survive, and a clear of an unseen claim does nothing to it (S8).

The store keeps each tag body in a tag_ops table, written when the event is
kept, and reads applied tag events back for the fold. Format is now v7.
Each live claim is indexed as (subject, name, value, claim) and as
(value, name, subject, claim) in tuple order, so prefix scans answer the
tags of a subject, its tags by name and value, and the subjects with a
value, in both directions. A bare tag's value is tuple null.

Every text and byte field is terminated, so the name a does not match
a NUL b. A property over random tags checks each scan against a filter.
The tag operation moves from a body beside the event into the signed header, as the ChainExt tag field. Sync moves events, so a receiver that has the event has the tag. A tag event takes no payload body, and its tag must fit its kind.

The tag_ops table and its write path are removed. The store format is v8, because a v7 store holds tag events whose operation is not in the header. A tag value is at most 512 bytes, the most the header decoder declares for text.
A clear used to walk its causal past on its own, so the fold cost was clears times history. compacted_claims makes one pass over the parent links. Each event gets the set of live claims in its past, built from its parents' sets. A clear removes the claims it names that are in its parents' sets, and removed claims are dropped from every later set. The result matches live_claims, which stays as the reference.

The property checks the two folds agree for histories of two or three writers, at 16 cases. A clear from an author who had not seen a claim leaves it live. The store's tag_claims uses the compacted fold.

This is an in-memory fold, not a persisted snapshot at a causal cut (N33). Snapshots are open.
Appends the progress record for the body-in-event change (#182) and compaction (P5.3, #184): the commits, the red-then-green evidence, the decisions, and the open items.
Keeps the two property failures as regressions. The regression file holds the persisted case, which replays under both properties. Two named tests use the exact (seed, steps, writers) of each failure: every event's causal past is the set its author had seen, and the store, the causal walk and the compacted fold all reach the oracle. Both fail until the generator fix.
…1, P5.3]

The generator shadowed the writer count with the clear's claim count, so a clear's after named only the first 1 to 3 writers. The writer then had seen events its clear did not name, and the oracle counted them as seen while the causal past did not. The fold and the causal walk agreed on every history. The fix keeps the writer count in the frontier.
Records the root cause of the two tag property failures: the test history generator shadowed the writer count, so a clear's frontier named too few writers. The fold and the causal walk were not at fault.
Red: tests/aliases.rs states the four decided rules over the store's tag claims. src/aliases.rs holds the final API with stub bodies (no aliases, no rows), so each test fails on its assertion. Stubs are replaced in the next commit.
…s [P5.7]

src/aliases.rs reads an alias as a tag.set named alias, on the object's ID. A view shows a pet name first, then the stored server primary (looked up by a group's ID), then one alias alone, or every alias as contested. Each row carries the shortest unique prefix of its ID, at least 7 hex digits, and the full ID when no prefix is unique. Nothing is unique. The creation date is not shown: the signed header has no time field (open).
Records P5.7: aliases as tag claims, the display rules, and what is left open (#185, #160, and the alias creation date).
@dezren39
dezren39 requested a review from a team as a code owner October 12, 2026 20:51
@dezren39
dezren39 merged commit bae1451 into main Oct 12, 2026
2 of 4 checks passed
@dezren39
dezren39 deleted the phase-5 branch October 12, 2026 20:51
@coderabbitai

coderabbitai Bot commented Oct 12, 2026

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3da640b6-17dc-493f-817d-6a4bd59e0e98

📥 Commits

Reviewing files that changed from the base of the PR and between 479cc76 and ab663c0.


📒 Files selected for processing (28)
  • doc/2026-10-12T14-33-36Z_phase_5_tags_documents/2026-10-12T14-33-36Z_phase_5_tags_documents.md
  • pkgs/id/src/aliases.rs
  • pkgs/id/src/chain.rs
  • pkgs/id/src/documents.rs
  • pkgs/id/src/event_store/claims.rs
  • pkgs/id/src/event_store/documents.rs
  • pkgs/id/src/event_store/ingest.rs
  • pkgs/id/src/event_store/mod.rs
  • pkgs/id/src/event_store/sync.rs
  • pkgs/id/src/lib.rs
  • pkgs/id/src/log_sync.rs
  • pkgs/id/src/search.rs
  • pkgs/id/src/store_traits.rs
  • pkgs/id/src/tag_claims.rs
  • pkgs/id/src/tag_index.rs
  • pkgs/id/tests/aliases.rs
  • pkgs/id/tests/chain_properties.rs
  • pkgs/id/tests/content_removal.rs
  • pkgs/id/tests/crash/store.rs
  • pkgs/id/tests/documents.rs
  • pkgs/id/tests/event_store_properties.rs
  • pkgs/id/tests/production_ingest.rs
  • pkgs/id/tests/search.rs
  • pkgs/id/tests/tag_claims.proptest-regressions
  • pkgs/id/tests/tag_claims.rs
  • pkgs/id/tests/tag_index.rs
  • pkgs/id/tests/voiding_properties.rs
  • pkgs/id/tests/voiding_scenarios.rs

 _______________________________
< I turn WTF moments into TILs. >
 -------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR

🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

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.

Phase 5: compaction for tag clears

1 participant