---
id: CAP-CRM-ACT-013
title: Offer work to a security role and reserve it by claim
feature: FEAT-CRM-ACT-03
product_area: crm
module: activities-tasks
revision: 2
status: draft
product_intent: proposed
implementation_evidence: partially-observed
supersedes: []
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - >-
    Andrew 2026-10-18 (role claim), recorded at
    services-crm:docs/workstreams/crm-tasks-role-claim.md
purpose: Work can wait for an eligible role holder without creating another team queue.
outcomes:
  - Role-directed work
  - One successful role claimant
  - Offers restored by release
concepts:
  - CON-CRM-ACT-003
actors:
  - ACT-CRM-006
  - ACT-CRM-007
surfaces:
  - api
preconditions:
  - Platform can evaluate holdings of the candidate role in this workspace.
postconditions: []
permissions:
  - key: crm.tasks.read
    where_checked: api
    scope: tenant
  - key: crm.tasks.update
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-CRM-ACT-013-01
    proved_by: [ATS-CRM-ACT-013-01, TST-CRM-ACT-017, TST-CRM-ACT-027]
    statement: >-
      A new task can be offered by custom role identifier or built-in role key,
      but cannot be created both assigned to a person and offered to a role.
    kind: validation
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.role-claim.integration.spec.js#refuses
      a create naming both an assignee and a role, naming the field, and writes
      nothing
    origin: >-
      Andrew 2026-10-18 (role claim), recorded at
      services-crm:docs/workstreams/crm-tasks-role-claim.md
  - id: BR-CAP-CRM-ACT-013-02
    proved_by: [ATS-CRM-ACT-013-02, ATS-CRM-ACT-017-09, TST-CRM-ACT-015, TST-CRM-ACT-027]
    statement: >-
      Claiming an unqueued role offer requires Platform to confirm the caller
      holds that role for the workspace; a non-holder receives Forbidden and
      leaves the offer unchanged.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.role-claim.integration.spec.js#is
      refused 403 with the code task_claim_not_role_holder, and the task stays
      offered
    origin: >-
      Andrew 2026-10-18 (role claim), recorded at
      services-crm:docs/workstreams/crm-tasks-role-claim.md
  - id: BR-CAP-CRM-ACT-013-03
    proved_by: [ATS-CRM-ACT-013-03, TST-CRM-ACT-015, TST-CRM-ACT-024]
    statement: >-
      Concurrent role-holder claims produce one winner and conflicts naming that
      winner for later claimants.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.concurrency.integration.spec.js#refuses
      the other two 409 with the code task_claimed_by_other
    origin: >-
      Andrew 2026-10-18 (role claim), recorded at
      services-crm:docs/workstreams/crm-tasks-role-claim.md
  - id: BR-CAP-CRM-ACT-013-04
    proved_by: [ATS-CRM-ACT-012-10, ATS-CRM-ACT-013-04, ATS-CRM-ACT-013-07, TST-CRM-ACT-015, TST-CRM-ACT-027]
    statement: >-
      Claim preserves the candidate role, and release makes the task available
      to that role again.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.role-claim.integration.spec.js#keeps
      the candidate role, so the task is offered again
    origin: >-
      Andrew 2026-10-18 (role claim), recorded at
      services-crm:docs/workstreams/crm-tasks-role-claim.md
  - id: BR-CAP-CRM-ACT-013-05
    proved_by: [ATS-CRM-ACT-013-04, TST-CRM-ACT-015, TST-CRM-ACT-027]
    statement: >-
      Reassignment to a different person clears the role offer, while removing
      the current holder retains it.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.role-claim.integration.spec.js#clears
      the role when the task is given to somebody other than its holder
    origin: none
  - id: BR-CAP-CRM-ACT-013-06
    proved_by: []
    statement: >-
      Queued tasks use queue claim rules regardless of any candidate role, so a
      task updater need not hold that role to claim them.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.role-claim.integration.spec.js#is
      claimed through its queue, as every queued task is, by a user who does not
      hold the role
    origin: none
  - id: BR-CAP-CRM-ACT-013-07
    proved_by: [ATS-CRM-ACT-013-05, ATS-CRM-ACT-014-05, TST-CRM-ACT-015, TST-CRM-ACT-026]
    statement: >-
      The offered list returns unassigned open tasks outside queues for the
      user’s roles, ordered oldest first and paged with a maximum of 200 items.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.queries.integration.spec.js#answers
      the three tasks offered to the user’s roles, oldest first, then by id
    origin: none
  - id: BR-CAP-CRM-ACT-013-08
    proved_by: []
    statement: Ordinary task replacement preserves the candidate role.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.role-claim.integration.spec.js#keeps
      the role a replacement leaves out, since it is create-only
    origin: none
  - id: BR-CAP-CRM-ACT-013-09
    proved_by: [ATS-CRM-ACT-013-06]
    statement: The console has no role-offer creation control or offered-to-me task view.
    kind: policy
    enforced_at:
      - console
    must_prove: true
    provenance: unknown
    source: FND-CRM-ACT-010
    origin: none
  - id: BR-CAP-CRM-ACT-013-10
    proved_by: []
    statement: >-
      Role-offer creation checks reference syntax without verifying that the
      role exists for the customer.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-crm:modules/tasks/services/persistence/tasks.ts:candidateRoleAsWritten
    origin: none
  - id: BR-CAP-CRM-ACT-013-11
    proved_by: []
    statement: >-
      Offered-task listing omits an active-user check, allowing a service to
      obtain offers for a user Platform would prevent from claiming.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: documented
    source: >-
      services-crm:docs/workstreams/crm-tasks-role-claim.md#2. Should "offered
      to me" read the user's status?
    origin: none
  - id: BR-CAP-CRM-ACT-013-12
    proved_by: []
    statement: >-
      Role claims pass no related-record resource and therefore use
      workspace-wide or customer-wide role holdings.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-crm:modules/tasks/services/persistence/tasks.ts:holdsRole'
    origin: none
scenarios:
  - id: SC-CAP-CRM-ACT-013-01
    given: An unqueued review task is offered to Reviewers.
    when: Let a reviewer and a non-reviewer attempt claims.
    then: 'The reviewer can claim, while the non-holder is forbidden.'
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/e2e/tasks.e2e.spec.js#gives the task to
      the first holder to claim it, keeping the role
edge_cases:
  - id: SC-CAP-CRM-ACT-013-02
    given: A person holds the candidate role only in a different workspace.
    when: Attempt to claim the offered task.
    then: Platform membership evaluation rejects the claim.
    provenance: test
    source: >-
      services-crm:modules/tasks/tests/integration/services/persistence/tasks.role-claim.integration.spec.js#is
      refused when the role is held only in another tenant
constraints: []
depends_on:
  - CAP-CRM-ACT-012
related:
  - CAP-CRM-ACT-017
journeys:
  - JNY-CRM-ACT-005
open_questions:
  - OQ-CRM-ACT-002
evidence:
  - >-
    services-crm at a8d1364f1dd44b723bb5f9acba12f983e9ec8d69: Independently
    reviewed declarations, behavior and assertions identified in this
    capability’s row citations.
  - >-
    react-console at baf6dae382d6f41dce976c7f848667ccc37e076f: Independently
    reviewed declarations, behavior and assertions identified in this
    capability’s row citations.
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-006, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004]
exercised_by: [FAS-CRM-ACT-03-02, FAS-CRM-ACT-03-05, FAS-CRM-ACT-05-01, FAS-CRM-ACT-05-02]
suites: [TST-CRM-ACT-015, TST-CRM-ACT-017, TST-CRM-ACT-024, TST-CRM-ACT-026, TST-CRM-ACT-027]
---

# Offer work to a security role and reserve it by claim

## Purpose

Work can wait for an eligible role holder without creating another team queue.

## How It Works

A service or API client creates an unassigned task with a candidate role. A holder asks for the tasks offered to their roles. The offered list excludes queued and already held work. Claim asks Platform to verify the claimant’s role holding. The row remains protected while that decision and assignment occur. A competing claimant receives the winning holder’s identity. Release keeps the role available for another claim. Queued tasks follow queue claim behavior even if they also name a role. The console does not yet expose an offered-work view. The product should resolve invalid role references and the difference between offered-list eligibility and claim eligibility.

## Relationships

- Task assignment supplies shared assignment and release behavior.
- Workflow task actions create and reoffer role-directed work.
- Platform security answers role membership for claims.
