Skip to content

Add candidate blurb library and drafting workflows#391

Open
michaelmwu wants to merge 2 commits into
mainfrom
michaelmwu/ai-gig-blurbs
Open

Add candidate blurb library and drafting workflows#391
michaelmwu wants to merge 2 commits into
mainfrom
michaelmwu/ai-gig-blurbs

Conversation

@michaelmwu

@michaelmwu michaelmwu commented Jul 15, 2026

Copy link
Copy Markdown
Member

Summary

Adds a durable, versioned candidate-blurb library so candidate-written introductions can be reused generally or tailored to a gig without creating a false application record.

  • Adds immutable blurb versions with provenance, source metadata, general/gig scope, and a migration-backed persistence layer.
  • Adds Steering+ Discord workflows: /save-blurb, /draft-blurb, and Apps → Save blurb on candidate messages, including DMs.
  • Adds Steering-gated dashboard APIs and UI for capture, review, edit, history, copy, and gig captures without applications.
  • Adds a review-only AI drafting path grounded in synced profile facts, gig context, and candidate-authored samples; it never sends, posts, or persists without an explicit save.
  • Syncs CRM profile descriptions into structured profile-summary context and documents the workflow.

Why

Candidate blurbs often arrive informally and retain the candidate's own voice. Previously they had to be requested and recreated for every gig. This creates a reusable, auditable library while preserving the distinction between a general profile and candidate-authored pitch.

Validation

  • ./scripts/test.sh — 1,942 passed, 20 skipped
  • ./scripts/pyrefly.sh — 0 errors
  • bun run lint && bun run typecheck && bun run test (admin dashboard) — passed
  • uv run --package worker alembic -c pyproject.toml heads20260715_0100 (head)

Note

Medium Risk
Large new write surface for candidate-facing text with Steering-gated but multi-channel entry (dashboard, Discord, AI drafts); correctness of scoping and “no false application” behavior matters for recruiting workflows.

Overview
Introduces a versioned candidate blurb library separate from CRM profile descriptions: immutable lineages with provenance (candidate, candidate_attributed, team, ai), general vs gig scope, and status/history. Persistence lands via migration (candidate_blurbs, people.profile_summary) and shared five08.candidate_blurbs (save, list, batch enrich, review-only LLM draft grounded on synced facts and prior samples).

Dashboard (Steering/admin-gated): new APIs under people, gig applications, and unattached gig identities; gig detail enriches applications plus gig-level blurbs that never imply an application. People and Gigs get CandidateBlurbPanel (load, paste, AI draft, edit/replace version, copy, history). Session groups / is_admin drive UI gating aligned with API steering checks.

Discord: /save-blurb, /draft-blurb, and Save blurb message action—private modals/views, explicit confirm before persist, scope from registered gig thread or general; DM access resolves roles against the configured server.

Worker: CRM description syncs into profile_summary for draft context.

Reviewed by Cursor Bugbot for commit adac78a. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added end-to-end candidate blurb management in the admin dashboard, including draft/approved states, editing with version history, and copy-to-clipboard.
    • Added AI-generated blurb drafting with structured supporting/missing facts.
    • Added private Discord workflows (commands and message actions) to save or draft candidate blurbs with scoped targeting.
    • Added gig-specific vs general blurbs, including gig-scoped captures that avoid creating unintended application records.
    • Synced a new CRM “profile summary” field into person records.
  • Documentation

    • Added “Candidate Blurbs” documentation covering scopes, metadata, permissions, and user actions.
  • Tests

    • Added unit tests for dashboard endpoints, Discord blurb workflows, shared persistence/drafting contracts, and profile summary storage.

@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_009a78f2-3c42-40ad-a6ab-9e7f446a0a5f)

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Candidate blurbs now have versioned shared storage, bounded AI drafting, dashboard APIs and panels, Discord save/draft workflows, permission checks, gig enrichment, and CRM profile-summary synchronization.

Candidate blurb management

