Repository navigation
refactor(user-management): move byte-identical team_service to autobot_shared (#12647) - #13164
Merged
Merged
Conversation
…t_shared (#12647) team_service.py was byte-identical across autobot-backend and autobot-slm-backend — 701 duplicated lines, so a fix landed in one service or the other but never both by accident. It is the first user_management *service* that could move: its entire runtime dependency set already lives in autobot_shared — Team/TeamMembership and the audit vocabulary (#13130), BaseService/TenantContext (#12972). Its only mentions of User and Organization are in docstrings and error strings, never as classes, so it does not need the concrete per-backend models. Placed flat as autobot_shared/user_management/team_service.py, matching the existing base_service.py rather than inventing a second services/ location. Both backends keep a re-export shim so all existing importers, including each services/__init__.py, are untouched. organization_service.py is also byte-identical but deliberately not moved: it imports the concrete User and Organization at runtime, and those stay backend-local by design.
Contributor
✅ SSOT Configuration Compliance: Passing🎉 No hardcoded values detected that have SSOT config equivalents! |
…t mypy (#12647) team_service.py moved into autobot_shared/, which CI type-checks strictly; the backend copy never was. Two latent errors surfaced: - _apply_team_name_update declared name: str but update_team passes str | None. The body already guards with 'if name and ...', so this was a wrong annotation rather than a live crash — widened to str | None. - changes needed an explicit annotation; typed as dict[str, dict[str, Any]] to match the {'old': ..., 'new': ...} audit payload it carries.
This was referenced Aug 1, 2026
mrveiss
added a commit
that referenced
this pull request
Aug 1, 2026
… models (#12647) (#13201) * refactor(user-management): converge organization_service via injected models (#12647) organization_service.py was byte-identical across both backends (545 lines) but could not be relocated the way team_service.py was (#13164): it queries the concrete Organization and User models, and those stay backend-local under the abstract-core decision (#13163) because backend carries LLC/PM-sync columns and activity relationships SLM must not gain. Importing them from autobot_shared would invert the dependency this umbrella exists to remove. Per the owner's decision the canonical service takes them by injection: - autobot_shared/user_management/organization_service.py names neither class. Queries go through self.organization_model / self.user_model; annotations use the shared OrganizationCore. Team needs no injection — it is already one shared class (#13130). - Each backend subclasses it and binds its own pair, and re-exports the four error classes so every existing importer is untouched. - Construction raises TypeError if a subclass forgot to bind, so the failure names its cause instead of surfacing as an AttributeError inside a query. No behaviour change: the query construction is identical, only the way the model class is reached differs. The public API is unchanged — all 11 methods plus the inherited apply_tenant_filter, verified against the pre-refactor surface. * docs(session): handoff for issue-12647 organization_service slice (#12647) --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This was referenced Aug 25, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #12647
Thinking Path
services/team_service.pywas byte-identical acrossautobot-backendandautobot-slm-backend:701 lines duplicated verbatim, which is the exact failure mode #12645 exists to
end: a fix lands in one service and silently never reaches the other.
It is the first
user_managementservice that can actually move, and thatis worth being precise about, because its byte-identical twin cannot. The whole
question is what a service needs at runtime:
Team,TeamMembershipautobot_sharedAuditAction,AuditLog,AuditResourceTypeautobot_sharedBaseService,TenantContextautobot_sharedEvery runtime dependency is already shared.
UserandOrganizationappear inthis file only in docstrings and error strings, never as classes — verified
by grep — so it does not need the concrete per-backend models.
organization_service.pyis also byte-identical (545 lines) and isdeliberately not in this PR: it does
from user_management.models import Organization, Team, Userat runtime, and those concrete classes staybackend-local by design (#13163). Moving it would force
autobot_sharedtoimport a backend-local package — an inverted dependency. It needs its own
resolution, not a copy of this one.
What Changed
autobot_shared/user_management/team_service.py— the implementation,with its three imports repointed at the shared modules.
(
TeamService,TeamServiceError,TeamNotFoundError,DuplicateTeamError,MembershipError), so every importer — including eachuser_management/services/__init__.py— is untouched.autobot_shared/user_management/team_service_test.py(8 tests).Placement: flat, as
autobot_shared/user_management/team_service.py,matching the existing
base_service.pyrather than inventing a secondservices/location for the same category of file. The package's lazy_LAZY_IMPORTSalready spellsbase_serviceas.base_service.Verification
Identity, not just equivalence. The tests assert both shims resolve to the
same objects — two same-named classes are not interchangeable, the trap
#12913 fixed for
CircuitState.(8 of these are the new
team_service_test.py; see the note on the 5 failuresbelow.)
Both backends import through the shim and configure cleanly:
Consumer suites:
The 3 backend failures are
rbac_denial_audit_test.py::TestAuditVocabulary,red on
Dev_new_guiitself since #13130 relocatedmodels/audit.py. They areunrelated to this change and are fixed in PR #13163. For the same reason,
models/base_test.py's 5 failures in the shared run are pre-existing (_ROOToff-by-one from #13126) and also fixed in #13163. Merge order between the two
PRs does not matter; neither touches the other's files.
isort,black --line-length=120andflake8 --config=.flake8clean on allfour touched files.
Note
Importing the SLM package during verification auto-generated a
.slm_keysfile into the worktree (it is gitignored, so it was never committable). It was
removed, and the remaining runs used throwaway
SLM_SECRET_KEY/SLM_ENCRYPTION_KEYvalues per #13090's guidance. Both worktrees confirmedclean of key material.
Model Used
Claude Opus 5 (1M context)