Skip to content

fix(teams): split multi-member update ops into per-member requests - #778

Merged
prasad-albert merged 5 commits into
mainfrom
cakeagents/sdk-167
Sep 30, 2026
Merged

prasad-albert merged 5 commits into
mainfrom
cakeagents/sdk-167

Conversation

@lkubie

@lkubie lkubie commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

What

TeamCollection.update() built one patch operation per member (add/remove) and sent them all in a single PATCH call. The ops for member changes all share attribute: "ACL". This splits those member ops out so each is sent in its own request, while all other ops (name, role changes) remain batched in one call.

Why

SDK-167 (audit §5.30): api-team's patch handler rejects any call containing more than one op for the same attribute (fgc" role changes excepted) with a 400 "Duplicate entities not allowed" (Team.service.js#Validate -> duplicates()). As a result, adding or removing two or more members in one update()` call always failed.

How

  • Extracted payload construction into a pure TeamCollection._generate_patch_payloads() helper that returns one op list per request: non-member ops (name, fgc role changes) batched first, then one request per member add/remove op (adds before removes, preserving owner-swap safety).
  • update() sends one PATCH per op list. The yml documents no per-call op maximum; the API constraint is one op per attribute per call, so per-member requests are the split.
  • 206 partial-success: implemented a minimal local check consistent with existing code (companies.merge, lots.create, custom_templates.create): when a PATCH returns 206 with FailedItems, a warning is logged instead of silently swallowing the partial failure. When the shared helper from fix(core): surface partial-success failures and skipped items #771 (SDK-156) lands, this can migrate to it as a follow-up.

Testing

  • Added pure unit tests for the payload split in tests/utils/test_patches.py (sanctioned patch-builder location; no FakeAlbertSession): multi-member split, single-member batching, and no-op cases.
  • Added integration coverage test_update_multiple_members (adds and removes two members in one update() call) plus a third_user session fixture, per the audit's note that tests only exercised single-member updates. Requires live credentials to run; verified with --collect-only.
  • Ran: ruff format + ruff check (clean), pytest tests/collections/test_teams.py --collect-only -q (8 collected), pytest tests/core tests/utils tests/unit -q (117 passed).

Cake session: https://agents.ai.albertinventdev.com/sessions/910a4725-9404-4336-81dd-e30bfef0ce73

TeamCollection.update() emitted one patch op per member in a single
call; api-team rejects duplicate attributes in one call, so adding or
removing two or more members at once always 400s. Member add/remove
ops now go out one request per member while other ops (name, role
changes) stay batched. A 206 partial-success response now logs its
FailedItems instead of being silently swallowed.

Refs: SDK-167
@claude

claude Bot commented Sep 24, 2026

Copy link
Copy Markdown

Looks good - no bugs or correctness issues found.

@prasad-albert prasad-albert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM! Verified backend contract parity, backward compatibility, caller ergonomics, and SDK conventions. Ready to merge.

@claude

claude Bot commented Sep 25, 2026

Copy link
Copy Markdown

Looks good - no bugs or correctness issues found.

# Conflicts:
#	tests/utils/test_patches.py
@claude

claude Bot commented Sep 25, 2026

Copy link
Copy Markdown

Looks good - no bugs or correctness issues found.

# Conflicts:
#	tests/utils/test_patches.py
@claude

claude Bot commented Sep 25, 2026

Copy link
Copy Markdown

Looks good - no bugs or correctness issues found.

@lkubie

lkubie commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator Author

CircleCI Integration Tests failed

Branch: cakeagents/sdk-167 (90f5375)
Build: https://circleci.com/gh/albert-labs/albert-python/8613

=========================== short test summary info ============================
FAILED tests/integration/collections/test_inventory.py::test_inventory_search_with_name_only_storage_location_filter@inventory - AssertionError: assert {'INVA658140'} == {'INVA658140', 'INVB658145'}
  
  Extra items in the right set:
  'INVB658145'
  
  Full diff:
    {
        'INVA658140',
  -     'INVB658145',
    }
