@haneinfo/assignment 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,33 +1,63 @@
1
- # @haneinfo/assignment
2
-
3
- See [agent-guide.md](agent-guide.md) for integration details.
4
-
5
- ## Instance readers and stored query values
6
-
7
- Every task creation (including initial-state entry, later rounds and self-entry) grants its
8
- assignee permanent read access to that instance in the same transaction. Assignment injects the
9
- state-machine-owned `StateMachineReaderGrants` service instead of writing another package's table.
10
- It requires state-machine 0.6 or later and the App's reader-table migration/backfill. OPEN,
11
- RESPONDED, CLOSED and CANCELLED tasks all retain their reader grants; there is no revoke operation.
12
- The grant is instance-specific and covers comments, following, lists and exports.
13
-
14
- After creating the reader table, Apps must backfill every existing task, regardless of status:
15
-
16
- ```sql
17
- INSERT INTO state_machine_instance_readers (instance_id, user_id, reason)
18
- SELECT DISTINCT instance_id, assignee_id, 'ASSIGNED'
19
- FROM assignment_tasks
20
- ON CONFLICT (instance_id, user_id) DO NOTHING;
21
- ```
22
-
23
- ## Date comparisons
24
-
25
- GT/GTE/LT/LTE compare numbers, valid calendar dates (YYYY-MM-DD), or timezone-qualified datetimes
26
- (YYYY-MM-DDTHH:mm:ss with optional fractional seconds and Z or +/-HH:mm). Both operands must have
27
- the same category. Dates use calendar order; datetimes compare UTC instants at millisecond precision.
28
- Invalid dates, mixed categories and empty operands yield false. EQ/NEQ/IN retain strict scalar equality;
29
- matching instants with different textual offsets are still unequal for those operators.
30
-
31
- ## Instance privacy boundary
32
-
33
- Task reads and responses first check task ownership and return identical TASK_NOT_FOUND/404 for another person's or a missing task. Every assignee receives a permanent state-machine reader grant on task creation, so the internal runtime snapshot read is restricted to an already authorized reader. `tasksOf` is a trusted internal API, not an HTTP/MCP instance lookup. USER transitions outside task responses apply state-machine's read-before-write checks; Assignment triggers keep their existing authorization.
1
+ # @haneinfo/assignment
2
+
3
+ See [agent-guide.md](agent-guide.md) for integration details.
4
+
5
+ ## Instance readers and stored query values
6
+
7
+ Every task creation (including initial-state entry, later rounds and self-entry) grants its
8
+ assignee permanent read access to that instance in the same transaction. Assignment injects the
9
+ state-machine-owned `StateMachineReaderGrants` service instead of writing another package's table.
10
+ It requires state-machine 0.6 or later and the App's reader-table migration/backfill. OPEN,
11
+ RESPONDED, CLOSED and CANCELLED tasks all retain their reader grants; there is no revoke operation.
12
+ The grant is instance-specific and covers comments, following, lists and exports.
13
+
14
+ After creating the reader table, Apps must backfill every existing task, regardless of status:
15
+
16
+ ```sql
17
+ INSERT INTO state_machine_instance_readers (instance_id, user_id, reason)
18
+ SELECT DISTINCT instance_id, assignee_id, 'ASSIGNED'
19
+ FROM assignment_tasks
20
+ ON CONFLICT (instance_id, user_id) DO NOTHING;
21
+ ```
22
+
23
+ ## Date comparisons
24
+
25
+ GT/GTE/LT/LTE compare numbers, valid calendar dates (YYYY-MM-DD), or timezone-qualified datetimes
26
+ (YYYY-MM-DDTHH:mm:ss with optional fractional seconds and Z or +/-HH:mm). Both operands must have
27
+ the same category. Dates use calendar order; datetimes compare UTC instants at millisecond precision.
28
+ Invalid dates, mixed categories and empty operands yield false. EQ/NEQ/IN retain strict scalar equality;
29
+ matching instants with different textual offsets are still unequal for those operators.
30
+
31
+ ## Instance privacy boundary
32
+
33
+ Task reads and responses first check task ownership and return identical TASK_NOT_FOUND/404 for another person's or a missing task. Every assignee receives a permanent state-machine reader grant on task creation, so the internal runtime snapshot read is restricted to an already authorized reader. `tasksOf` is a trusted internal API, not an HTTP/MCP instance lookup. USER transitions outside task responses apply state-machine's read-before-write checks; Assignment triggers keep their existing authorization.
34
+
35
+ ## Period delegation (draft implementation)
36
+
37
+ With the optional delegation resolver, original tasks remain and delegates receive separate tasks
38
+ with nullable onBehalfOfId and delegationId. Proxy titles start with [Delegate]. Task creation grants
39
+ permanent instance readership in the same transaction. No resolver means the existing behavior.
40
+ Migrate the two nullable assignment_tasks columns before deploying; no backfill of those columns is
41
+ needed for older tasks. Upgrade state-machine for optional actingUserId/onBehalfOfId history output.
42
+
43
+ ANY_ONE/SINGLE completes on the first original or delegated response. JOINT counts one vote per
44
+ original assignee; the first response closes that vote's other tasks and does not add votes. A
45
+ proxy never expands into another proxy. A delegate already present in the round is not duplicated;
46
+ when several originals share a delegate, deterministic delegation-id order picks one represented
47
+ original. Other originals keep their own required votes.
48
+
49
+ Delegation registers internal effects for immediate, idempotent backfill of original OPEN tasks and
50
+ transactional revocation cancellation. Future periods do not backfill tasks open before the start.
51
+ Expired OPEN proxy tasks are hidden in GET /assignments/mine and list_my_assignments; a response
52
+ commits CANCELLED and then raises DELEGATION_ENDED/409. Revocation cancels OPEN proxies in its own
53
+ transaction. Permanent readers survive both. GET /assignments/:id returns no response choices for
54
+ an expired OPEN proxy. Task ownership still hides other people's tasks as TASK_NOT_FOUND/404.
55
+
56
+ Task reads add optional onBehalfOfId and onBehalfOfName. Names use one authorized-page batch through
57
+ identity-store.findActiveNamesByIds; missing/inactive/older providers yield null. MCP names are
58
+ $userContent. A successful proxy response records actual actingUserId, and notifies the original
59
+ with assignment-response:<taskId>. Appointment notifications belong to delegation; task notification
60
+ keys remain assignment:<taskId>. Missing inbox capability skips notifications as before.
61
+
62
+ See @haneinfo/delegation's agent guide for period rules, human management and read-only MCP. There
63
+ is no MCP response, creation, revocation, per-task reassignment or delegation frontend.
package/agent-guide.md CHANGED
@@ -1,146 +1,176 @@
1
- # @haneinfo/assignment — Agent Guide
2
-
3
- ## Purpose
4
-
5
- The assignment mechanism (decision `202610-00b3`, first batch; details in its own decision). An
6
- `Assignment` definition says: when an instance of a StateMachine **enters a state**, these people
7
- get a task, and their **response takes a transition**. It covers approvals, read-and-acknowledge
8
- steps and task hand-offs.
9
-
10
- ```json
11
- {
12
- "kind": "Assignment",
13
- "schemaVersion": 1,
14
- "metadata": { "code": "equipment-manager-approval", "name": "Approve equipment loan" },
15
- "spec": {
16
- "stateMachine": { "kind": "StateMachine", "code": "equipment-loan-flow" },
17
- "onEnter": "SUBMITTED",
18
- "assignees": [{ "type": "ROLE", "role": "EQUIPMENT_MANAGER" }],
19
- "policy": "ANY_ONE",
20
- "responses": [
21
- { "key": "approve", "label": "Approve", "transition": "approve" },
22
- { "key": "reject", "label": "Reject", "transition": "reject" }
23
- ],
24
- "dueIn": "P2D"
25
- }
26
- }
27
- ```
28
-
29
- ## When to use it, and when not
30
-
31
- Use it whenever a person must act before a business object moves on. Do not use it for plain
32
- notifications (that is a Timer `NOTIFY` action or the notification inbox) or for decisions a rule
33
- could make (use a CHOICE state).
34
-
35
- ## Kind and example definition
36
-
37
- - `stateMachine`, `onEnter`: the machine and the state that opens the tasks. Not a FINAL or CHOICE state.
38
- - `assignees`: person resolvers — `SPECIFIC_USER` (`userIds`), `ROLE` (role machine name, resolved
39
- through RBAC), `FORM_FIELD_USER` (a `user_select` field of the machine's subject Form, by id),
40
- `SUBMITTER`, `DIRECT_SUPERVISOR`, `DEPARTMENT_HEAD`, `DIVISION_HEAD` (the last three require org-directory). Resolving to nobody makes the transition into `onEnter` fail with
41
- `ASSIGNEE_UNRESOLVED` — fix the role membership or the field.
42
- - `policy`: `ANY_ONE` (first response decides; use it for roles), `SINGLE` (same, but you expect
43
- exactly one person — a warning if the resolvers can produce several), `JOINT` (everybody must give
44
- the one non-`decisive` response; one `decisive` response — e.g. reject — decides at once).
45
- - `responses[]`: `key`, `label`, `transition` (must leave `onEnter`), `decisive` (JOINT only).
46
- - `dueIn`: ISO 8601 duration (`P2D`, `PT4H`); it only sets the task's due time. What happens when
47
- it passes is a Timer with an `ASSIGNMENT_DUE` anchor.
48
- - `title`: shown to the assignees; defaults to `metadata.name`.
49
- - Permissions: `assignment:definition:read|write|publish`.
50
-
51
- Instances pin the published assignments of their machine when they start; re-entering the state
52
- opens a new round. Leaving the state any other way (a Timer, a person) cancels open tasks.
53
-
54
- Self-transitions also cancel the old round before opening the next. A deciding response leaves
55
- the responding task `RESPONDED` and other open tasks `CLOSED`; an external state change uses
56
- `CANCELLED`. PostgreSQL responses lock the instance before reading/writing the round, so concurrent
57
- JOINT votes see committed earlier votes. Round evaluation reads every task, without a 500-row cap.
58
-
59
- Example: `examples/definitions/equipment-loan/equipment-manager-approval.assignment.json`.
60
-
61
- ## MCP tools
62
-
63
- | Tool | Scope | Use |
64
- | --- | --- | --- |
65
- | `list_my_assignments` | `<namespace>:assignment:read` (read only) | Tasks of the person the connection acts for, with responses and instance data (as `$userContent`) |
66
-
67
- There is no tool to respond: a response takes a transition (approve, reject) and stays a human
68
- step in the App. Register from the App: `assignmentMcpTools.registerInto(registry, { scopeNamespace })`.
69
-
70
- The scope is required at listing and invocation by the MCP host. No definition-read permission is
71
- required to see your own tasks: the acting user must own them. The client cannot select another
72
- user. Invalid status input returns `INVALID_INPUT`; a credential without an acting user is refused.
73
-
74
- ## HTTP API (people)
75
-
76
- | Route | Purpose |
77
- | --- | --- |
78
- | `GET /assignments/mine?status=OPEN` | Your tasks |
79
- | `GET /assignments/:id` | One of your tasks with the instance |
80
- | `POST /assignments/:id/respond` `{ response, comment? }` | Respond; may take the transition |
81
-
82
- ## Events
83
-
84
- `assignment.opened` (`assignmentCode`, `round`, `dueAt`, `assigneeIds`) and `assignment.closed`
85
- (`assignmentCode`, `round`, `outcome`: the response key or `CANCELLED`), on the state-machine
86
- runtime's event channel. Timer uses them for `ASSIGNMENT_DUE`.
87
-
88
- ## Adapters
89
-
90
- None. Roles resolve through `haneinfo.rbac-policy` (`userIdsWithRole`); assignees are notified through
91
- `haneinfo.notification-inbox` when it is installed.
92
-
93
- ## Common error codes and fixes
94
-
95
- | Code | Fix |
96
- | --- | --- |
97
- | `UNKNOWN_STATE` / `ASSIGNMENT_ON_FINAL_STATE` | `onEnter` must be a non-FINAL state of the machine |
98
- | `UNKNOWN_TRANSITION` / `TRANSITION_NOT_FROM_STATE` | A response's transition must leave `onEnter` |
99
- | `JOINT_NEEDS_ONE_AGREEMENT` | Mark all but one JOINT response as `decisive` |
100
- | `SINGLE_MAY_RESOLVE_MANY` (warning) | Use `ANY_ONE` for roles |
101
- | `NOT_A_USER_FIELD` / `NO_SUBJECT_FORM` | `FORM_FIELD_USER` needs a `user_select` field of the subject Form |
102
- | `INVALID_DURATION` | `dueIn` is a positive duration without months or years |
103
- | `ASSIGNEE_UNRESOLVED` (runtime) | The resolvers produced nobody; see `details.unresolved` |
104
- | `TASK_NOT_OPEN` (runtime) | Someone else already decided, or the instance moved on |
105
-
106
- ## Conditional activation
107
-
108
- Optional spec.when uses the shared Form evaluateCondition function and PREDICATE/GROUP syntax,
109
- including CONTEXT SUBMITTER_ID. False skips this assignment with no tasks or notifications and does
110
- not block other transitions, even when every assignment is skipped. Empty inputs are errors.
111
-
112
- The prepareStateEntry listener fixes when and assignee results before entry writes. Each matching
113
- assignment resolves its people once and uses that exact result to open tasks. Any unresolved resolver
114
- blocks entry, including partially resolved lists; details.unresolved preserves organization reasons
115
- and unit information. A CHOICE stays in CHOICE and records/notifies the failure; other transitions
116
- roll back to their original state and report the failure. Existing tasks keep their assignees.
117
-
118
- ## Instance readers and stored query values
119
-
120
- Every task creation (including initial-state entry, later rounds and self-entry) grants its
121
- assignee permanent read access to that instance in the same transaction. Assignment injects the
122
- state-machine-owned `StateMachineReaderGrants` service instead of writing another package's table.
123
- It requires state-machine 0.6 or later and the App's reader-table migration/backfill. OPEN,
124
- RESPONDED, CLOSED and CANCELLED tasks all retain their reader grants; there is no revoke operation.
125
- The grant is instance-specific and covers comments, following, lists and exports.
126
-
127
- After creating the reader table, Apps must backfill every existing task, regardless of status:
128
-
129
- ```sql
130
- INSERT INTO state_machine_instance_readers (instance_id, user_id, reason)
131
- SELECT DISTINCT instance_id, assignee_id, 'ASSIGNED'
132
- FROM assignment_tasks
133
- ON CONFLICT (instance_id, user_id) DO NOTHING;
134
- ```
135
-
136
- ## Date comparisons
137
-
138
- GT/GTE/LT/LTE compare numbers, valid calendar dates (YYYY-MM-DD), or timezone-qualified datetimes
139
- (YYYY-MM-DDTHH:mm:ss with optional fractional seconds and Z or +/-HH:mm). Both operands must have
140
- the same category. Dates use calendar order; datetimes compare UTC instants at millisecond precision.
141
- Invalid dates, mixed categories and empty operands yield false. EQ/NEQ/IN retain strict scalar equality;
142
- matching instants with different textual offsets are still unequal for those operators.
143
-
144
- ## Instance privacy boundary
145
-
146
- Task reads and responses first check task ownership and return identical TASK_NOT_FOUND/404 for another person's or a missing task. Every assignee receives a permanent state-machine reader grant on task creation, so the internal runtime snapshot read is restricted to an already authorized reader. `tasksOf` is a trusted internal API, not an HTTP/MCP instance lookup. USER transitions outside task responses apply state-machine's read-before-write checks; Assignment triggers keep their existing authorization.
1
+ # @haneinfo/assignment — Agent Guide
2
+
3
+ ## Purpose
4
+
5
+ The assignment mechanism (decision `202610-00b3`, first batch; details in its own decision). An
6
+ `Assignment` definition says: when an instance of a StateMachine **enters a state**, these people
7
+ get a task, and their **response takes a transition**. It covers approvals, read-and-acknowledge
8
+ steps and task hand-offs.
9
+
10
+ ```json
11
+ {
12
+ "kind": "Assignment",
13
+ "schemaVersion": 1,
14
+ "metadata": { "code": "equipment-manager-approval", "name": "Approve equipment loan" },
15
+ "spec": {
16
+ "stateMachine": { "kind": "StateMachine", "code": "equipment-loan-flow" },
17
+ "onEnter": "SUBMITTED",
18
+ "assignees": [{ "type": "ROLE", "role": "EQUIPMENT_MANAGER" }],
19
+ "policy": "ANY_ONE",
20
+ "responses": [
21
+ { "key": "approve", "label": "Approve", "transition": "approve" },
22
+ { "key": "reject", "label": "Reject", "transition": "reject" }
23
+ ],
24
+ "dueIn": "P2D"
25
+ }
26
+ }
27
+ ```
28
+
29
+ ## When to use it, and when not
30
+
31
+ Use it whenever a person must act before a business object moves on. Do not use it for plain
32
+ notifications (that is a Timer `NOTIFY` action or the notification inbox) or for decisions a rule
33
+ could make (use a CHOICE state).
34
+
35
+ ## Kind and example definition
36
+
37
+ - `stateMachine`, `onEnter`: the machine and the state that opens the tasks. Not a FINAL or CHOICE state.
38
+ - `assignees`: person resolvers — `SPECIFIC_USER` (`userIds`), `ROLE` (role machine name, resolved
39
+ through RBAC), `FORM_FIELD_USER` (a `user_select` field of the machine's subject Form, by id),
40
+ `SUBMITTER`, `DIRECT_SUPERVISOR`, `DEPARTMENT_HEAD`, `DIVISION_HEAD` (the last three require org-directory). Resolving to nobody makes the transition into `onEnter` fail with
41
+ `ASSIGNEE_UNRESOLVED` — fix the role membership or the field.
42
+ - `policy`: `ANY_ONE` (first response decides; use it for roles), `SINGLE` (same, but you expect
43
+ exactly one person — a warning if the resolvers can produce several), `JOINT` (everybody must give
44
+ the one non-`decisive` response; one `decisive` response — e.g. reject — decides at once).
45
+ - `responses[]`: `key`, `label`, `transition` (must leave `onEnter`), `decisive` (JOINT only).
46
+ - `dueIn`: ISO 8601 duration (`P2D`, `PT4H`); it only sets the task's due time. What happens when
47
+ it passes is a Timer with an `ASSIGNMENT_DUE` anchor.
48
+ - `title`: shown to the assignees; defaults to `metadata.name`.
49
+ - Permissions: `assignment:definition:read|write|publish`.
50
+
51
+ Instances pin the published assignments of their machine when they start; re-entering the state
52
+ opens a new round. Leaving the state any other way (a Timer, a person) cancels open tasks.
53
+
54
+ Self-transitions also cancel the old round before opening the next. A deciding response leaves
55
+ the responding task `RESPONDED` and other open tasks `CLOSED`; an external state change uses
56
+ `CANCELLED`. PostgreSQL responses lock the instance before reading/writing the round, so concurrent
57
+ JOINT votes see committed earlier votes. Round evaluation reads every task, without a 500-row cap.
58
+
59
+ Example: `examples/definitions/equipment-loan/equipment-manager-approval.assignment.json`.
60
+
61
+ ## MCP tools
62
+
63
+ | Tool | Scope | Use |
64
+ | --- | --- | --- |
65
+ | `list_my_assignments` | `<namespace>:assignment:read` (read only) | Tasks of the person the connection acts for, with responses and instance data (as `$userContent`) |
66
+
67
+ There is no tool to respond: a response takes a transition (approve, reject) and stays a human
68
+ step in the App. Register from the App: `assignmentMcpTools.registerInto(registry, { scopeNamespace })`.
69
+
70
+ The scope is required at listing and invocation by the MCP host. No definition-read permission is
71
+ required to see your own tasks: the acting user must own them. The client cannot select another
72
+ user. Invalid status input returns `INVALID_INPUT`; a credential without an acting user is refused.
73
+
74
+ ## HTTP API (people)
75
+
76
+ | Route | Purpose |
77
+ | --- | --- |
78
+ | `GET /assignments/mine?status=OPEN` | Your tasks |
79
+ | `GET /assignments/:id` | One of your tasks with the instance |
80
+ | `POST /assignments/:id/respond` `{ response, comment? }` | Respond; may take the transition |
81
+
82
+ ## Events
83
+
84
+ `assignment.opened` (`assignmentCode`, `round`, `dueAt`, `assigneeIds`) and `assignment.closed`
85
+ (`assignmentCode`, `round`, `outcome`: the response key or `CANCELLED`), on the state-machine
86
+ runtime's event channel. Timer uses them for `ASSIGNMENT_DUE`.
87
+
88
+ ## Adapters
89
+
90
+ None. Roles resolve through `haneinfo.rbac-policy` (`userIdsWithRole`); assignees are notified through
91
+ `haneinfo.notification-inbox` when it is installed.
92
+
93
+ ## Common error codes and fixes
94
+
95
+ | Code | Fix |
96
+ | --- | --- |
97
+ | `UNKNOWN_STATE` / `ASSIGNMENT_ON_FINAL_STATE` | `onEnter` must be a non-FINAL state of the machine |
98
+ | `UNKNOWN_TRANSITION` / `TRANSITION_NOT_FROM_STATE` | A response's transition must leave `onEnter` |
99
+ | `JOINT_NEEDS_ONE_AGREEMENT` | Mark all but one JOINT response as `decisive` |
100
+ | `SINGLE_MAY_RESOLVE_MANY` (warning) | Use `ANY_ONE` for roles |
101
+ | `NOT_A_USER_FIELD` / `NO_SUBJECT_FORM` | `FORM_FIELD_USER` needs a `user_select` field of the subject Form |
102
+ | `INVALID_DURATION` | `dueIn` is a positive duration without months or years |
103
+ | `ASSIGNEE_UNRESOLVED` (runtime) | The resolvers produced nobody; see `details.unresolved` |
104
+ | `TASK_NOT_OPEN` (runtime) | Someone else already decided, or the instance moved on |
105
+
106
+ ## Conditional activation
107
+
108
+ Optional spec.when uses the shared Form evaluateCondition function and PREDICATE/GROUP syntax,
109
+ including CONTEXT SUBMITTER_ID. False skips this assignment with no tasks or notifications and does
110
+ not block other transitions, even when every assignment is skipped. Empty inputs are errors.
111
+
112
+ The prepareStateEntry listener fixes when and assignee results before entry writes. Each matching
113
+ assignment resolves its people once and uses that exact result to open tasks. Any unresolved resolver
114
+ blocks entry, including partially resolved lists; details.unresolved preserves organization reasons
115
+ and unit information. A CHOICE stays in CHOICE and records/notifies the failure; other transitions
116
+ roll back to their original state and report the failure. Existing tasks keep their assignees.
117
+
118
+ ## Instance readers and stored query values
119
+
120
+ Every task creation (including initial-state entry, later rounds and self-entry) grants its
121
+ assignee permanent read access to that instance in the same transaction. Assignment injects the
122
+ state-machine-owned `StateMachineReaderGrants` service instead of writing another package's table.
123
+ It requires state-machine 0.6 or later and the App's reader-table migration/backfill. OPEN,
124
+ RESPONDED, CLOSED and CANCELLED tasks all retain their reader grants; there is no revoke operation.
125
+ The grant is instance-specific and covers comments, following, lists and exports.
126
+
127
+ After creating the reader table, Apps must backfill every existing task, regardless of status:
128
+
129
+ ```sql
130
+ INSERT INTO state_machine_instance_readers (instance_id, user_id, reason)
131
+ SELECT DISTINCT instance_id, assignee_id, 'ASSIGNED'
132
+ FROM assignment_tasks
133
+ ON CONFLICT (instance_id, user_id) DO NOTHING;
134
+ ```
135
+
136
+ ## Date comparisons
137
+
138
+ GT/GTE/LT/LTE compare numbers, valid calendar dates (YYYY-MM-DD), or timezone-qualified datetimes
139
+ (YYYY-MM-DDTHH:mm:ss with optional fractional seconds and Z or +/-HH:mm). Both operands must have
140
+ the same category. Dates use calendar order; datetimes compare UTC instants at millisecond precision.
141
+ Invalid dates, mixed categories and empty operands yield false. EQ/NEQ/IN retain strict scalar equality;
142
+ matching instants with different textual offsets are still unequal for those operators.
143
+
144
+ ## Instance privacy boundary
145
+
146
+ Task reads and responses first check task ownership and return identical TASK_NOT_FOUND/404 for another person's or a missing task. Every assignee receives a permanent state-machine reader grant on task creation, so the internal runtime snapshot read is restricted to an already authorized reader. `tasksOf` is a trusted internal API, not an HTTP/MCP instance lookup. USER transitions outside task responses apply state-machine's read-before-write checks; Assignment triggers keep their existing authorization.
147
+
148
+ ## Period delegation (draft implementation)
149
+
150
+ With the optional delegation resolver, original tasks remain and delegates receive separate tasks
151
+ with nullable onBehalfOfId and delegationId. Proxy titles start with [Delegate]. Task creation grants
152
+ permanent instance readership in the same transaction. No resolver means the existing behavior.
153
+ Migrate the two nullable assignment_tasks columns before deploying; no backfill of those columns is
154
+ needed for older tasks. Upgrade state-machine for optional actingUserId/onBehalfOfId history output.
155
+
156
+ ANY_ONE/SINGLE completes on the first original or delegated response. JOINT counts one vote per
157
+ original assignee; the first response closes that vote's other tasks and does not add votes. A
158
+ proxy never expands into another proxy. A delegate already present in the round is not duplicated;
159
+ when several originals share a delegate, deterministic delegation-id order picks one represented
160
+ original. Other originals keep their own required votes.
161
+
162
+ Delegation registers internal effects for immediate, idempotent backfill of original OPEN tasks and
163
+ transactional revocation cancellation. Future periods do not backfill tasks open before the start.
164
+ Expired OPEN proxy tasks are hidden in GET /assignments/mine and list_my_assignments; a response
165
+ commits CANCELLED and then raises DELEGATION_ENDED/409. Revocation cancels OPEN proxies in its own
166
+ transaction. Permanent readers survive both. GET /assignments/:id returns no response choices for
167
+ an expired OPEN proxy. Task ownership still hides other people's tasks as TASK_NOT_FOUND/404.
168
+
169
+ Task reads add optional onBehalfOfId and onBehalfOfName. Names use one authorized-page batch through
170
+ identity-store.findActiveNamesByIds; missing/inactive/older providers yield null. MCP names are
171
+ $userContent. A successful proxy response records actual actingUserId, and notifies the original
172
+ with assignment-response:<taskId>. Appointment notifications belong to delegation; task notification
173
+ keys remain assignment:<taskId>. Missing inbox capability skips notifications as before.
174
+
175
+ See @haneinfo/delegation's agent guide for period rules, human management and read-only MCP. There
176
+ is no MCP response, creation, revocation, per-task reassignment or delegation frontend.
@@ -11,6 +11,7 @@ export declare class AssignmentController {
11
11
  respond(user: InteractivePrincipal, id: string, body: unknown): Promise<{
12
12
  completed: boolean;
13
13
  task: {
14
+ actingUserId: string;
14
15
  status: "RESPONDED";
15
16
  response: string;
16
17
  comment: string | null;
@@ -21,6 +22,8 @@ export declare class AssignmentController {
21
22
  assignmentVersion: number;
22
23
  round: number;
23
24
  assigneeId: string;
25
+ onBehalfOfId?: string | null;
26
+ delegationId?: string | null;
24
27
  title: string;
25
28
  dueAt: Date | null;
26
29
  createdAt: Date;
@@ -29,6 +32,7 @@ export declare class AssignmentController {
29
32
  } | {
30
33
  completed: boolean;
31
34
  task: {
35
+ actingUserId: string;
32
36
  status: "RESPONDED";
33
37
  response: string;
34
38
  comment: string | null;
@@ -39,6 +43,8 @@ export declare class AssignmentController {
39
43
  assignmentVersion: number;
40
44
  round: number;
41
45
  assigneeId: string;
46
+ onBehalfOfId?: string | null;
47
+ delegationId?: string | null;
42
48
  title: string;
43
49
  dueAt: Date | null;
44
50
  createdAt: Date;
@@ -1 +1 @@
1
- {"version":3,"file":"assignment.controller.d.ts","sourceRoot":"","sources":["../src/assignment.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAkB,MAAM,sBAAsB,CAAC;AAajF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAwBzD,0GAA0G;AAC1G,qBAEa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAAX,WAAW,EAAE,iBAAiB;IAG3D,IAAI,CAAgB,IAAI,EAAE,oBAAoB,EAAW,KAAK,EAAE,OAAO;;;IAUvE,GAAG,CAAgB,IAAI,EAAE,oBAAoB,EAAe,EAAE,EAAE,MAAM;IAKtE,OAAO,CACU,IAAI,EAAE,oBAAoB,EAC5B,EAAE,EAAE,MAAM,EACf,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYxB"}
1
+ {"version":3,"file":"assignment.controller.d.ts","sourceRoot":"","sources":["../src/assignment.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAkB,MAAM,sBAAsB,CAAC;AAajF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAwBzD,0GAA0G;AAC1G,qBAEa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAAX,WAAW,EAAE,iBAAiB;IAG3D,IAAI,CAAgB,IAAI,EAAE,oBAAoB,EAAW,KAAK,EAAE,OAAO;;;IAUvE,GAAG,CAAgB,IAAI,EAAE,oBAAoB,EAAe,EAAE,EAAE,MAAM;IAKtE,OAAO,CACU,IAAI,EAAE,oBAAoB,EAC5B,EAAE,EAAE,MAAM,EACf,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"assignment.module.d.ts","sourceRoot":"","sources":["../src/assignment.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQ/E,qBACa,0BAA2B,YAAW,YAAY;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,sBAAsB;IAE1F,YAAY;CAGb;AAED,qBAca,gBAAgB;CAAG"}
1
+ {"version":3,"file":"assignment.module.d.ts","sourceRoot":"","sources":["../src/assignment.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQ/E,qBACa,0BAA2B,YAAW,YAAY;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,sBAAsB;IAE1F,YAAY;CAGb;AAED,qBAea,gBAAgB;CAAG"}
@@ -43,6 +43,7 @@ exports.AssignmentModule = AssignmentModule = __decorate([
43
43
  (0, common_2.Module)({
44
44
  controllers: [assignment_controller_1.AssignmentController],
45
45
  providers: [
46
+ { provide: assignment_service_1.ASSIGNMENT_CLOCK, useValue: () => new Date() },
46
47
  AssignmentKindRegistration,
47
48
  {
48
49
  provide: store_1.ASSIGNMENT_STORE,
@@ -1 +1 @@
1
- {"version":3,"file":"assignment.module.js","sourceRoot":"","sources":["../src/assignment.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,6CAAiD;AACjD,qDAAwF;AACxF,2CAA+E;AAC/E,mEAA+D;AAC/D,6DAAyD;AACzD,iCAAkD;AAClD,2CAAiD;AACjD,iDAAuD;AACvD,mCAA2C;AAGpC,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IACrC,YAA0D,QAAgC;QAAhC,aAAQ,GAAR,QAAQ,CAAwB;IAAG,CAAC;IAE9F,YAAY;QACV,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,+BAAwB,CAAC,CAAC;IACvD,CAAC;CACF,CAAA;AANY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,mBAAU,GAAE;IAEE,WAAA,IAAA,eAAM,EAAC,gCAAmB,CAAC,CAAA;;GAD7B,0BAA0B,CAMtC;AAgBM,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAAG,CAAA;AAAnB,4CAAgB;2BAAhB,gBAAgB;IAd5B,IAAA,eAAM,EAAC;QACN,WAAW,EAAE,CAAC,4CAAoB,CAAC;QACnC,SAAS,EAAE;YACT,0BAA0B;YAC1B;gBACE,OAAO,EAAE,wBAAgB;gBACzB,UAAU,EAAE,CAAC,MAAqB,EAAE,EAAE,CAAC,IAAI,oCAAqB,CAAC,MAAM,CAAC;gBACxE,MAAM,EAAE,CAAC,sBAAa,CAAC;aACxB;YACD,sCAAiB;YACjB,8BAAkB;SACnB;QACD,OAAO,EAAE,CAAC,sCAAiB,EAAE,8BAAkB,CAAC;KACjD,CAAC;GACW,gBAAgB,CAAG"}
1
+ {"version":3,"file":"assignment.module.js","sourceRoot":"","sources":["../src/assignment.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,6CAAiD;AACjD,qDAAwF;AACxF,2CAA+E;AAC/E,mEAA+D;AAC/D,6DAA2E;AAC3E,iCAAkD;AAClD,2CAAiD;AACjD,iDAAuD;AACvD,mCAA2C;AAGpC,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IACrC,YAA0D,QAAgC;QAAhC,aAAQ,GAAR,QAAQ,CAAwB;IAAG,CAAC;IAE9F,YAAY;QACV,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,+BAAwB,CAAC,CAAC;IACvD,CAAC;CACF,CAAA;AANY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,mBAAU,GAAE;IAEE,WAAA,IAAA,eAAM,EAAC,gCAAmB,CAAC,CAAA;;GAD7B,0BAA0B,CAMtC;AAiBM,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAAG,CAAA;AAAnB,4CAAgB;2BAAhB,gBAAgB;IAf5B,IAAA,eAAM,EAAC;QACN,WAAW,EAAE,CAAC,4CAAoB,CAAC;QACnC,SAAS,EAAE;YACT,EAAE,OAAO,EAAE,qCAAgB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE;YACzD,0BAA0B;YAC1B;gBACE,OAAO,EAAE,wBAAgB;gBACzB,UAAU,EAAE,CAAC,MAAqB,EAAE,EAAE,CAAC,IAAI,oCAAqB,CAAC,MAAM,CAAC;gBACxE,MAAM,EAAE,CAAC,sBAAa,CAAC;aACxB;YACD,sCAAiB;YACjB,8BAAkB;SACnB;QACD,OAAO,EAAE,CAAC,sCAAiB,EAAE,8BAAkB,CAAC;KACjD,CAAC;GACW,gBAAgB,CAAG"}
@@ -10,7 +10,7 @@
10
10
  * transaction, with an ASSIGNMENT trigger (which skips the transition's person permission: the
11
11
  * assignment itself is the authorization).
12
12
  */
13
- import { type DefinitionRegistryPort, type NotificationInboxPort, type OrgDirectoryPort, type RbacPolicyPort, type StateMachineInstanceView, type StateMachineListener, type StateMachineRuntimePort } from '@haneinfo/plugin-api';
13
+ import { type DefinitionRegistryPort, type DelegationMatch, type DelegationResolverPort, type IdentityStorePort, type NotificationInboxPort, type OrgDirectoryPort, type RbacPolicyPort, type StateMachineInstanceView, type StateMachineListener, type StateMachineRuntimePort } from '@haneinfo/plugin-api';
14
14
  import { StateMachineReaderGrants } from '@haneinfo/state-machine';
15
15
  import { type OnModuleInit } from '@nestjs/common';
16
16
  import { type AssignmentStore, type TaskRecord } from './store';
@@ -18,6 +18,8 @@ import type { AssignmentResponse, AssignmentSpec } from './types';
18
18
  export declare const ASSIGNMENT_CLOCK: unique symbol;
19
19
  export declare const ASSIGNMENT_APP_NAME: unique symbol;
20
20
  export interface AssignmentTaskView extends TaskRecord {
21
+ onBehalfOfName?: string | null;
22
+ actingUserId?: string;
21
23
  responses: Pick<AssignmentResponse, 'key' | 'label'>[];
22
24
  policy: AssignmentSpec['policy'];
23
25
  instance: Pick<StateMachineInstanceView, 'id' | 'machine' | 'state' | 'data' | 'submitterId' | 'revision'> | null;
@@ -31,15 +33,25 @@ export declare class AssignmentService implements OnModuleInit {
31
33
  private readonly notifications?;
32
34
  private readonly appName;
33
35
  private readonly orgDirectory?;
36
+ private readonly delegation?;
37
+ private readonly identity?;
34
38
  private readonly now;
35
39
  private readonly preparedEntries;
36
40
  readonly listener: StateMachineListener;
37
- constructor(store: AssignmentStore, runtime: StateMachineRuntimePort, registry: DefinitionRegistryPort, readerGrants: StateMachineReaderGrants, rbac?: RbacPolicyPort | undefined, notifications?: NotificationInboxPort | undefined, clock?: () => Date, appName?: string, orgDirectory?: OrgDirectoryPort | undefined);
41
+ constructor(store: AssignmentStore, runtime: StateMachineRuntimePort, registry: DefinitionRegistryPort, readerGrants: StateMachineReaderGrants, rbac?: RbacPolicyPort | undefined, notifications?: NotificationInboxPort | undefined, clock?: () => Date, appName?: string, orgDirectory?: OrgDirectoryPort | undefined, delegation?: DelegationResolverPort | undefined, identity?: IdentityStorePort | undefined);
38
42
  onModuleInit(): void;
39
43
  private pin;
40
44
  private prepareEntry;
41
45
  private cancelOpen;
42
46
  private open;
47
+ private notifyTasks;
48
+ private expandDelegations;
49
+ /** Called inside delegation creation; instance locks make retries idempotent. */
50
+ backfillDelegation(delegation: DelegationMatch, tx: unknown): Promise<void>;
51
+ /** Joins revocation's transaction. CAS and row locks serialize cancellation with responses. */
52
+ prepareDelegationRevocation(delegationId: string, tx: unknown): Promise<void>;
53
+ cancelDelegation(delegationId: string, tx: unknown): Promise<void>;
54
+ private delegationActive;
43
55
  /** A person responds to their task. Human interface only (decision 202610-00b3, point 16 by analogy). */
44
56
  respond(input: {
45
57
  taskId: string;
@@ -49,6 +61,7 @@ export declare class AssignmentService implements OnModuleInit {
49
61
  }): Promise<{
50
62
  completed: boolean;
51
63
  task: {
64
+ actingUserId: string;
52
65
  status: "RESPONDED";
53
66
  response: string;
54
67
  comment: string | null;
@@ -59,6 +72,8 @@ export declare class AssignmentService implements OnModuleInit {
59
72
  assignmentVersion: number;
60
73
  round: number;
61
74
  assigneeId: string;
75
+ onBehalfOfId?: string | null;
76
+ delegationId?: string | null;
62
77
  title: string;
63
78
  dueAt: Date | null;
64
79
  createdAt: Date;
@@ -67,6 +82,7 @@ export declare class AssignmentService implements OnModuleInit {
67
82
  } | {
68
83
  completed: boolean;
69
84
  task: {
85
+ actingUserId: string;
70
86
  status: "RESPONDED";
71
87
  response: string;
72
88
  comment: string | null;
@@ -77,6 +93,8 @@ export declare class AssignmentService implements OnModuleInit {
77
93
  assignmentVersion: number;
78
94
  round: number;
79
95
  assigneeId: string;
96
+ onBehalfOfId?: string | null;
97
+ delegationId?: string | null;
80
98
  title: string;
81
99
  dueAt: Date | null;
82
100
  createdAt: Date;
@@ -91,6 +109,7 @@ export declare class AssignmentService implements OnModuleInit {
91
109
  getMine(userId: string, taskId: string): Promise<AssignmentTaskView>;
92
110
  /** Every task of an instance, for its history view. */
93
111
  tasksOf(instanceId: string, tx?: unknown): Promise<TaskRecord[]>;
112
+ private withNames;
94
113
  private view;
95
114
  }
96
115
  //# sourceMappingURL=assignment.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assignment.service.d.ts","sourceRoot":"","sources":["../src/assignment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAEL,KAAK,sBAAsB,EAG3B,KAAK,qBAAqB,EAE1B,KAAK,gBAAgB,EAGrB,KAAK,cAAc,EAGnB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAsB,KAAK,YAAY,EAAY,MAAM,gBAAgB,CAAC;AAEjF,OAAO,EAEL,KAAK,eAAe,EAGpB,KAAK,UAAU,EAChB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAElE,eAAO,MAAM,gBAAgB,eAA0C,CAAC;AACxE,eAAO,MAAM,mBAAmB,eAA6C,CAAC;AAE9E,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,SAAS,EAAE,IAAI,CAAC,kBAAkB,EAAE,KAAK,GAAG,OAAO,CAAC,EAAE,CAAC;IACvD,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IACjC,QAAQ,EAAE,IAAI,CACZ,wBAAwB,EACxB,IAAI,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,CACjE,GAAG,IAAI,CAAC;CACV;AAED,qBACa,iBAAkB,YAAW,YAAY;IAqBxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACpB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IACf,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAC9B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IA5BnE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgD;IAEhF,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAcrC;gBAG2C,KAAK,EAAE,eAAe,EACjB,OAAO,EAAE,uBAAuB,EAClC,QAAQ,EAAE,sBAAsB,EAC3B,YAAY,EAAE,wBAAwB,EACvC,IAAI,CAAC,EAAE,cAAc,YAAA,EACd,aAAa,CAAC,EAAE,qBAAqB,YAAA,EACxD,KAAK,CAAC,EAAE,MAAM,IAAI,EACE,OAAO,GAAE,MAAc,EAC7B,YAAY,CAAC,EAAE,gBAAgB,YAAA;IAKrF,YAAY;YAME,GAAG;YAaH,YAAY;YA0CZ,UAAU;YAmBV,IAAI;IAkElB,yGAAyG;IACnG,OAAO,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAgHrF,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAkB,GAChD,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAO1B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAS1E,uDAAuD;IACjD,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,OAAO;YAIhC,IAAI;CA4BnB"}
1
+ {"version":3,"file":"assignment.service.d.ts","sourceRoot":"","sources":["../src/assignment.service.ts"],"names":[],"mappings":"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"}