Layer / File(s) Summary
Shared blurb runtime and storage
packages/shared/src/five08/candidate_blurbs.py, apps/worker/src/five08/worker/migrations/versions/*, tests/unit/test_candidate_blurbs.py
Adds validated target resolution, immutable versioning, history listing, bounded drafting context, strict model-output validation, database constraints, indexes, and unit coverage.
Dashboard API contracts and handlers
apps/api/src/five08/backend/schemas.py, apps/api/src/five08/backend/routes.py, apps/api/src/five08/backend/api.py, tests/unit/test_backend_api.py
Adds request schemas, six dashboard routes, permission and CSRF validation, gig-detail enrichment, save/draft handlers, audit events, and API tests.
Dashboard blurb management UI
apps/admin_dashboard/src/main.tsx
Adds blurb types, permission gating, API callbacks, People and Gigs integration, application panels, unattached gig sections, history browsing, editing, copying, and AI drafting.
Discord blurb workflow
apps/discord_bot/src/five08/discord_bot/cogs/jobs.py, tests/unit/test_jobs.py
Adds private save and draft modals, scoped confirmation and editing views, requester authorization, gig-thread resolution, persistence helpers, slash commands, context-menu capture, and tests.
Profile synchronization and documentation
apps/worker/src/five08/worker/crm/people_sync.py, packages/shared/src/five08/audit.py, docs/discord-gig-dashboard.md, tests/unit/test_shared_audit.py, tests/unit/test_worker_people_sync.py
Stores CRM descriptions as person profile summaries and documents candidate blurb scopes, metadata, permissions, and supported workflows.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SteeringMember
  participant Dashboard
  participant BackendAPI
  participant SharedBlurbRuntime
  participant CandidateBlurbStore
  SteeringMember->>Dashboard: Open candidate or gig details
  Dashboard->>BackendAPI: Load candidate blurbs
  BackendAPI->>SharedBlurbRuntime: List or enrich blurbs
  SharedBlurbRuntime->>CandidateBlurbStore: Query current and historical versions
  CandidateBlurbStore-->>BackendAPI: Blurb records
  BackendAPI-->>Dashboard: Enriched gig or person data
  SteeringMember->>Dashboard: Draft or save blurb
  Dashboard->>BackendAPI: Submit draft or save request
  BackendAPI->>SharedBlurbRuntime: Draft or persist blurb
  SharedBlurbRuntime-->>BackendAPI: Draft or versioned record
  BackendAPI-->>Dashboard: Result and metadata
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a candidate blurb library plus drafting workflows.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch michaelmwu/ai-gig-blurbs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/admin_dashboard/src/main.tsx`:
- Around line 216-233: Update CandidateBlurb to include lineage_id, version, and
supersedes_id, then revise the current/history grouping and rendering logic to
partition blurbs by lineage_id. Treat each independent lineage’s current blurb
as current, and only classify superseded versions within that same lineage as
history; update the related logic around the alternate occurrence as well.
- Around line 6365-6373: Update the candidate blurb panel rendering around
candidate-selection state and the existing unattachedBlurbGroups flow so it also
renders an empty creation panel when a candidate is selected, even when no
unattached groups exist. Preserve listing and editing of existing groups, and
use the existing candidate/API callbacks to draft the first gig-specific blurb
without requiring an application.

In `@apps/api/src/five08/backend/api.py`:
- Around line 4264-4276: Update the application enrichment loop around
list_candidate_blurbs to eliminate sequential per-application database calls:
fetch all valid application and general blurb histories through a bounded batch
query, then group the results by application ID in memory and assign each
application’s blurbs. Preserve empty blurbs for invalid IDs and the existing
current_only=False/include_general=True behavior.
- Around line 4367-4377: Update the non-write listing branch around
list_candidate_blurbs to catch CandidateBlurbNotFoundError and validation
errors, mapping them to the same stable HTTP responses used by the POST path
instead of allowing them to escape as 500s. Preserve the existing successful
JSONResponse behavior and reuse the POST path’s established exception handling
and response construction.

In `@apps/discord_bot/src/five08/discord_bot/cogs/jobs.py`:
- Around line 517-518: Update the Save and Cancel callbacks to use the shared
_save_lock for their entire terminal transition, and add cancellation tracking
alongside _saved. Under the lock, prevent either callback from reopening or
persisting an already-cancelled/saved draft, mark the appropriate terminal state
atomically, and preserve the existing “not saved” behavior only when no terminal
transition has occurred.
- Around line 921-940: Update the early role authorization in the relevant
command authorization method before the configured-guild lookup so it cannot
approve roles from an arbitrary guild; only evaluate “Steering Committee” roles
after resolving and validating the configured Discord server and its member.
Preserve the existing member-fetch fallback and denial behavior, and add a
regression test proving an identically named role from another guild is
rejected.

In
`@apps/worker/src/five08/worker/migrations/versions/20260715_0100_create_candidate_blurbs.py`:
- Around line 156-185: Replace the partial current-only indexes in the
migration’s upgrade path with non-partial indexes on each target column plus
created_at, covering person_id, crm_contact_id, discord_user_id, engagement_id,
and application_id. Update the downgrade path to drop these corresponding
historical-lookup indexes, preserving consistent index names and migration
reversibility.
- Around line 133-142: Update the foreign key constraints in the candidate blurb
migration so deleting an engagement or application cannot cascade-delete blurb
history. Replace CASCADE behavior on both engagement_id and the composite
application_id/engagement_id constraint with RESTRICT or NO ACTION, preserving
blurb rows and their provenance.

In `@packages/shared/src/five08/candidate_blurbs.py`:
- Around line 857-858: Update the target-only branch in the blurb query, where
_candidate_match_sql(target, params) is appended, to also constrain results to
general blurbs by filtering scope appropriately. Preserve scoped matching for
branches that provide an explicit scope, while ensuring person-only requests
return only general-library records.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cdaeab03-8c3c-4410-a8eb-47793f32c782

📥 Commits

Reviewing files that changed from the base of the PR and between 43aea7f and e50a6c2.

📒 Files selected for processing (15)
  • apps/admin_dashboard/src/main.tsx
  • apps/api/src/five08/backend/api.py
  • apps/api/src/five08/backend/routes.py
  • apps/api/src/five08/backend/schemas.py
  • apps/discord_bot/src/five08/discord_bot/cogs/jobs.py
  • apps/worker/src/five08/worker/crm/people_sync.py
  • apps/worker/src/five08/worker/migrations/versions/20260715_0100_create_candidate_blurbs.py
  • docs/discord-gig-dashboard.md
  • packages/shared/src/five08/audit.py
  • packages/shared/src/five08/candidate_blurbs.py
  • tests/unit/test_backend_api.py
  • tests/unit/test_candidate_blurbs.py
  • tests/unit/test_jobs.py
  • tests/unit/test_shared_audit.py
  • tests/unit/test_worker_people_sync.py

Comment thread apps/admin_dashboard/src/main.tsx
Comment thread apps/admin_dashboard/src/main.tsx
Comment thread apps/api/src/five08/backend/api.py Outdated
Comment thread apps/api/src/five08/backend/api.py Outdated
Comment thread apps/discord_bot/src/five08/discord_bot/cogs/jobs.py
Comment thread apps/discord_bot/src/five08/discord_bot/cogs/jobs.py Outdated
Comment thread packages/shared/src/five08/candidate_blurbs.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e50a6c2144

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/api/src/five08/backend/api.py Outdated
Comment thread apps/api/src/five08/backend/api.py
Comment thread packages/shared/src/five08/candidate_blurbs.py Outdated
Comment thread apps/api/src/five08/backend/api.py Outdated
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_54c41a3f-9ad3-4e39-bd61-8b42a117950d)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: adac78a44b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +4283 to +4284
if application is None:
application = applications_by_person.get(str(blurb.get("person_id") or ""))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep unattached gig blurbs off application rows

When a gig-scoped blurb has application_id null but shares a CRM/Discord/person identity with an application (for example, it was captured from Discord before the candidate was added), these identity fallbacks attach it to application.blurbs instead of leaving it in candidate_blurbs. The application panel then edits via /applications/{application_id}/blurbs, but save_candidate_blurb rejects replacing the original because its stored application_id is still None, so the blurb is shown in a panel that cannot update it. Limit the identity fallback to general blurbs or keep unattached gig blurbs at the gig level.

Useful? React with 👍 / 👎.

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.

1 participant