SKIPPED [10] tests/integration/collections/test_cas.py: CAS collection is deprecated in favor of Substance v4; the testing tenant has migrated to substance_v4.
SKIPPED [1] tests/integration/collections/test_data_templates.py:193: No eligible user returned by users.search() for ACL update.
SKIPPED [1] tests/integration/collections/test_data_templates.py:731: No extensions configured in tenant
SKIPPED [1] tests/integration/collections/test_inventory.py:197: LLM search is currently not working as expected.
SKIPPED [1] tests/integration/collections/test_lots.py:91: No second active user available for team tests
SKIPPED [1] tests/integration/collections/test_btdataset.py:23: created_by=USR226595 returned no datasets on this tenant (seeded DST1522)
SKIPPED [1] tests/integration/collections/test_reports.py:48: Report Queries not loaded into testing environment yet
SKIPPED [1] tests/integration/collections/test_sds.py:105: Tenant cannot generate SDS for seeded formula: POST 'https://staging.albertinventdev.com/api/v2/documentgenerator/sds' failed with status code 422 (Unprocessable Entity). Errors: [{'msg': 'ERROR_MISSING_INFO_CAS', 'casIDs': ['SDK-Test-cac61efb-627a-4d4a-82c8-37cc1d47009b-64-17-5']}]
SKIPPED [1] tests/integration/collections/test_teams.py:90: No second active user available for team tests
SKIPPED [1] tests/integration/collections/test_teams.py:116: No second active user available for team tests
SKIPPED [1] tests/integration/collections/test_teams.py:141: No second active user available for team tests
SKIPPED [15] tests/integration/collections/test_chats.py: Chats API is not yet available in the test environment.
SKIPPED [1] tests/integration/collections/test_files.py:33: Breakthrough file namespace not available or upload not visible
SKIPPED [1] tests/integration/collections/test_users.py:92: No search hits could be hydrated (stale index IDs)
SKIPPED [1] tests/integration/resources/test_sheets.py:221: Seeded Process Design has no rows to reference
XFAIL tests/integration/collections/test_design_runs.py::test_create_optimization_returns_generate_insight@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_create_doe_returns_smart_doe_insight@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_optimization_returns_response@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_doe_returns_response@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_create_optimization_accepts_weighted_objectives@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_optimization_accepts_weighted_objectives@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_optimization_accepts_plain_criterion@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_optimization_treats_a_null_weight_as_unweighted@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_smart_datasets.py::test_smart_dataset_get_data@datatemplates - No DWH available in TEN0 test environment.
XFAIL tests/integration/collections/test_smart_datasets.py::test_smart_dataset_get_data_with_filters@datatemplates - No DWH available in TEN0 test environment.
XFAIL tests/integration/collections/test_tasks.py::test_get_and_set_block_rules@tasks - increased intervals is not live on ten0 test env
XFAIL tests/integration/collections/test_tasks.py::test_create_with_combinations_integration@tasks - increased intervals is not live on ten0 test env
XFAIL tests/integration/collections/test_activities.py::test_activity_search - GET /api/v3/activities/search 500 OpenSearch on TEN0 staging: https://linear.app/albert-invent/issue/SEA-221
XPASS tests/integration/collections/test_smart_datasets.py::test_smart_dataset_create_with_build@datatemplates - No DWH available in TEN0 test environment.
XPASS tests/integration/collections/test_targets.py::test_target_create_with_between_parameter_filter@datatemplates - Requires api-targets backend to accept operator/value-pair TargetParameter.value (ML-1207). Remove decorator once deployed.
XPASS tests/integration/collections/test_batch_data.py::test_create_batch_data@tasks - Batch data creation is currently not idempotent, so this test may fail if batch data already exists for the task.
XPASS tests/integration/collections/test_tasks.py::test_generate_block_combinations_integration@tasks - increased intervals is not live on ten0 test env
XPASS tests/integration/collections/test_substance_v4.py::test_search_pagination@projects - api-substance-v4 search pagination intermittently returns duplicate items across pages (MoleculeEngineering/api-substance-v4#57).
= 1 failed, 353 passed, 38 skipped, 13 xfailed, 5 xpassed, 36 warnings in 579.68s (0:09:39) =

lkubie commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator Author

Integration failure is the known partial-index poll flake in test_inventory_search_with_name_only_storage_location_filter (poll stopped at first non-empty page before both seeds indexed). Fixed by the poll_until predicate in #798, pending merge. Teams diff is unrelated.

@lkubie
lkubie requested review from albert-tb and anubhavd-albert and removed request for albert-tb and anubhavd-albert September 28, 2026 15:53
@claude

claude Bot commented Sep 28, 2026

Copy link
Copy Markdown

Looks good - no bugs or correctness issues found.

@lkubie

lkubie commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator Author

CircleCI Integration Tests failed

Branch: cakeagents/sdk-167 (7e6b7ba)
Build: https://circleci.com/gh/albert-labs/albert-python/8718

=========================== short test summary info ============================
FAILED tests/integration/collections/test_substance_v4.py::test_update_metadata@projects - albert.exceptions.BadRequestError: PATCH 'https://staging.albertinventdev.com/api/v4/substances/metadata/SUB1f1bb552-f6b6-6e20-a155-db861cc5d10a' failed with status code 400 (Bad Request). Errors: [{'msg': 'CAS API request failed (no response received)'}]
Body:
b'{"data": [{"operation": "add", "attribute": "notes", "newValue": "sdk test note"}, {"operation": "add", "attribute": "casSmiles", "newValue": "CCO"}, {"operation": "add", "attribute": "Metadata.test_substances_string_field", "newValue": "sdk test value"}]}'
SKIPPED [10] tests/integration/collections/test_cas.py: CAS collection is deprecated in favor of Substance v4; the testing tenant has migrated to substance_v4.
SKIPPED [1] tests/integration/collections/test_data_templates.py:193: No eligible user returned by users.search() for ACL update.
SKIPPED [1] tests/integration/collections/test_inventory.py:210: LLM search is currently not working as expected.
SKIPPED [1] tests/integration/collections/test_data_templates.py:731: No extensions configured in tenant
SKIPPED [1] tests/integration/collections/test_lots.py:91: No second active user available for team tests
SKIPPED [1] tests/integration/collections/test_btdataset.py:23: created_by=USR226595 returned no datasets on this tenant (seeded DST1570)
SKIPPED [1] tests/integration/collections/test_reports.py:46: Report Queries not loaded into testing environment yet
SKIPPED [1] tests/integration/collections/test_teams.py:90: No second active user available for team tests
SKIPPED [1] tests/integration/collections/test_teams.py:116: No second active user available for team tests
SKIPPED [1] tests/integration/collections/test_teams.py:141: No second active user available for team tests
SKIPPED [15] tests/integration/collections/test_chats.py: Chats API is not yet available in the test environment.
SKIPPED [1] tests/integration/collections/test_sds.py:105: Tenant cannot generate SDS for seeded formula: POST 'https://staging.albertinventdev.com/api/v2/documentgenerator/sds' failed with status code 422 (Unprocessable Entity). Errors: [{'msg': 'ERROR_MISSING_INFO_CAS', 'casIDs': ['SDK-Test-e57073d9-114a-4916-9a60-4be319c36f0b-64-17-5']}]
SKIPPED [1] tests/integration/collections/test_users.py:92: No search hits could be hydrated (stale index IDs)
SKIPPED [1] tests/integration/collections/test_files.py:33: Breakthrough file namespace not available or upload not visible
SKIPPED [1] tests/integration/resources/test_sheets.py:221: Seeded Process Design has no rows to reference
XFAIL tests/integration/collections/test_design_runs.py::test_create_optimization_returns_generate_insight@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_create_doe_returns_smart_doe_insight@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_optimization_returns_response@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_doe_returns_response@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_create_optimization_accepts_weighted_objectives@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_optimization_accepts_weighted_objectives@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_optimization_accepts_plain_criterion@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_design_runs.py::test_validate_optimization_treats_a_null_weight_as_unweighted@datatemplates - api-designruns is not live in the TEN0 test environment.
XFAIL tests/integration/collections/test_smart_datasets.py::test_smart_dataset_get_data@datatemplates - No DWH available in TEN0 test environment.
XFAIL tests/integration/collections/test_smart_datasets.py::test_smart_dataset_get_data_with_filters@datatemplates - No DWH available in TEN0 test environment.
XFAIL tests/integration/collections/test_tasks.py::test_get_and_set_block_rules@tasks - increased intervals is not live on ten0 test env
XFAIL tests/integration/collections/test_tasks.py::test_create_with_combinations_integration@tasks - increased intervals is not live on ten0 test env
XFAIL tests/integration/collections/test_activities.py::test_activity_search - GET /api/v3/activities/search 500 OpenSearch on TEN0 staging: https://linear.app/albert-invent/issue/SEA-221
XPASS tests/integration/collections/test_smart_datasets.py::test_smart_dataset_create_with_build@datatemplates - No DWH available in TEN0 test environment.
XPASS tests/integration/collections/test_batch_data.py::test_create_batch_data@tasks - Batch data creation is currently not idempotent, so this test may fail if batch data already exists for the task.
XPASS tests/integration/collections/test_targets.py::test_target_create_with_between_parameter_filter@datatemplates - Requires api-targets backend to accept operator/value-pair TargetParameter.value (ML-1207). Remove decorator once deployed.
XPASS tests/integration/collections/test_tasks.py::test_generate_block_combinations_integration@tasks - increased intervals is not live on ten0 test env
XPASS tests/integration/collections/test_substance_v4.py::test_search_pagination@projects - api-substance-v4 search pagination intermittently returns duplicate items across pages (MoleculeEngineering/api-substance-v4#57).
= 1 failed, 354 passed, 38 skipped, 13 xfailed, 5 xpassed, 36 warnings in 593.69s (0:09:53) =

@prasad-albert
prasad-albert merged commit 17f37c5 into main Sep 30, 2026
5 checks passed
@prasad-albert
prasad-albert deleted the cakeagents/sdk-167 branch September 30, 2026 10:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants