Skip to content

[recipes] Authorship edges — speaker attribution + self author edges - #51

Open
alanshurafa wants to merge 1 commit into
mainfrom
contrib/alanshurafa/authorship-edges
Open

[recipes] Authorship edges — speaker attribution + self author edges#51
alanshurafa wants to merge 1 commit into
mainfrom
contrib/alanshurafa/authorship-edges

Conversation

@alanshurafa

Copy link
Copy Markdown
Owner

What this adds

A recipes/authorship-edges/ recipe that brings authorship to spoken and machine-generated capture.

The atomizer's correspondent resolver keys people off RFC-2822 email addresses. Spoken capture has no addresses: a wearable transcript chunk is labelled You / Alex / Speaker 1, and a device-generated title or action item has no human speaker at all. Nothing in OB1 turns those into an authorship edge, and nothing marks a row as machine-generated. This recipe is the display-name counterpart.

  • Deterministic classifier (lib/speaker-attribution.mjs, no LLM) maps a thought's speaker labels to self / other / mixed / machine / unknown.
  • Self author edges (lib/author-edges.mjs) link every self/mixed thought to a configured self-entity via thought_entities(mention_role = 'author' | 'participant').
  • Backfill (backfill-authorship.mjs) adds edges to thoughts you've already captured — idempotent, keyset-paginated, with one batched edge lookup per page.
  • Query layer (queries.sql) — "everything I said" vs. "machine-generated only", or down-rank machine rows in search.

Why it's safe to merge

  • Additive only. It reads/writes the existing entities and thought_entities tables from the entity-extraction schema. It creates no tables, changes no columns, and does not depend on a canonical_email column.
  • No hardcoded identity. The self-entity comes from OB_SELF_ENTITY_ID or a display name the recipe upserts once (and marks is_self). If a same-named non-self entity already exists, it refuses rather than mis-attributing your speech.
  • Id-type agnostic. thought_id is passed through opaque, so it works whether your thoughts.id is UUID or BIGINT (no numeric coercion of ids).
  • No secrets, Node 18+ with zero dependencies, and a node test-attribution.mjs self-test (21 assertions) covering the full classifier matrix.

Scope

Named-other speakers are classified but not resolved to entity rows — display-name → entity resolution is deliberately left as an extension point, the same way the email resolver defers multi-address identity. This recipe links the unambiguous self side and ships the substrate for the rest.

🤖 Generated with Claude Code

OB1's correspondent resolver keys people off email addresses, so spoken
and machine-generated capture has no path to authorship: a transcript
labelled "You"/"Alex"/"Speaker 1" never becomes an edge, and nothing
marks a device-generated summary as machine-made. This recipe is the
display-name counterpart — a deterministic self/other/mixed/machine/
unknown classifier that links the thoughts you spoke to a configured
self-entity via thought_entities author edges, plus the "what I said vs.
what a machine generated" query layer. No LLM, no hardcoded ids, additive
on the existing entities/thought_entities tables, and thought_id is
treated opaque so it works on UUID or BIGINT brains.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant