Skip to content

Commit 4d262a7

Browse files
fregataaclaude
andcommitted
refactor(BA-5777): rename Batch to Bulk to match updated issue terminology
BA-5777 description was revised to use "Bulk" throughout. Rename the identifiers introduced in this branch to match: - Files: action/batch.py → action/bulk.py and the mirrors under processor/, validator/, validators/rbac/, plus the test file - Classes & type vars: BaseBatchAction → BaseBulkAction, BaseBatchActionResult → BaseBulkActionResult, BatchActionValidator → BulkActionValidator, BatchActionRBACValidator → BulkActionRBACValidator, BatchActionProcessor → BulkActionProcessor, BatchValidationResult → BulkValidationResult, BatchValidatorDecision → BulkValidatorDecision, BatchProcessResult → BulkProcessResult, TBatchAction/TBatchActionResult → TBulkAction/TBulkActionResult - __init__ exports and changelog fragment updated accordingly Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 32a0fa8 commit 4d262a7

7 files changed

Lines changed: 107 additions & 111 deletions

File tree

changes/11191.feature.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Add batch RBAC filtering infrastructure so `BatchActionProcessor` can narrow actions per-entity and report per-validator decisions.
1+
Add bulk RBAC filtering infrastructure so `BulkActionProcessor` can narrow actions per-entity and report per-validator decisions.

