Conversation
Format migration list in CLAUDE.md for readability Remove references to deleted design documentation files Document --limit flag for embeddings backfill command
Add regression coverage for the federation event-signing feature: - migration017_test.go: assert the signature/pubkey columns exist as NOT NULL DEFAULT '' and that a row inserted without them backfills to the empty (unsigned) sentinel rather than NULL, the property a mixed-version ring relies on to treat pre-signing events as unsigned. - signing_interop_test.go: exercise the full cross-cortex wire path the in-process unit tests skip — emit on cortex A, JSON-serialize exactly as sync_events transmits, deserialize, and ReplayEvent on cortex B. Covers signed round-trip under enforce (with TOFU pin), in-transit tamper rejection, the mixed-version unsigned-upstream matrix (enforce rejects / off accepts), and no-silent-downgrade-after-pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign every emitted event with a per-cortex Ed25519 key and verify replayed events against the originating cortex's pinned key, moving the federation trust anchor from the shared transport key to the cortex that authored each event. Once cortex_id is authenticated, source-locking is enforced on the replay path: a source-locked trace may only be mutated by its owning cortex. - eventsig: canonical, length-prefixed, domain-separated preimage with sign/verify and ed25519:<base64> key+signature encoding. - noema keygen generates/rotates the key into a 0600 sidecar and records the public key in cortex.md; the cortex_identity handshake advertises it. - Key distribution is trust-on-first-use keyed on cortex_id, with conflict detection and downgrade resistance. A high-assurance peer's key can be hard-pinned via pubkey: on its cortex.md entry, which overrides TOFU and refuses a mismatching handshake regardless of verify mode. - Verification is staged via federation.verify (off default | warn | enforce) so a mixed-version ring never hard-partitions; migration 017 adds the additive, NOT NULL DEFAULT '' signature/pubkey columns. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the root CLAUDE.md with AGENTS.md and move reference material into docs/architecture.md and docs/development.md, linked from the README. Update the Makefile and a migration comment that pointed at CLAUDE.md, and ignore the generated docs/layout.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make explicit in the federation signing section that off (default) checks nothing and warn logs but still applies forged events, so the forgery and source-lock-bypass risks stay open until peers are moved to enforce. off/warn are a rollout on-ramp, not protection. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the O_TRUNC-then-write with a temp-file + fsync + rename so a crash or error mid-write can never truncate or partially overwrite an existing key. A key clobbered halfway through a `keygen --force` rotation would otherwise force every peer to re-pin. The temp file sits beside the target to keep the rename on one filesystem, and the 0600 mode is forced explicitly so it holds even over a looser-permission original. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the seed file to a .gitignore at the cortex root so it can't be accidentally committed if the cortex directory is (or becomes) a git repo. Idempotent, creates .gitignore if absent, and skips a key stored outside the cortex directory (which a .gitignore there couldn't cover). A gitignore failure warns but does not fail keygen — the key is valid either way. Also refresh the now-stale O_TRUNC comment on the write path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
detectCopiedDirectory keyed on "any foreign cortex_id with none of our own" — which is the normal state of a receiver/subscribe cortex after its first federation sync, since peer events are replayed under the originating cortex's id. The guard runs on every Open, so it made such a cortex unopenable: serve restart and every CLI command (including the reset-peer recovery the signing feature points operators to) failed with "appears to be a copy", and the suggested escape hatch (migrate cortex-id --reset) didn't even help — it only re-keys rows this cortex authored. Scope the check to locally-authored history: trip only when events with origin == this cortex's name are recorded under a cortex_id other than the one cortex.md declares — the actual copy/re-id signature, and exactly the rows --reset re-keys. Peer-replayed events no longer count. Pre-existing since the cortex-ULID work; surfaced by end-to-end federation testing of the signing feature. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A key rotation (noema keygen --force) retires the old key, but a peer's pre-rotation events stay signed with it. A full reset-peer resets the cursor to the start, so the peer re-pulls those old-key events and, under verify=enforce, rejects them (their embedded pubkey conflicts with the newly re-pinned key) — the cursor sticks and recovery stalls. Add reset-peer --key-rotated: clear only the pinned signing key, keeping the cursor, pinned identity, and vclock. An already-caught-up peer then re-pins the new key on its next handshake and pulls only post-rotation events, never re-touching the retired-key history. Document the residual limitation: a from-scratch resync of a rotated cortex (a brand-new peer, or a full reset) still can't replay its pre-rotation events under enforce — there is no key history. Rotate only when forfeiting that to zero-state peers is acceptable. Surfaced by end-to-end federation testing of the signing feature. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Authenticate federated events with per-cortex Ed25519 signatures so a shared-key ring no longer has to trust any key-holder to author events as any cortex.
noema keygengives a cortex an Ed25519 key; it signs every event it emits and advertises the public key via thecortex_identityhandshake.federation.verify=off(default) |warn|enforce. Underenforce, replay rejects events not correctly signed by their owning cortex, and source-locking is enforced on the replay path.cortex_id, with conflict detection and downgrade resistance; optional out-of-band hard-pin (pubkey:on a peer entry); rotation recovery viareset-peer --key-rotated.signature/pubkeycolumns so mixed-version rings degrade gracefully.AGENTS.md+docs/; Obsidian plugin bump.Verify defaults to
off, so upgrading changes nothing until an operator opts in.