Skip to content

feat(slack): personal lanes — picks by DM, ranked against one researcher's vault (#121) - #123

Merged
jacktrnr merged 1 commit into
mainfrom
feat/121-personal-lanes
Nov 6, 2026
Merged

jacktrnr merged 1 commit into
mainfrom
feat/121-personal-lanes

Conversation

@jacktrnr

@jacktrnr jacktrnr commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Closes #121.

What this does

A personal lane sends one researcher picks ranked against their own vault, as Slack DMs, alongside the shared channel digest.

[lanes.jackson]
recipient = "U0BC5EPT4HK"         # Slack member id — the DM target and the lane's only keeper
roots = ["~/vaults/jacktrnr"]     # never inherited from [vault]
feeds = ["math.AP", "quant-ph"]   # never inherited, never defaulted
top = 5                           # optional
papers_dir = "…"                  # optional; where the lane's keeps land
  • arjev digest --lane <name> --post slack: opens the recipient's DM (conversations.open) before ranking, then posts a header ("arJev picks for you") plus one message per pick. The content boundary is the same as the channel's.
  • arjev slack sync --lane <name>: harvests reactions and replies from the lane's DM. Only the recipient's reactions count, and keeps scaffold into the lane's own papers dir.
  • State isolation: a lane_scope context variable routes state_dir() and ledger_path() to <state>/arjev/lanes/<name>/. Journal, posted ids, receipts and the ledger are all per-lane, and the persisted schemas are unchanged (invariant 8).
  • arjev inspect prints one lane <name> <key>: <value> block per lane (recipient, roots, feeds, top, identity-bearing, directives). It blocks with blocked: lane <name>: no {recipient|roots|feeds} configured, or when the lane has zero identity-bearing notes.
  • arjev daily runs every lane after the shared day: the digest is retried like the shared one, then the lane sync. A failing lane never stops the others. Lanes are skipped (and logged) when no Slack token is available.
  • keep and staged also take --lane.
  • The manifest and docs gain im:write and im:history. Existing app: add the two scopes and reinstall to the workspace (the token stays the same).

Acceptance criteria (#121)

  • No-lane config is unchanged (ranking-parity test: fingerprint and scores identical).
  • Lane picks arrive by DM, one message per pick, each with who-line and why-line.
  • DM reactions label only that lane, and only from its recipient. Shared-channel reactions never label a lane (cross_lane_labels == 0, tested both directions).
  • A lane ranks only its own roots (it never inherits [vault].roots).
  • Per-lane posted-id and journal state (a paper the shared channel posted can still be picked in a lane).
  • inspect reports each lane and blocks an empty-feeds lane, naming it.
  • Manifest and setup docs carry the DM scopes, each mapped to its surface.

Tests

tests/test_lanes.py (21 tests, recorded Slack transport, no network). Full suite and ruff check . are green, with one exception: test_init_template::test_no_lab_name_anywhere_in_the_template fails locally only because my clone lives under ~/harmoniqs/, so the fixture-vault path written into the template contains "harmoniqs". It passes from a neutral path, and CI is unaffected.

Not in this PR

…her's vault (#121)

A [lanes.<name>] table names a recipient, their roots and their feeds.
digest --lane posts the picks to the recipient's DM (conversations.open);
slack sync --lane harvests only the recipient's DM reactions. Each lane's
journal, posted ids and label ledger live under <state>/lanes/<name>/, so
labels never cross lanes. A lane inherits no roots or feeds; inspect reports
each lane and blocks one missing a recipient, roots or feeds; daily runs
every lane after the shared day. Manifest gains im:write + im:history.
@jacktrnr
jacktrnr merged commit 954164d into main Nov 6, 2026
1 check passed
@jacktrnr
jacktrnr deleted the feat/121-personal-lanes branch November 6, 2026 02:18
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.

feat(slack): personal lanes — a daily DM of picks ranked against one researcher's vault

2 participants