@agent-native/core 0.210.1 β 0.211.0-nightly-20261020183616
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/dist/action.d.ts +8 -0
- package/dist/action.js +17 -0
- package/dist/agent/production-agent.js +11 -20
- package/dist/client/chat/agentkit-protocol.js +48 -5
- package/dist/client/chat/runtime.d.ts +2 -0
- package/dist/client/chat/runtime.js +6 -1
- package/dist/client/hooks/index.d.ts +1 -1
- package/dist/client/hooks/index.js +1 -1
- package/dist/client/resources/mcp-integration-logos.js +4 -0
- package/dist/client/session-identity.d.ts +8 -0
- package/dist/client/session-identity.js +13 -0
- package/dist/client/use-action.d.ts +14 -0
- package/dist/client/use-action.js +117 -28
- package/dist/client/use-agent-engine-configured.d.ts +2 -2
- package/dist/client/use-agent-engine-configured.js +3 -9
- package/dist/client/use-session.js +2 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +24 -3
- package/dist/mcp/actions/revoke-org-service-token.js +5 -1
- package/dist/mcp/execute-action-call.js +8 -17
- package/dist/observability/routes.d.ts +5 -5
- package/dist/org/actions/set-app-member-roles.js +4 -0
- package/dist/org/actions/set-app-permission-roles.js +4 -0
- package/dist/org/actions/set-workspace-app-access.js +4 -0
- package/dist/org/index.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +17 -17
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/review/suggestions/actions.d.ts +1 -0
- package/dist/review/suggestions/actions.js +54 -42
- package/dist/secrets/actions/delete-api-key.js +4 -0
- package/dist/secrets/routes.d.ts +4 -4
- package/dist/server/action-approval.d.ts +15 -0
- package/dist/server/action-approval.js +39 -0
- package/dist/server/action-routes.js +33 -28
- package/dist/server/edge.d.ts +1 -0
- package/dist/server/edge.js +1 -0
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/server/workspace-provider-oauth.js +1 -0
- package/dist/shared/action-error-codes.d.ts +5 -0
- package/dist/shared/action-error-codes.js +5 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +5 -3
- package/dist/templates/default/.agents/skills/actions/references/action-fields.md +5 -3
- package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +105 -33
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +128 -74
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +39 -11
- package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +5 -3
- package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +5 -3
- package/dist/vite/client.js +2 -1
- package/docs/content/actions-access-control.mdx +3 -3
- package/package.json +4 -4
- package/src/templates/chat/.agents/skills/actions/references/action-fields.md +5 -3
- package/src/templates/default/.agents/skills/actions/references/action-fields.md +5 -3
- package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +105 -33
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +128 -74
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +39 -11
- package/src/templates/headless/.agents/skills/actions/references/action-fields.md +5 -3
- package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +5 -3
|
@@ -21,7 +21,25 @@ Four phases, in order. Phase 0 comes before any investigation, not after.
|
|
|
21
21
|
2. **Fix** what the evidence actually proves, at the owning boundary.
|
|
22
22
|
3. **Reply** with useful questions, then recap.
|
|
23
23
|
|
|
24
|
-
Output is fixes. For every report root this task owns, keep one concise, current same-actor status reply after the latest human message. It names every verified `β
` scope and its evidence, every open scope, and each `π«` action and owner (or why a mark does not apply). Add and read back root `β
` as soon as direct post-change proof verifies a scope, and root `π«` as soon as another person or team must act. An `π` alone never completes the status. Preserve all reaction history, and follow [`slack-reaction-replies.md`](references/slack-reaction-replies.md). Do not reply on person-assigned or `:mag:` items.
|
|
24
|
+
Output is fixes. For every unheld in-scope report root this task owns, keep one concise, current same-actor status reply after the latest human message. It names every verified `β
` scope and its evidence, every open scope, and each `π«` action and owner (or why a mark does not apply). Add and read back root `β
` as soon as direct post-change proof verifies a scope, and root `π«` as soon as another person or team must act. An `π` alone never completes the status. Preserve all reaction history, and follow [`slack-reaction-replies.md`](references/slack-reaction-replies.md). Do not reply on held, person-assigned, or `:mag:` items.
|
|
25
|
+
|
|
26
|
+
### Read the root marks as history; use the reply for current status
|
|
27
|
+
|
|
28
|
+
- `π` records this workflow's claim. It does not mean the report is still open.
|
|
29
|
+
- `β
` records a scope that passed direct post-change proof. Add it as soon as
|
|
30
|
+
any scope passes, even when another scope remains open; name the verified
|
|
31
|
+
scope and evidence in the status reply.
|
|
32
|
+
- `π«` records a distinct action another person must take, including a reporter
|
|
33
|
+
request. Keep the reaction as history after that action is completed,
|
|
34
|
+
answered, or abandoned; the current reply must say whether the action is
|
|
35
|
+
still open or historical.
|
|
36
|
+
- Every owned root needs one current same-actor reply after the latest human
|
|
37
|
+
reply. Reuse it while the disposition and evidence remain current; do not
|
|
38
|
+
send a duplicate progress reply on every sweep. The reply names verified
|
|
39
|
+
scopes, open scopes, human actions and owners, and why either `β
` or `π«` is
|
|
40
|
+
absent. An eye-only root is correct when no scope is verified and no separate
|
|
41
|
+
human action is pending; say whether the next step is this workflow's
|
|
42
|
+
investigation or no further action.
|
|
25
43
|
|
|
26
44
|
## Slack channels and ownership
|
|
27
45
|
|
|
@@ -34,44 +52,93 @@ channel. For a permalink, its channel ID identifies only where the exact linked
|
|
|
34
52
|
root must appear; it does not limit the cutoff or channel scope. For an
|
|
35
53
|
explicitly narrowed sweep, verify that the active request names every selected
|
|
36
54
|
channel, then record its exact text and IDs in the separate scope-confirmation
|
|
37
|
-
file.
|
|
55
|
+
file. A request can select exactly two channels by linking one report in the
|
|
56
|
+
first and directly asking for βthe same inβ the second, without saying βonly.β
|
|
57
|
+
The checker permits one adjacent-transposition typo in that target only when it
|
|
58
|
+
uniquely matches a selected canonical channel; it rejects incidental or quoted
|
|
59
|
+
mentions and prefixes. See [`channel-inventory.md`](references/channel-inventory.md)
|
|
60
|
+
for the scope gate and its confirmation requirements. `#dev-agent-native-feedback`
|
|
61
|
+
is not excluded.
|
|
38
62
|
|
|
39
63
|
In every scoped channel, run the complete bot-inclusive `slack_search_public`
|
|
40
64
|
scan with only the channel filter and that channel's inclusive lower bound.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
65
|
+
Freeze one `windowEndTs` at sweep start and use it for every channel and
|
|
66
|
+
owned-mark search. Messages newer than it belong to the next scheduled sweep;
|
|
67
|
+
never move the boundary to chase arrivals. Exhaust every cursor;
|
|
68
|
+
`slack_read_channel` cannot replace this inventory. Resolve
|
|
69
|
+
each row to its true parent and read the root reactions before opening the thread.
|
|
70
|
+
If another actor owns any workflow mark (`π`, `β
`, or `π«`), or this actor owns
|
|
71
|
+
`:mag:`, apply the held-thread boundary below: do not read the thread, react, or
|
|
72
|
+
reply. Otherwise read the report's full thread and attachments before
|
|
73
|
+
classifying or claiming it. Follow
|
|
44
74
|
[`channel-inventory.md`](references/channel-inventory.md) for exact query
|
|
45
|
-
arguments, raw-page receipts, cap recovery, root classification,
|
|
46
|
-
searches for this actor's `π`, `β
`, and `π«`,
|
|
75
|
+
arguments, raw-page receipts, cap recovery, root classification, fixed-window
|
|
76
|
+
source scans, bounded ownership searches for this actor's `π`, `β
`, and `π«`,
|
|
77
|
+
and checker requirements. Owned-mark searches use Slack's exact syntax
|
|
78
|
+
`hasmy::eyes:`, `hasmy::white_check_mark:`, or `hasmy::ticket:` with the channel
|
|
79
|
+
filter and the same inclusive `after` and `before` as that channel's source
|
|
80
|
+
scan. Do not widen a finite catch-up request into an all-history audit. A root
|
|
81
|
+
older than `after` is in scope only when an in-window reply links to it. A
|
|
82
|
+
missing trailing colon is not a valid ownership query.
|
|
47
83
|
|
|
48
84
|
Only the invoking Slack actor's root marks are owned here. Another task's eye
|
|
49
85
|
plus its current open status remains theirs; an explicit handoff naming this
|
|
50
86
|
task and scope is required to transfer investigation. An eye is a permanent
|
|
51
87
|
claim, not proof of open or completed work. A mark on a reply never claims or
|
|
52
|
-
checks off its parent. Before exit, reconcile every
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
88
|
+
checks off its parent. Before exit, reconcile every in-window root carrying
|
|
89
|
+
this actor's `π`, `β
`, or `π«` found by the bounded searches. Also reconcile an
|
|
90
|
+
older root when an in-window reply links to it. For every owned root, compare
|
|
91
|
+
the latest human reply, current status, verified scopes, open scopes, human
|
|
92
|
+
actions, and exact root reactions.
|
|
93
|
+
Never let a high eye count hide a verified scope without `β
` or a missing
|
|
94
|
+
current status reply.
|
|
95
|
+
|
|
96
|
+
**Held-thread boundary:** A direct root reaction read showing another person's
|
|
97
|
+
`π`, `β
`, or `π«` means the thread belongs to that workflow; this actor's
|
|
98
|
+
`:mag:` means this actor opted out. Record the exact root, reaction owners, and
|
|
99
|
+
one reason (`foreign_workflow_mark` or `mag_opt_out`) in `ownershipSkip`, with
|
|
100
|
+
`Skipped` disposition. When this actor owns both `:mag:` and a workflow mark,
|
|
101
|
+
use `mag_opt_out` and preserve the exact root reaction-owner record as history.
|
|
102
|
+
Do not open/read that thread, inspect reply reactions, add or remove reactions,
|
|
103
|
+
or post a reply. Apply the same skip to channel reply
|
|
104
|
+
rows linked to that root. A linked pre-window root without source text remains
|
|
105
|
+
`unclassified`; do not infer its original report from the reply. This explicit
|
|
106
|
+
exception keeps ownership boundaries intact while allowing the rest of the
|
|
107
|
+
window to be reconciled. A foreign `π` without current status is still held;
|
|
108
|
+
do not read it to decide whether its owner is active.
|
|
57
109
|
|
|
58
110
|
Only Steve's `:mag:` and `:yes-party:` count (`U0GCV21HC`). When Steve invokes,
|
|
59
|
-
exhaust `hasmy::mag:` and `hasmy::yes-party:` searches
|
|
60
|
-
|
|
61
|
-
|
|
111
|
+
exhaust `hasmy::mag:` and `hasmy::yes-party:` searches within each channel's
|
|
112
|
+
same inclusive cutoff; otherwise inspect root reactions in the requested
|
|
113
|
+
window. `:mag:` opts out and wins over `:yes-party:`. The latter authorizes only
|
|
114
|
+
an otherwise review-only item; it never overrides an assignment or another
|
|
62
115
|
task's claim.
|
|
63
116
|
|
|
64
117
|
## Phase 0: claim and reconcile
|
|
65
118
|
|
|
66
119
|
Resolve known duplicates before claiming. Check ownership, then add and read
|
|
67
120
|
back this task's root `π` before investigating an eligible unowned report.
|
|
68
|
-
Reconcile
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
121
|
+
Reconcile only owned roots inside this invocation's fixed window and older
|
|
122
|
+
roots explicitly linked by an in-window reply. Never expand a finite sweep to
|
|
123
|
+
all historical roots just because this actor owns an old mark; widen the range
|
|
124
|
+
only when the invocation explicitly requests it or hands off exact roots. Finish
|
|
125
|
+
this bounded reconciliation before discovering new questions. Keep one
|
|
126
|
+
concise canonical status by the same actor after the latest human message; read
|
|
127
|
+
back the visible reply and root reactions after each write. Use
|
|
72
128
|
[`slack-reaction-replies.md`](references/slack-reaction-replies.md) for exact
|
|
73
129
|
status and reaction rules.
|
|
74
130
|
|
|
131
|
+
**Bounded exit gate:** enumerate the complete candidate set from the fixed
|
|
132
|
+
source window, the three matching owned-mark searches, and older roots linked
|
|
133
|
+
by in-window replies. For every unheld owned root, compare the latest human
|
|
134
|
+
message, current status reply, verified scopes, open scopes, and root marks.
|
|
135
|
+
Add and read back `β
` for each newly verified scope and `π«` for each distinct
|
|
136
|
+
pending human action; the status reply must follow the latest human message and
|
|
137
|
+
name current evidence, remaining work, and owners. An `π` with a verified
|
|
138
|
+
scope missing `β
`, a pending human action missing `π«`, or no current status is
|
|
139
|
+
unfinished. Finish the complete bounded set once, then stop; do not chase
|
|
140
|
+
unrelated historical marks.
|
|
141
|
+
|
|
75
142
|
Split reports into distinct scopes. Add root `β
` as soon as any named scope
|
|
76
143
|
passes direct post-change proof, even while its PR is open; say **Verified
|
|
77
144
|
locally** and that merge is pending. Use **Fixed** only after merge and direct
|
|
@@ -97,11 +164,14 @@ action and owner. Use **Skipped** only for non-defects.
|
|
|
97
164
|
|
|
98
165
|
Phase 0 handles new human replies on owned roots first; never hide a newer
|
|
99
166
|
reporter reply behind a mark. Then find prior unanswered questions using the
|
|
100
|
-
exact bot disclosure and the saved channel reply cursor
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
167
|
+
exact bot disclosure and the saved channel reply cursor, bounded by this
|
|
168
|
+
invocation's fixed window. On a first run, use the same default five-day window;
|
|
169
|
+
never scan all available history to initialize the cursor. Exhaust pages, use a
|
|
170
|
+
one-day overlap for date-only cursors, resolve every hit to its parent, and read
|
|
171
|
+
the full thread after checking reactions. An older root is eligible only when
|
|
172
|
+
an in-window reply links to it. Follow
|
|
173
|
+
[`slack-reaction-replies.md`](references/slack-reaction-replies.md) for exact
|
|
174
|
+
searches, legacy identity handling, and answer criteria.
|
|
105
175
|
|
|
106
176
|
A valid answer is a human post after the question, without this workflow's
|
|
107
177
|
disclosure, that addresses the question. Rebuild the evidence and attempt the
|
|
@@ -316,15 +386,17 @@ send one concise disposition covering done, remaining, and next action/owner.
|
|
|
316
386
|
Do not reply again to announce merge, publication, or live beta; answer direct
|
|
317
387
|
reporter follow-ups. End Slack replies with `this was sent from a bot.`.
|
|
318
388
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
actor
|
|
323
|
-
reply
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
389
|
+
Reporter-facing replies are one or two sentences: the change or question, its limit, and the next step. Do not explain workflow mechanics, ledgers, or external tracker tickets. Never send **Open**/**pending** or a symptom recap. Ask for reporter input only when it changes the next step; never request supplied evidence or internal access. Keep hashes, branches, CI, publisher, and run details in the recap.
|
|
390
|
+
|
|
391
|
+
Every root this actor marks with `π`, `β
`, or `π«` also needs the current
|
|
392
|
+
same-actor status reply required by the Slack reaction reference. One concise
|
|
393
|
+
reply may serve both purposes when it answers the reporter and records the
|
|
394
|
+
current disposition, verified/open scopes, owner/action, and any reason a mark
|
|
395
|
+
is absent. This status requirement takes precedence over the reporter-facing
|
|
396
|
+
brevity rule only for those facts; do not explain ledger mechanics or external
|
|
397
|
+
tracker tickets. A Slack `π«` reaction tracks a distinct human action, not an
|
|
398
|
+
external ticket, and remains as history after the action closes. Never imply
|
|
399
|
+
that an external ticket was created or assigned.
|
|
328
400
|
|
|
329
401
|
Keep publisher and beta checks in the internal recap after the disposition;
|
|
330
402
|
they do not trigger a second reporter reply.
|
package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md
CHANGED
|
@@ -3,15 +3,27 @@
|
|
|
3
3
|
Use this procedure before investigating, claiming, or using a CI rollup in
|
|
4
4
|
place of Slack source messages.
|
|
5
5
|
|
|
6
|
+
At the start of a sweep, capture one Slack timestamp as `windowEndTs`. Use it
|
|
7
|
+
as the inclusive `before` argument on the source scan and all three `hasmy`
|
|
8
|
+
ownership searches in every scoped channel. Use the same inclusive `after` on
|
|
9
|
+
the source scan and ownership searches. Record the bounds in `scanQuery` and
|
|
10
|
+
each owned search's `query`. Keep `after` fixed through the sweep. Keep the
|
|
11
|
+
exact upper bound for the whole sweep; page-cap recovery slices may narrow only
|
|
12
|
+
`before` using the existing one-microsecond boundary rule. Messages newer than
|
|
13
|
+
`windowEndTs` belong to the next scheduled sweep. Never advance either bound to
|
|
14
|
+
chase arrivals or expand a finite catch-up request into an all-history audit.
|
|
15
|
+
|
|
6
16
|
- For the exhaustive channel source scan, use `slack_search_public` with only
|
|
7
|
-
`filters=in:<#CHANNEL>`, `after=<channel cutoff>`,
|
|
17
|
+
`filters=in:<#CHANNEL>`, `after=<channel cutoff>`,
|
|
18
|
+
`before=<windowEndTs>`, `keywords=[]`, an empty
|
|
8
19
|
`natural_language_query`, `include_bots=true`, `include_context=false`,
|
|
9
20
|
`content_types=messages`, `limit=20`, `sort=timestamp`, `sort_dir=desc`, and
|
|
10
21
|
`response_format=detailed`. Do not add lexical, semantic, date, author, or
|
|
11
22
|
reaction filters: they silently hide reports. Record these exact arguments
|
|
12
23
|
under that channel's `scanQuery`; the inventory checker rejects a missing or
|
|
13
|
-
narrowed query. `after`
|
|
14
|
-
cutoff
|
|
24
|
+
narrowed query. `after` and `before` are inclusive and must equal that
|
|
25
|
+
channel's effective lower cutoff and the sweep's fixed upper bound. Follow
|
|
26
|
+
every `next_cursor` newest-first to Slack exhaustion, even
|
|
15
27
|
after reaching the cutoff, because later pages can contain replies to older
|
|
16
28
|
roots. Page and
|
|
17
29
|
source-row timestamps must descend across the full chain. This is separate
|
|
@@ -50,9 +62,18 @@ place of Slack source messages.
|
|
|
50
62
|
`ts >= effectiveCutoffTs`, and record the exact `oldest` in `oldestQuery`.
|
|
51
63
|
- Record `scope.channelIds` as the exact IDs requested and scanned. The default
|
|
52
64
|
sweep lists all three default feedback channels. For an explicitly narrowed
|
|
53
|
-
invocation, inspect the active user request itself
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
invocation, inspect the active user request itself. It can name the exact
|
|
66
|
+
channel set with an explicit limit such as βonlyβ and exact IDs or
|
|
67
|
+
`#channel-name`s. It can also select exactly two channels by linking one
|
|
68
|
+
report permalink in the first channel and directly asking for βthe same in
|
|
69
|
+
channel-nameβ (with or without `#`) in the second; that direct linked-report
|
|
70
|
+
form selects exactly those two channels and does not need an exclusivity
|
|
71
|
+
word. It requires exactly one linked root and one direct βsame inβ target. In
|
|
72
|
+
that clause only, accept a single adjacent transposition in the channel name
|
|
73
|
+
only when it uniquely resolves to one canonical channel in the requested
|
|
74
|
+
set. Do not infer scope from incidental or quoted channel mentions or a
|
|
75
|
+
channel-name prefix. A permalink or time anchor by itself does not narrow
|
|
76
|
+
channel scope. Ask the user if the
|
|
56
77
|
requested channels are unclear. Store the exact instruction in
|
|
57
78
|
`scope.userRequest` and `scope.narrowingJudgment`, then create a separate
|
|
58
79
|
`.tmp/feedback-scope-confirmation.json` from that active request with
|
|
@@ -85,10 +106,12 @@ place of Slack source messages.
|
|
|
85
106
|
`administrative` decision, and a human rationale tied to that text. This is
|
|
86
107
|
an attributed human triage judgment; the checker verifies its presence and
|
|
87
108
|
source-text linkage but cannot prove the interpretation is correct.
|
|
88
|
-
For every classified root, including administrative posts, capture a
|
|
109
|
+
For every unheld classified root, including administrative posts, capture a
|
|
89
110
|
complete thread read and make `sourceText` exactly match its `rootText`.
|
|
90
|
-
|
|
91
|
-
|
|
111
|
+
A held root keeps the exact channel-scan `sourceText` and direct reaction
|
|
112
|
+
evidence but has no thread-derived fields. Search output can confuse
|
|
113
|
+
user-authored `Files:` or `Reactions:` lines with connector metadata, so do
|
|
114
|
+
not classify from a truncated search excerpt.
|
|
92
115
|
For a canonical Slack message permalink, inspect its `thread_ts` query value:
|
|
93
116
|
if it differs from the message's `ts`, the message is a reply and that value
|
|
94
117
|
is its root. A self-valued `thread_ts` or a canonical root permalink without
|
|
@@ -194,9 +217,9 @@ place of Slack source messages.
|
|
|
194
217
|
root message.
|
|
195
218
|
Read and capture a complete, oldest-first `threadSnapshot` after the final
|
|
196
219
|
channel page for every in-scope classified root, including administrative
|
|
197
|
-
posts, unmarked roots, and roots with no replies
|
|
198
|
-
|
|
199
|
-
`sourceText`.
|
|
220
|
+
posts, unmarked roots, and roots with no replies, except roots held by the
|
|
221
|
+
reaction ownership boundary below. The checker rejects a classified root
|
|
222
|
+
without this read or with `rootText` that differs from its `sourceText`.
|
|
200
223
|
Supplemental roots must strictly predate the oldest `sourceTimestamps` entry
|
|
201
224
|
across every scanned page, as well as `cutoffTs`; a root inside the scanned
|
|
202
225
|
source range must have its own source-manifest row even when it predates the
|
|
@@ -205,8 +228,8 @@ place of Slack source messages.
|
|
|
205
228
|
`ts === threadParentTs` and must not be duplicated in `threadRoots`. A
|
|
206
229
|
supplemental root exists to resolve an in-window reply;
|
|
207
230
|
its presence does not make the older report a new in-scope claim. Read its
|
|
208
|
-
exact root reactions
|
|
209
|
-
|
|
231
|
+
exact root reactions, then apply the ownership gate before opening the thread.
|
|
232
|
+
Do not add `π`, `β
`, or `π«`, or post a status, just because
|
|
210
233
|
an unowned older root appears as context. If this actor already owns a mark
|
|
211
234
|
on that older root, reconcile its current status and scopes as usual; record
|
|
212
235
|
another actor's marks as ownership evidence and leave them untouched. Their
|
|
@@ -214,29 +237,53 @@ place of Slack source messages.
|
|
|
214
237
|
shows an open disposition; a later closed status makes that eye historical.
|
|
215
238
|
Keep
|
|
216
239
|
the root disposition and any open scope in the audit row without claiming it.
|
|
217
|
-
|
|
218
|
-
`threadSnapshot
|
|
219
|
-
|
|
220
|
-
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
`
|
|
224
|
-
`
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
the
|
|
240
|
+
For an unheld supplemental root, the inventory checker still requires a
|
|
241
|
+
complete, oldest-first `threadSnapshot`, so a reply cannot predate or
|
|
242
|
+
otherwise contradict its reported root.
|
|
243
|
+
- **Held thread:** If the exact root reaction read shows another actor owns any
|
|
244
|
+
workflow mark (`π`, `β
`, or `π«`), or this actor owns `:mag:`, do not open or
|
|
245
|
+
read the thread, inspect reply reactions, react, or reply. Record an
|
|
246
|
+
`ownershipSkip` with the root timestamp and `foreign_workflow_mark` or
|
|
247
|
+
`mag_opt_out`; use `Skipped` and leave thread-derived fields empty. If this
|
|
248
|
+
actor also owns a workflow mark, use `mag_opt_out` and preserve the exact
|
|
249
|
+
direct root reaction-owner record as history. The checker treats it as held
|
|
250
|
+
and requires no thread snapshot or status. Mark every
|
|
251
|
+
channel reply linked to that root with the same skip reference. The checker
|
|
252
|
+
requires direct root reaction evidence and the matching skip reason, but no
|
|
253
|
+
full-thread snapshot. For a linked pre-window root without source text, use
|
|
254
|
+
`unclassified`; do not guess from its in-window reply. This boundary also
|
|
255
|
+
applies when the other actor's eye has no visible status reply: ownership is
|
|
256
|
+
not permission to inspect. The direct root-reaction read must still be fresh
|
|
257
|
+
and after the final source page; it is the only read allowed for a held root.
|
|
258
|
+
Preserve the source's exact file ID, name, and MIME type when its raw search
|
|
259
|
+
result includes `Files:`. If that result omits file metadata, leave the held
|
|
260
|
+
root's `files` field absent to represent unknown; do not record `[]`. For an
|
|
261
|
+
unheld root, use the full thread read to record files and require the source
|
|
262
|
+
row and snapshot to agree.
|
|
263
|
+
- After each bounded channel scan, run three separate bounded ownership
|
|
264
|
+
searches for this actor's `π`, `β
`, and `π«` with `slack_search_public`. Each
|
|
265
|
+
query uses only `in:<#CHANNEL> hasmy::EMOJI:` plus the same inclusive `after`
|
|
266
|
+
and `before` as the source scan. These searches cover only this invocation's
|
|
267
|
+
finite window; do not search unrelated channel history. An older root is in
|
|
268
|
+
scope only when an in-window reply links to it. Resolve that reply's true
|
|
269
|
+
parent, read the older root's exact reactions, and apply the held-thread gate
|
|
270
|
+
before opening it. Reconcile every candidate in the window and each linked
|
|
271
|
+
older root; unheld roots need exact reaction and full-thread evidence in the
|
|
272
|
+
source or supplemental-root audit. A candidate missing either audit is
|
|
273
|
+
unresolved, not outside scope.
|
|
274
|
+
If Slack caps a cursor before exhaustion, preserve that capped page and
|
|
275
|
+
record the exact `page_limit_exceeded` response in that search's
|
|
229
276
|
`pageLimitRecoveries[]`, including its failed cursor and request args, raw
|
|
230
277
|
response, read time, and the capped page's oldest result as `boundaryTs`.
|
|
231
|
-
Restart the same
|
|
232
|
-
`before` exactly one microsecond below that boundary. Keep
|
|
233
|
-
every page in the restarted cursor slice and in each raw request wrapper
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
278
|
+
Restart the same `hasmy` query at `cursor: null` with the same fixed `after`
|
|
279
|
+
and a `before` exactly one microsecond below that boundary. Keep both bounds
|
|
280
|
+
on every page in the restarted cursor slice and in each raw request wrapper.
|
|
281
|
+
Follow the restarted slice to exhaustion and repeat this recovery for every
|
|
282
|
+
later cap. The checker proves each failed cursor against exactly one
|
|
283
|
+
restarted slice, checks the boundary and read order, and requires explicit
|
|
284
|
+
exhaustion. If Slack does not let you recover a capped tail, report the
|
|
285
|
+
bounded ownership search as incomplete; do not claim every in-window owned
|
|
286
|
+
mark was reconciled.
|
|
240
287
|
Record each exact query and page in `ownedMarkSearches`; save raw wrappers
|
|
241
288
|
named `owned-marks-{channelName}-{eyes|white_check_mark|ticket}-00.json` and
|
|
242
289
|
continue numbering for each cursor page. Each wrapper preserves exact
|
|
@@ -252,16 +299,19 @@ place of Slack source messages.
|
|
|
252
299
|
evidence; if the exact read fails or is incomplete, leave ownership
|
|
253
300
|
unresolved rather than treating the query as confirmation. A result with
|
|
254
301
|
`ts !== root` is reply-level evidence: resolve and preserve its parent, but
|
|
255
|
-
never count it as a root checkoff.
|
|
256
|
-
reply read-back in its complete thread snapshot; if that
|
|
257
|
-
cannot be read back, report reply-level reconciliation as
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
302
|
+
never count it as a root checkoff. For an unheld root, verify reply reactions
|
|
303
|
+
from the exact reply read-back in its complete thread snapshot; if that
|
|
304
|
+
historical reply cannot be read back, report reply-level reconciliation as
|
|
305
|
+
incomplete. For a held root, preserve the reply parent and matching skip
|
|
306
|
+
reason without opening the thread.
|
|
307
|
+
Deduplicate confirmed roots across the three searches. Every in-window root
|
|
308
|
+
candidate must appear in the source pages. An older root linked by an
|
|
309
|
+
in-window reply belongs in `threadRoots` and `threadRootAudits`. If a bounded
|
|
310
|
+
search hit has no matching source row or linked supplemental root, rerun the
|
|
311
|
+
source scan and include the missing evidence; do not invent an audit row.
|
|
312
|
+
Reconcile each unheld discovered root's latest human message, status reply,
|
|
313
|
+
scopes, and exact current reaction state. Read its full thread after the final
|
|
314
|
+
ownership-search page and preserve every raw
|
|
265
315
|
`slack_read_thread` page under `thread-{channelName}-{rootTs}-00.json` and
|
|
266
316
|
contiguous page numbers. Each wrapper records exact request `args`,
|
|
267
317
|
requested `cursor`, raw response, and `readAt`; the raw response must
|
|
@@ -387,9 +437,13 @@ place of Slack source messages.
|
|
|
387
437
|
and every source `{ ts, root }` row with the reviewed inventory and raw Slack
|
|
388
438
|
responses. If it finds a mismatch,
|
|
389
439
|
rebuild the inventory from the captured Slack pages and rerun the check; never
|
|
390
|
-
edit the receipt to fit the inventory.
|
|
391
|
-
|
|
392
|
-
|
|
440
|
+
edit the receipt to fit the inventory. Source and ownership-search pages are
|
|
441
|
+
immutable evidence for the fixed `after`/`before` interval; their age does not
|
|
442
|
+
restart the sweep. The 15-minute freshness window applies to current root and
|
|
443
|
+
reply reaction reads and full-thread snapshots. If one expires, reread only
|
|
444
|
+
that exact state. After one targeted retry, if a required current-state read
|
|
445
|
+
is still stale or unavailable, mark the inventory incomplete and stop; do
|
|
446
|
+
not restart the channel-wide search or loop.
|
|
393
447
|
It rejects any root mark this actor owns without a current same-actor
|
|
394
448
|
status reply, a
|
|
395
449
|
assigned-human handoff without that person's explicit acceptance, an
|
|
@@ -434,19 +488,18 @@ verified disposition may retain the eye as history. Never remove or clean up a
|
|
|
434
488
|
reaction. Slack thread replies appear under the root's reply count, not as
|
|
435
489
|
separate channel posts; do not broadcast routine status replies.
|
|
436
490
|
|
|
437
|
-
After
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
before checking the inventory. Only a complete fresh pass can certify coverage.
|
|
491
|
+
After a long investigation, CI/deploy wait, or handoff, do one final exhaustive
|
|
492
|
+
pass of the exact original channel-wide query for every scoped channel, using
|
|
493
|
+
the same recorded `scanQuery.after` and `scanQuery.before`. Replace the saved
|
|
494
|
+
page responses, timestamps, source manifests, and source rows; never append a
|
|
495
|
+
delta or refresh `readAt` without rereading the page. This is one bounded
|
|
496
|
+
reconciliation pass, not a moving high-water mark. Resolve newly found replies
|
|
497
|
+
to their actual roots and reconcile them inside the fixed interval. Then reread
|
|
498
|
+
current root reactions and full threads for marked roots after the final source
|
|
499
|
+
and ownership-search pages. If an exact current-state read expires, reread that
|
|
500
|
+
target once. If it still cannot pass freshness, mark coverage incomplete and
|
|
501
|
+
stop; do not restart the global scan. Activity newer than `windowEndTs` is for
|
|
502
|
+
the next scheduled sweep.
|
|
450
503
|
|
|
451
504
|
Channel history does not include the contents of existing thread replies. In
|
|
452
505
|
that final pass, also enumerate every distinct root thread carrying this
|
|
@@ -492,21 +545,22 @@ read time as `reactionReadAt`; when this sweep writes a reaction, record
|
|
|
492
545
|
also requires each owned root reaction read and the full-thread reaction reads
|
|
493
546
|
to follow the final channel page.
|
|
494
547
|
|
|
495
|
-
The
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
548
|
+
The inventory checker requires source pages to use one recorded inclusive
|
|
549
|
+
`after`/`before` window and ownership-census pages to use the fixed `before`
|
|
550
|
+
upper bound with no `after`. Both page chains must remain in cursor order and
|
|
551
|
+
have valid local ISO read times. Their age does not invalidate those fixed
|
|
552
|
+
bounds. Current root and reply reaction reads and full-thread snapshots must be
|
|
553
|
+
within 15 minutes, allow at most one minute of local clock skew, and follow the
|
|
554
|
+
final source and ownership-search pages. Refresh only a stale current-state
|
|
555
|
+
target; if one targeted reread is still stale or unavailable, mark coverage
|
|
556
|
+
incomplete and stop instead of repeating the full sweep.
|
|
503
557
|
|
|
504
558
|
The inventory checker requires a complete `threadSnapshot` for every in-scope
|
|
505
|
-
classified root
|
|
506
|
-
|
|
507
|
-
raw thread page cursor exhaustion, Slack's reply count, exact source
|
|
508
|
-
attachments, and snapshot order, and rejects a newer human or sweep reply
|
|
509
|
-
the recorded status. A failed check means the sweep is not reconciled.
|
|
559
|
+
classified root and every supplemental root included to resolve an in-scope
|
|
560
|
+
reply, except roots recorded under the held-thread boundary. For unheld roots it
|
|
561
|
+
checks raw thread page cursor exhaustion, Slack's reply count, exact source
|
|
562
|
+
text, attachments, and snapshot order, and rejects a newer human or sweep reply
|
|
563
|
+
than the recorded status. A failed check means the sweep is not reconciled.
|
|
510
564
|
|
|
511
565
|
A grouped CI report or attachment is a discovery index, never a replacement for
|
|
512
566
|
the channel-message inventory.
|
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Use the connected Slack integration for every Slack read and write. Never use a browser, screenshots, or UI automation to operate Slack.
|
|
4
4
|
|
|
5
|
-
At sweep exit, reconcile every report root in the scoped inventory that
|
|
6
|
-
this task's `π`, `β
`, or `π«`, including marks left by earlier runs.
|
|
5
|
+
At sweep exit, reconcile every unheld report root in the scoped inventory that
|
|
6
|
+
has this task's `π`, `β
`, or `π«`, including marks left by earlier runs. A
|
|
7
|
+
root is held when a direct reaction read shows another actor owns any workflow
|
|
8
|
+
mark or this actor owns `:mag:`. For held roots, record the root and safe-skip
|
|
9
|
+
reason, then stop: do not open the thread, inspect reply reactions, write any
|
|
10
|
+
reaction, or post a status. When this actor owns both `:mag:` and a workflow
|
|
11
|
+
mark, use `mag_opt_out` and preserve the exact direct root reaction-owner
|
|
12
|
+
record as history; the root remains held without a thread read or status reply.
|
|
13
|
+
Capture
|
|
7
14
|
the exact Slack actor ID used by the connected tool at sweep start. A mark is
|
|
8
15
|
owned by this task only when its reaction owner ID matches that actor ID. Each
|
|
9
|
-
owned root needs a current disposition and a matching status reply by
|
|
10
|
-
actor under that same parent, even when the root has only `β
` or `π«`. A
|
|
16
|
+
unheld owned root needs a current disposition and a matching status reply by
|
|
17
|
+
that same actor under that same parent, even when the root has only `β
` or `π«`. A
|
|
11
18
|
same-run fix gets its final reply after verification; continuing work gets a
|
|
12
19
|
concrete progress reply. An earlier generic βtaking a lookβ does not satisfy
|
|
13
20
|
this update. If an existing reply already names the exact canonical disposition
|
|
@@ -30,6 +37,23 @@ includes human handoffs, the status reply must name each handoff's recorded
|
|
|
30
37
|
owner and action; include its scope when the report context does not make it
|
|
31
38
|
clear.
|
|
32
39
|
|
|
40
|
+
Interpret the three root reactions independently from the current disposition:
|
|
41
|
+
|
|
42
|
+
- `π` is a permanent claim/history mark, not an open/closed indicator.
|
|
43
|
+
- `β
` is permanent history for named scopes that passed direct post-change
|
|
44
|
+
proof. Add it as soon as any scope passes; do not wait for other scopes or
|
|
45
|
+
merge. Keep it if later evidence changes the scope's status, and explain the
|
|
46
|
+
historical mark in the current reply and inventory.
|
|
47
|
+
- `π«` is permanent history for a distinct human action, including an
|
|
48
|
+
unassigned team action or reporter request. Keep it after completion,
|
|
49
|
+
answer, or four-day abandonment; label it historical in the current reply
|
|
50
|
+
and inventory when it no longer blocks progress.
|
|
51
|
+
|
|
52
|
+
The current status reply is the source for whether work remains open. When a
|
|
53
|
+
root has only `π`, say that no scope has passed the proof bar for `β
`, whether
|
|
54
|
+
the next step belongs to this workflow, and why no separate human action needs
|
|
55
|
+
`π«`. Reuse a current reply rather than posting again on every sweep.
|
|
56
|
+
|
|
33
57
|
An evidence-only addendum or a correction is not a current status. When your
|
|
34
58
|
newest own reply is one of those, edit that reply into the full canonical
|
|
35
59
|
disposition when possible; otherwise send one final status after the latest
|
|
@@ -101,10 +125,13 @@ slack_search: "this was sent from a bot." in:<#CHANNEL>
|
|
|
101
125
|
sort=timestamp sort_dir=asc include_context=true max_context_length=300
|
|
102
126
|
```
|
|
103
127
|
|
|
104
|
-
Also scan channel messages from the saved reply cursor
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
128
|
+
Also scan channel messages from the saved reply cursor within the current
|
|
129
|
+
invocation's fixed window; on the first run, use the default five-day window,
|
|
130
|
+
not all available history. Since `after:` is date-only, start one day before
|
|
131
|
+
the later of the saved cursor and window start, exhaust pages, resolve hits to
|
|
132
|
+
their root, and advance the cursor only through processed messages. An older
|
|
133
|
+
root is eligible only when an in-window reply links to it. Read inherited
|
|
134
|
+
threads carrying any of this actor's root marks (`π`, `β
`,
|
|
108
135
|
or `π«`): a checkmark closes only its verified scope, not a newer reporter
|
|
109
136
|
answer or another open scope. Do not reply or react on another actor's root when work is handed off for investigation; that handoff permits local investigation only. A separate explicit authorization is required to post a status or reporter reply there.
|
|
110
137
|
|
|
@@ -130,9 +157,10 @@ human/team actions, including actions with no named owner yet. The eye alone
|
|
|
130
157
|
does not mean work remains open. One root `β
` covers every verified scope
|
|
131
158
|
listed in `fixedScopes[]`; one root `π«` covers every action listed in
|
|
132
159
|
`handoffs[]`, including unassigned, accepted, and completed actions. Completion
|
|
133
|
-
evidence changes its status, not the historical `π«` reaction. For every
|
|
134
|
-
carrying any of this actor's marks, post or reuse a current status
|
|
135
|
-
unclaimed items and another actor's marks
|
|
160
|
+
evidence changes its status, not the historical `π«` reaction. For every
|
|
161
|
+
unheld root carrying any of this actor's marks, post or reuse a current status
|
|
162
|
+
in that root's thread; unclaimed items, held roots, and another actor's marks
|
|
163
|
+
are not ours to reply to. Reconcile
|
|
136
164
|
each report as one unit: send or verify its current same-thread status reply,
|
|
137
165
|
then immediately update and read back each applicable root reaction before
|
|
138
166
|
advancing to the next report. Add `β
` as soon as any reported scope passes the
|
|
@@ -95,9 +95,9 @@ MCP clients see no `outputSchema` by default. Set `mcpOutputSchema: true` (requi
|
|
|
95
95
|
|
|
96
96
|
`authorize` decides whether the caller may run the action at all. It wraps
|
|
97
97
|
`run`, so it holds at **all six dispatch sites** β agent tool, HTTP, frontend
|
|
98
|
-
hook, MCP, A2A, CLI
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
hook, MCP, A2A, CLI. Use `authorize` for "not everyone may do this"; use
|
|
99
|
+
`needsApproval` to ask a human to bless one call a permitted caller is already
|
|
100
|
+
allowed to make.
|
|
101
101
|
|
|
102
102
|
```ts
|
|
103
103
|
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
@@ -140,4 +140,6 @@ export default defineAction({
|
|
|
140
140
|
|
|
141
141
|
When the gate is truthy and the call isn't yet approved, the loop emits an `approval_required` event and **stops the turn β `run()` never executes**. A predicate gates conditionally (e.g. only external recipients) and **fails closed**: a throw is treated as "approval required". It receives its own copy of the prepared snapshot of the validated arguments, defaults applied, and the approval binds to the snapshot's hash, so an approved call runs only with the arguments that were approved (a Date binds by its time). The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's `approvalKey`, and only then does the action run.
|
|
142
142
|
|
|
143
|
+
Approval is given in the app, so HTTP never grants it. The HTTP action route and the generated Workers entry run a gated call only for the proven app UI (a frontend call from the signed-in user, same origin, holding the short-lived UI capability; `isProvenUiRequest`, the proof `uiOnly` uses) or the app's MCP directory widget. Every other HTTP caller (bearer or API key, MCP OAuth token, org service token, A2A, extension iframe, mobile app) gets `409 approval_required`, and a service identity can never approve. The shared client presents the capability with every write from a signed-in session (minted once per user, reused for nine minutes, never for reads or public pages), so a gated button works on its first request. A call without proof gets `403 ui_capability_required`; the client then re-mints and retries once, which is only the fallback for an expired or rejected capability. Every surface evaluates the gate through `preparedCallNeedsApproval`, so a throwing predicate asks there too. A caller that must run unattended needs a different action, never a bypass of the gate.
|
|
144
|
+
|
|
143
145
|
**Keep approvals rare** β the default is off and almost every action should leave it off. The canonical example is Mail's `send-email` (`needsApproval: true`). See the `security` skill and the Human Approval doc.
|