src/ai/backend/manager/actions/action/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
TAction,
99
TActionResult,
1010
)
11-
from .batch import (
12-
BaseBatchAction,
13-
BaseBatchActionResult,
11+
from .bulk import (
12+
BaseBulkAction,
13+
BaseBulkActionResult,
1414
)
1515
from .rbac import (
1616
BaseRBACAction,
@@ -111,8 +111,8 @@
111111
"BaseActionResult",
112112
"BaseActionResultMeta",
113113
"BaseActionTriggerMeta",
114-
"BaseBatchAction",
115-
"BaseBatchActionResult",
114+
"BaseBulkAction",
115+
"BaseBulkActionResult",
116116
"BaseRBACAction",
117117
"RBACActionName",
118118
"RBACRequiredPermission",

src/ai/backend/manager/actions/action/batch.py renamed to src/ai/backend/manager/actions/action/bulk.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66

77

88
@dataclass
9-
class BaseBatchAction[T](BaseAction):
10-
"""Base class for actions operating on a batch of entities.
9+
class BaseBulkAction[T](BaseAction):
10+
"""Base class for actions operating on a bulk of entities.
1111
12-
``entity_ids`` is stored as ``list[str]`` so ``BatchActionValidator``
12+
``entity_ids`` is stored as ``list[str]`` so ``BulkActionValidator``
1313
implementations can match against validator verdicts directly. The
1414
original ``T``-typed view is exposed via ``typed_entity_ids()``.
1515
16-
Batch actions intentionally carry **only** ``entity_ids``. User context
16+
Bulk actions intentionally carry **only** ``entity_ids``. User context
1717
(user id, role) flows through ``current_user()``, not the action, so
18-
``BatchActionProcessor`` can reconstruct a filtered action by calling
18+
``BulkActionProcessor`` can reconstruct a filtered action by calling
1919
``type(action)(entity_ids=...)`` directly — no ``__init__`` override or
2020
factory hook is required. Subclasses that try to add required fields
2121
break that constructor call and will fail fast at runtime, which is
@@ -30,7 +30,7 @@ def typed_entity_ids(self) -> list[T]:
3030
raise NotImplementedError
3131

3232

33-
class BaseBatchActionResult(BaseActionResult):
33+
class BaseBulkActionResult(BaseActionResult):
3434
@override
3535
def entity_id(self) -> str | None:
3636
return None
@@ -40,5 +40,5 @@ def entity_ids(self) -> list[str]:
4040
raise NotImplementedError
4141

4242

43-
TBatchAction = TypeVar("TBatchAction", bound=BaseBatchAction[Any])
44-
TBatchActionResult = TypeVar("TBatchActionResult", bound=BaseBatchActionResult)
43+
TBulkAction = TypeVar("TBulkAction", bound=BaseBulkAction[Any])
44+
TBulkActionResult = TypeVar("TBulkActionResult", bound=BaseBulkActionResult)

src/ai/backend/manager/actions/processor/batch.py renamed to src/ai/backend/manager/actions/processor/bulk.py

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
from ai.backend.manager.actions.action import (
1111
BaseActionTriggerMeta,
1212
)
13-
from ai.backend.manager.actions.action.batch import (
14-
BaseBatchAction,
15-
BaseBatchActionResult,
13+
from ai.backend.manager.actions.action.bulk import (
14+
BaseBulkAction,
15+
BaseBulkActionResult,
1616
)
1717
from ai.backend.manager.actions.monitors.monitor import ActionMonitor
18-
from ai.backend.manager.actions.validator.batch import (
19-
BatchActionValidator,
20-
BatchValidationResult,
18+
from ai.backend.manager.actions.validator.bulk import (
19+
BulkActionValidator,
20+
BulkValidationResult,
2121
)
2222

2323
from .base import ActionRunner
@@ -26,45 +26,45 @@
2626

2727

2828
@dataclass(frozen=True)
29-
class BatchValidatorDecision:
30-
"""One validator's per-entity verdict observed during batch processing.
29+
class BulkValidatorDecision:
30+
"""One validator's per-entity verdict observed during bulk processing.
3131
3232
Mirrors the ``SubStepResult`` pattern used by the scheduler history so
3333
callers can trace where in the validator chain each ID was filtered and
3434
*why*. ``results`` carries the validator's classification unchanged.
3535
"""
3636

3737
validator_name: str
38-
results: BatchValidationResult
38+
results: BulkValidationResult
3939

4040

4141
@dataclass(frozen=True)
42-
class BatchProcessResult[TBatchActionResult: BaseBatchActionResult]:
43-
"""Outcome of a ``BatchActionProcessor`` run.
42+
class BulkProcessResult[TBulkActionResult: BaseBulkActionResult]:
43+
"""Outcome of a ``BulkActionProcessor`` run.
4444
4545
``result`` is what the service function returned for the permitted subset
4646
of entity IDs. ``validator_decisions`` keeps the per-validator trace in
4747
iteration order; callers assemble the partial-success response by
4848
walking it (each decision carries the denied IDs and their reasons).
4949
"""
5050

51-
result: TBatchActionResult
52-
validator_decisions: list[BatchValidatorDecision]
51+
result: TBulkActionResult
52+
validator_decisions: list[BulkValidatorDecision]
5353

5454

55-
class BatchActionProcessor[
56-
TBatchAction: BaseBatchAction[Any],
57-
TBatchActionResult: BaseBatchActionResult,
55+
class BulkActionProcessor[
56+
TBulkAction: BaseBulkAction[Any],
57+
TBulkActionResult: BaseBulkActionResult,
5858
]:
59-
_validators: Sequence[BatchActionValidator]
59+
_validators: Sequence[BulkActionValidator]
6060

61-
_runner: ActionRunner[TBatchAction, TBatchActionResult]
61+
_runner: ActionRunner[TBulkAction, TBulkActionResult]
6262

6363
def __init__(
6464
self,
65-
func: Callable[[TBatchAction], Awaitable[TBatchActionResult]],
65+
func: Callable[[TBulkAction], Awaitable[TBulkActionResult]],
6666
monitors: Sequence[ActionMonitor] | None = None,
67-
validators: Sequence[BatchActionValidator] | None = None,
67+
validators: Sequence[BulkActionValidator] | None = None,
6868
) -> None:
6969
self._runner = ActionRunner(func, monitors)
7070

@@ -73,13 +73,13 @@ def __init__(
7373
@asynccontextmanager
7474
async def _validator_scope(
7575
self,
76-
validator: BatchActionValidator,
77-
action: TBatchAction,
76+
validator: BulkActionValidator,
77+
action: TBulkAction,
7878
meta: BaseActionTriggerMeta,
79-
) -> AsyncIterator[BatchValidationResult]:
79+
) -> AsyncIterator[BulkValidationResult]:
8080
"""Run one validator inside a bookend scope.
8181
82-
Yields the validator's ``BatchValidationResult`` so the caller can
82+
Yields the validator's ``BulkValidationResult`` so the caller can
8383
record the decision inside the block. Timing and per-validator
8484
logging live here rather than inside each validator implementation.
8585
"""
@@ -90,7 +90,7 @@ async def _validator_scope(
9090
finally:
9191
duration = (datetime.now(UTC) - started_at).total_seconds()
9292
log.debug(
93-
"batch validator {} saw {} ids, denied {} in {:.3f}s",
93+
"bulk validator {} saw {} ids, denied {} in {:.3f}s",
9494
validator.name(),
9595
len(validation.allowed_entity_ids) + len(validation.denied_entities),
9696
len(validation.denied_entities),
@@ -99,9 +99,9 @@ async def _validator_scope(
9999

100100
def _process_action(
101101
self,
102-
current_action: TBatchAction,
103-
validation: BatchValidationResult,
104-
) -> TBatchAction:
102+
current_action: TBulkAction,
103+
validation: BulkValidationResult,
104+
) -> TBulkAction:
105105
"""Return a new action narrowed to the IDs this validator permitted.
106106
107107
Returns the incoming action unchanged when the validator denied
@@ -115,30 +115,28 @@ def _process_action(
115115
filtered_ids = [eid for eid in current_action.entity_ids if eid in allowed_set]
116116
return type(current_action)(entity_ids=filtered_ids)
117117

118-
async def _run(self, action: TBatchAction) -> BatchProcessResult[TBatchActionResult]:
118+
async def _run(self, action: TBulkAction) -> BulkProcessResult[TBulkActionResult]:
119119
started_at = datetime.now(UTC)
120120
action_id = uuid.uuid4()
121121
action_trigger_meta = BaseActionTriggerMeta(action_id=action_id, started_at=started_at)
122122

123-
current_action: TBatchAction = action
124-
decisions: list[BatchValidatorDecision] = []
123+
current_action: TBulkAction = action
124+
decisions: list[BulkValidatorDecision] = []
125125

126126
for validator in self._validators:
127127
async with self._validator_scope(
128128
validator, current_action, action_trigger_meta
129129
) as validation:
130130
decisions.append(
131-
BatchValidatorDecision(
131+
BulkValidatorDecision(
132132
validator_name=validator.name(),
133133
results=validation,
134134
)
135135
)
136136
current_action = self._process_action(current_action, validation)
137137

138138
action_result = await self._runner.run(current_action, action_trigger_meta)
139-
return BatchProcessResult(result=action_result, validator_decisions=decisions)
139+
return BulkProcessResult(result=action_result, validator_decisions=decisions)
140140

141-
async def wait_for_complete(
142-
self, action: TBatchAction
143-
) -> BatchProcessResult[TBatchActionResult]:
141+
async def wait_for_complete(self, action: TBulkAction) -> BulkProcessResult[TBulkActionResult]:
144142
return await self._run(action)

src/ai/backend/manager/actions/validator/batch.py renamed to src/ai/backend/manager/actions/validator/bulk.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,36 @@
33
from typing import Any
44

55
from ai.backend.manager.actions.action import BaseActionTriggerMeta
6-
from ai.backend.manager.actions.action.batch import BaseBatchAction
6+
from ai.backend.manager.actions.action.bulk import BaseBulkAction
77

88

99
@dataclass(frozen=True)
1010
class DeniedEntity:
11-
"""A batch entity that a validator rejected, paired with its reason."""
11+
"""A bulk entity that a validator rejected, paired with its reason."""
1212

1313
entity_id: str
1414
deny_reason: str
1515

1616

1717
@dataclass(frozen=True)
18-
class BatchValidationResult:
19-
"""Per-entity validation outcome for a batch action.
18+
class BulkValidationResult:
19+
"""Per-entity validation outcome for a bulk action.
2020
21-
``BatchActionProcessor`` intersects ``allowed_entity_ids`` across
21+
``BulkActionProcessor`` intersects ``allowed_entity_ids`` across
2222
validators and records each ``DeniedEntity`` — with its reason — on the
23-
corresponding ``BatchValidatorDecision`` so the final response can
23+
corresponding ``BulkValidatorDecision`` so the final response can
2424
surface *why* each ID was filtered out.
2525
"""
2626

2727
allowed_entity_ids: list[str]
2828
denied_entities: list[DeniedEntity]
2929

3030

31-
class BatchActionValidator(ABC):
31+
class BulkActionValidator(ABC):
3232
@classmethod
3333
@abstractmethod
3434
def name(cls) -> str:
35-
"""Stable identifier used in ``BatchValidatorDecision.validator_name``.
35+
"""Stable identifier used in ``BulkValidatorDecision.validator_name``.
3636
3737
Chosen by the implementation so logs and partial-success responses can
3838
attribute denials to a specific validator independently of the Python
@@ -42,9 +42,9 @@ class name.
4242

4343
@abstractmethod
4444
async def validate(
45-
self, action: BaseBatchAction[Any], meta: BaseActionTriggerMeta
46-
) -> BatchValidationResult:
47-
"""Validate the batch action and return per-entity permission results.
45+
self, action: BaseBulkAction[Any], meta: BaseActionTriggerMeta
46+
) -> BulkValidationResult:
47+
"""Validate the bulk action and return per-entity permission results.
4848
4949
Implementations must classify every ID in ``action.entity_ids`` as
5050
either allowed or denied. Validators that cannot make a decision for

src/ai/backend/manager/actions/validators/rbac/batch.py renamed to src/ai/backend/manager/actions/validators/rbac/bulk.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
from typing import Any, override
22

33
from ai.backend.manager.actions.action import BaseActionTriggerMeta
4-
from ai.backend.manager.actions.action.batch import BaseBatchAction
5-
from ai.backend.manager.actions.validator.batch import (
6-
BatchActionValidator,
7-
BatchValidationResult,
4+
from ai.backend.manager.actions.action.bulk import BaseBulkAction
5+
from ai.backend.manager.actions.validator.bulk import (
6+
BulkActionValidator,
7+
BulkValidationResult,
88
)
99
from ai.backend.manager.repositories.permission_controller.repository import (
1010
PermissionControllerRepository,
1111
)
1212

1313

14-
class BatchActionRBACValidator(BatchActionValidator):
14+
class BulkActionRBACValidator(BulkActionValidator):
1515
def __init__(
1616
self,
1717
repository: PermissionControllerRepository,
@@ -25,11 +25,11 @@ def name(cls) -> str:
2525

2626
@override
2727
async def validate(
28-
self, action: BaseBatchAction[Any], meta: BaseActionTriggerMeta
29-
) -> BatchValidationResult:
30-
# TODO: wire this to PermissionControllerRepository.check_batch_permission_with_scope_chain().
28+
self, action: BaseBulkAction[Any], meta: BaseActionTriggerMeta
29+
) -> BulkValidationResult:
30+
# TODO: wire this to PermissionControllerRepository.check_bulk_permission_with_scope_chain().
3131
# Until then, every entity is treated as allowed so legacy behavior is preserved.
32-
return BatchValidationResult(
32+
return BulkValidationResult(
3333
allowed_entity_ids=list(action.entity_ids),
3434
denied_entities=[],
3535
)

0 commit comments

Comments
 (0)