Skip to content

feat(activity): attribute AI tool creates and edits to the tool actor (Macro AI) - #6050

Merged
synoet merged 7 commits into
mainfrom
synoet/feat-activity-ai-tool-attribution-d5e6
Sep 3, 2026
Merged

synoet merged 7 commits into
mainfrom
synoet/feat-activity-ai-tool-attribution-d5e6

Conversation

@synoet

@synoet synoet commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Middle of the activity-attribution stack. Parent #6051 has merged; this PR is now based on main.

Stack

  1. feat(activity): attribute EditDocument collab edits to the AI bot #6051 — EditDocument collab actor (merged)
  2. feat(activity): attribute AI tool creates and edits to the tool actor (Macro AI) #6050 (this PR) — AI tool creates/edits → tool actor (Macro AI by default)
  3. fix(activity): attribute signup defaults and support channel to system #6049 — Signup defaults + support channel → SYSTEM

Supersedes #5841.

Why

AI tools that create or edit entities minted a user receipt or omitted attribution. Ingest then recorded a silent user write, or dropped the event. The feed should show the AI acting for the requesting user.

How identity flows

Tools never name a bot. Each toolset context (DocumentToolContext, PropertiesToolContext, ProjectToolContext, ChannelToolContext) carries actor: BotId, defaulting to MACRO_AI_BOT_ID, with with_actor(BotId). ai_tools::ToolServiceContext::with_actor sets all four at once, so a host running a specific agent sets the identity once per session and every mutating tool follows. (ai_toolset::RequestContext is frozen, so the actor lives on the service contexts rather than the request.)

Each domain then receives the actor through its own carrier:

  • bot receipt (generate_bot_entity_access_receipt(actor, BotAccessScope::user(user), ..)): RenameDocument, SetEntityProperty, BulkSetEntityPropertyOptions, MoveToProject for documents. The domain maps EntityAccessAuth::Bot to actor/on_behalf_of on the event.
  • create metadata (DocumentToolContext::attribution(user) → Attribution::delegated(actor, user)): CreateDocument, because the create path discards its receipt.
  • collab JWT actor claim: EditDocument (carrier from feat(activity): attribute EditDocument collab edits to the AI bot #6051).
  • Sender::new_from_bot(actor): SendChannelMessage.

BotAccessScope::user(user_id) is the constructor for callers that know only the acting user (AI tool requests carry no org context).

Coverage

Attributed to the actor on behalf of the user: CreateDocument, EditDocument, RenameDocument, SetEntityProperty, BulkSetEntityPropertyOptions, MoveToProject (documents), SendChannelMessage.

Still attributed to the user directly, because the domain does not yet accept a bot principal (projects drops EntityAccessAuth::Bot, channels' user_sender(&receipt)? rejects it, email uses the acting user): MoveToProject for chat/email/project (MovePrincipal::User), CreateProject, CreateChannel, RenameChannel, ManageChannelParticipants, SendEmail, UpdateThreadLabels, SetSenderPolicy, CreateTag/EditTag/DeleteTag. Each of those becomes a one-line switch to the context actor once its domain accepts bot receipts; that is follow-up work per domain.

No ActivitySource at all (out of scope for activity): calendar, reminders, import, notifications, bots tools. The import job's ToolEntityCreator keeps MACRO_AI_BOT_ID because it runs detached from the requesting agent's session.

Also in this PR

  • DocumentUpdatedMetadata and DocumentDeletedMetadata add optional actor and on_behalf_of. published_document_actors fills them from a user-scoped bot receipt. Ingest uses mutation_attribution so those events become Edited / Deleted instead of Ignore.
  • SetEntityProperty parent/subtask access and assignee notify use acting_user_id() so a user-scoped bot receipt can link tasks and notify.
  • EditDocument keeps a user receipt for the access check; attribution rides the JWT actor.
  • Regenerated storage OpenAPI / SDK types for the new Updated/Deleted fields.

Tests

  • documents: edit token carries the context actor (with_actor) and defaults to Macro AI; attribution(user) is delegated from the context actor.
  • channels: SendChannelMessage posts as the default Macro AI sender and as a with_actor bot, with triggered_by set to the user.
  • properties, projects: schema tests unchanged; receipts now read service_context.actor.

Blast Radius

User-receipt document edits keep the old actor_user_id JSON. Team-scoped bot deletes stay unattributed. Downstream Kafka test fixtures that construct Updated/Deleted set the new optional fields. Property and project crates depend on bot_id. documents and channels add bot_id/test-utils as a dev-dependency for BotId::TEST_A.

Open in Web Open in Cursor 

@coderabbitai

coderabbitai Bot commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 4a737a6e-2171-4d14-a174-bd17510e43c9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 8933658b-a017-4d5e-917b-c2e019fb2364

📥 Commits

Reviewing files that changed from the base of the PR and between c758571 and 4cb7304.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock, !**/Cargo.lock
  • packages/sdk/generated/storage/types.gen.ts is excluded by !**/generated/**, !**/*.gen.ts
📒 Files selected for processing (23)
  • apps/web/src/lib/service-clients/service-storage/openapi.json
  • crates/documents/src/domain/activity.rs
  • crates/documents/src/domain/activity/test.rs
  • crates/documents/src/domain/events.rs
  • crates/documents/src/domain/service.rs
  • crates/documents/src/inbound/toolset.rs
  • crates/documents/src/inbound/toolset/create_document.rs
  • crates/documents/src/inbound/toolset/rename_document.rs
  • crates/documents/src/inbound/toolset/test.rs
  • crates/entity_access/src/domain/models.rs
  • crates/projects/Cargo.toml
  • crates/projects/src/inbound/toolset/move_to_project.rs
  • crates/properties/Cargo.toml
  • crates/properties/src/domain/service_impl.rs
  • crates/properties/src/domain/service_impl/task_properties.rs
  • crates/properties/src/domain/test.rs
  • crates/properties/src/inbound/toolset/bulk_set_entity_property_options.rs
  • crates/properties/src/inbound/toolset/set_entity_property.rs
  • crates/soup_realtime/src/inbound/kafka_consumer/test.rs
  • crates/webhook/src/domain/ingestion/test.rs
  • crates/webhook/src/inbound/kafka_consumer/test.rs
  • packages/sdk/specs/storage.json
  • services/search_processing_service/src/inbound/kafka_consumer/test.rs

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Summary

Summary by CodeRabbit

  • New Features
    • Document update and deletion events now include optional actor and “on behalf of” attribution details.
    • AI-assisted document actions are attributed to the AI assistant while identifying the user they act for.
    • User-scoped automated actions can now update task assignments, relationships, properties, and project locations with the appropriate user context.
  • Improvements
    • Activity feeds and notifications more accurately reflect both the acting assistant and the represented user.
    • Updated event schemas are available through the storage API and SDK.

Walkthrough

Document update and delete metadata now includes optional actor and on_behalf_of fields. Lifecycle activity derives attribution from explicit actors, legacy user IDs, and delegation data. AI document tools record Macro AI attribution and use user-scoped bot receipts. Project moves and property tools use the same receipt model. Property authorization and task assignment notifications resolve the acting user. Tests and generated storage schemas were updated.

Merge Risk: 🔵 Low · up to 4cb73

AI-created and edited documents will show Macro AI acting for the requesting user while preserving that user's permissions. The PR is mergeable with owner awareness that incorrect upstream identity binding could misattribute or authorize writes, and that attribution may be lost during partial event-publication or recovery failures.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title uses the conventional commits format with the feat: prefix, is 63 characters long, and accurately describes the AI activity attribution changes.
Description check ✅ Passed The description clearly explains the Macro AI attribution changes, affected workflows, scope, and tradeoffs. It is related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

❤️ Share

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

@github-actions

github-actions Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Comment thread crates/projects/src/inbound/toolset/move_to_project.rs Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8234e42. Configure here.

Comment thread crates/properties/src/inbound/toolset/set_entity_property.rs Outdated
Comment thread crates/properties/src/inbound/toolset/set_entity_property.rs Outdated
Base automatically changed from synoet/feat-activity-collab-actor-d5e6 to main September 2, 2026 22:03
cursoragent and others added 6 commits September 2, 2026 18:03
CreateDocument sets Delegated(MACRO_AI_BOT_ID, user).
Rename, property writes, and MoveToProject mint a user-scoped
AI bot receipt. Document Updated/Deleted gain actor and
on_behalf_of so those receipts ingest as Edited, not Ignore.

Co-authored-by: teo <synoet@users.noreply.github.com>
Same Kafka fields as property publish. A named struct
replaces the positional triple.

Co-authored-by: teo <synoet@users.noreply.github.com>
DocumentUpdatedMetadata and DocumentDeletedMetadata now carry optional
actor and on_behalf_of. Refresh the OpenAPI spec and SDK types.

Co-authored-by: teo
MoveToProject minted a Macro AI receipt for every entity kind, but
chat patch, project updates, and email project-changed events still
require an authenticated user. Only documents publish bot attribution.

Co-authored-by: teo <synoet@users.noreply.github.com>
SetEntityProperty mints a Macro AI receipt, but parent/subtask
checks treated every bot as denied and assignee notify read only
authenticated_user. Use the acting user for both.

Co-authored-by: teo <synoet@users.noreply.github.com>
…ceipt path

- BotAccessScope::user replaces the per-crate ai_tool_user_scope helpers and
  inline literals.
- MoveToProject mints entity and project receipts through a single
  MovePrincipal::receipt instead of two duplicated if/else blocks.
- published_document_actors uses Default; mutation_attribution uses
  Attribution::new.

Co-authored-by: teo <synoet@users.noreply.github.com>
@synoet
synoet force-pushed the synoet/feat-activity-ai-tool-attribution-d5e6 branch from 16427d0 to 4cb7304 Compare September 2, 2026 22:03
…Macro AI

Every mutating AI tool hardcoded MACRO_AI_BOT_ID into whatever carrier its
domain uses: create metadata, bot receipts, the collab JWT actor claim, the
channel Sender. The identity now lives once on each toolset context as
`actor: BotId` (default Macro AI) and ToolServiceContext::with_actor sets
it for a whole agent session. Tools read service_context.actor; documents
expose attribution(user) for the create metadata carrier, and MovePrincipal
carries the bot it mints receipts for.

Tests pin both the Macro AI default and with_actor flowing into the edit
token, the create attribution, and the channel message sender.
@cursor cursor Bot changed the title feat(activity): attribute AI tool creates and edits to Macro AI feat(activity): attribute AI tool creates and edits to the tool actor (Macro AI) Sep 2, 2026
@synoet
synoet merged commit 6bd5217 into main Sep 3, 2026
34 checks passed
@synoet
synoet deleted the synoet/feat-activity-ai-tool-attribution-d5e6 branch September 3, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants