Make propose_lore_relationships campaign-scoped — entries without a linked session get no relationship suggestions #289

Closed
opened 2026-08-05 22:11:46 +00:00 by claude-bot · 1 comment
Contributor

Follow-up to #286, which moved relationship-proposal scheduling from lore-pipeline completion (where the task structurally could not see the new entries) to proposal approval.

The remaining gap

propose_lore_relationships takes a session_id, but it only uses it to resolve the campaign — it loads the session purely to read session.campaign_id, then queries every approved entry in that campaign (reminder_tasks.py:3889-3945). The work itself is campaign-scoped; the session parameter is vestigial.

Scheduling from approval means passing the approved entry's linked_session_id. When that is NULL, nothing is scheduled — lore_service.schedule_relationship_proposals returns early. That is correct given the current signature, and it is tested, but it means:

  • manually-created wiki entries never trigger relationship suggestions — a GM writing up an NPC by hand gets nothing
  • shelf-promotion stubs and any other entry created outside a session context are likewise skipped
  • the entry that does trigger a pass contributes only its session id; the pass itself ignores the session entirely

Fix direction

Change the task to take a campaign_id. That removes the vestigial lookup, makes the trigger work for every approved entry regardless of provenance, and simplifies the debounce key in lore_service._RELATIONSHIP_DEBOUNCE_SECONDS scheduling from per-session to per-campaign — which is arguably more correct anyway, since two sessions in the same campaign approving entries concurrently currently schedule two passes over the same entry set.

Points to touch:

  • propose_lore_relationships / _propose_lore_relationships_async signature and the session lookup
  • lore_service.schedule_relationship_proposals — pass entry.campaign_id, drop the NULL guard
  • the debounce key (lore_rel_pending:{session_id} → campaign)
  • create_bot_relationship_proposals if it records a session linkage worth preserving — check before assuming it does not

Worth confirming whether relationship proposals should carry a "discovered in session X" attribution. If so the session id is still wanted as optional context rather than as the lookup key, and the signature should take both.

Acceptance

  • An approved entry with no linked_session_id still schedules a relationship pass
  • Debounce is per campaign, so concurrent approvals across sessions coalesce
  • Existing tests in test_relationship_proposal_trigger.py updated — the "entry without a linked session is skipped" test inverts to "is still scheduled"

Labels: backend

Follow-up to #286, which moved relationship-proposal scheduling from lore-pipeline completion (where the task structurally could not see the new entries) to proposal approval. ## The remaining gap `propose_lore_relationships` takes a `session_id`, but it only uses it to resolve the campaign — it loads the session purely to read `session.campaign_id`, then queries every approved entry in that campaign (`reminder_tasks.py:3889-3945`). The work itself is campaign-scoped; the session parameter is vestigial. Scheduling from approval means passing the approved entry's `linked_session_id`. When that is NULL, nothing is scheduled — `lore_service.schedule_relationship_proposals` returns early. That is correct given the current signature, and it is tested, but it means: - **manually-created wiki entries never trigger relationship suggestions** — a GM writing up an NPC by hand gets nothing - shelf-promotion stubs and any other entry created outside a session context are likewise skipped - the entry that *does* trigger a pass contributes only its session id; the pass itself ignores the session entirely ## Fix direction Change the task to take a `campaign_id`. That removes the vestigial lookup, makes the trigger work for every approved entry regardless of provenance, and simplifies the debounce key in `lore_service._RELATIONSHIP_DEBOUNCE_SECONDS` scheduling from per-session to per-campaign — which is arguably more correct anyway, since two sessions in the same campaign approving entries concurrently currently schedule two passes over the same entry set. Points to touch: - `propose_lore_relationships` / `_propose_lore_relationships_async` signature and the session lookup - `lore_service.schedule_relationship_proposals` — pass `entry.campaign_id`, drop the NULL guard - the debounce key (`lore_rel_pending:{session_id}` → campaign) - `create_bot_relationship_proposals` if it records a session linkage worth preserving — check before assuming it does not Worth confirming whether relationship proposals should carry a "discovered in session X" attribution. If so the session id is still wanted as *optional context* rather than as the lookup key, and the signature should take both. ## Acceptance - [ ] An approved entry with no `linked_session_id` still schedules a relationship pass - [ ] Debounce is per campaign, so concurrent approvals across sessions coalesce - [ ] Existing tests in `test_relationship_proposal_trigger.py` updated — the "entry without a linked session is skipped" test inverts to "is still scheduled" Labels: backend
Author
Contributor

Verified against the acceptance criteria before closing. All met.

  • Approved entry with no linked_session_id still schedules a pass — task signature is now propose_lore_relationships(campaign_id) (reminder_tasks.py:4087), no session lookup remains, NULL guard gone. Tested by test_entry_without_a_linked_session_is_still_scheduled (tests/test_relationship_proposal_trigger.py:201) — literally the inverted case this issue asked for.
  • Debounce is per-campaign — key is lore_rel_pending:{campaign_id} (lore_service.py:489). Tested by test_approvals_in_different_campaigns_are_scheduled_separately.
  • Tests updated — the file header documents the change.

The issue's open question about create_bot_relationship_proposals still taking a session_id was answered rather than ignored: it is explicitly passed None with a comment noting LoreRelationship has no such column and the parameter is otherwise dead (reminder_tasks.py:4240-4249).

Closing. Part of a full acceptance-criteria pass across the v4.0.0 milestone.

Verified against the acceptance criteria before closing. All met. - **Approved entry with no `linked_session_id` still schedules a pass** — task signature is now `propose_lore_relationships(campaign_id)` (`reminder_tasks.py:4087`), no session lookup remains, NULL guard gone. Tested by `test_entry_without_a_linked_session_is_still_scheduled` (`tests/test_relationship_proposal_trigger.py:201`) — literally the inverted case this issue asked for. - **Debounce is per-campaign** — key is `lore_rel_pending:{campaign_id}` (`lore_service.py:489`). Tested by `test_approvals_in_different_campaigns_are_scheduled_separately`. - **Tests updated** — the file header documents the change. The issue's open question about `create_bot_relationship_proposals` still taking a `session_id` was answered rather than ignored: it is explicitly passed `None` with a comment noting `LoreRelationship` has no such column and the parameter is otherwise dead (`reminder_tasks.py:4240-4249`). Closing. Part of a full acceptance-criteria pass across the v4.0.0 milestone.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#289
No description provided.