Repository navigation
Umbrella: canonical-source duplication — concepts with no single definition, where the copies have already drifted #13916
Copy link
Copy link
Open
7 / 237 of 23 issues completedOpen
7 / 237 of 23 issues completed
Copy link
Labels
area: canonical-enumsWave 2 · cluster T — Canonical enums & duplicationWave 2 · cluster T — Canonical enums & duplicationbackendfrontendinfrastructureumbrellaEpic/umbrella tracking issue grouping member issuesEpic/umbrella tracking issue grouping member issues
Milestone
Description
Activity
New child finding: #14194 — the agent roster is hardcoded in both
.claude/agents/*.mdandAGENT_TIER_MAPinautobot-backend/agent_tier_classifier.py, drifted 3 agents one way and 9 the other. Fits this umbrella's pattern exactly, including the guard-test requirement (#6689 regrew to 15 without one).Filed #14584: the
health_collector_state_change_test.py/ ansible-mirror pair drifted silently (caught by accident in PR #14576, closing #14535/#14538) and has no guard test — same shape as this umbrella's wave items. Not added as a formal child task here since it's a single small file pair, but linking for visibility.- added sub-issues
on Sep 1, 2026 - addedarea: canonical-enumsWave 2 · cluster T — Canonical enums & duplicationWave 2 · cluster T — Canonical enums & duplicationumbrellaEpic/umbrella tracking issue grouping member issuesEpic/umbrella tracking issue grouping member issues
on Sep 1, 2026 19 remaining items
- added 5 commits that reference this issue
on Oct 5, 2026 - added sub-issues
on Oct 10, 2026
Metadata
Metadata
Assignees
Labels
area: canonical-enumsWave 2 · cluster T — Canonical enums & duplicationWave 2 · cluster T — Canonical enums & duplicationbackendfrontendinfrastructureumbrellaEpic/umbrella tracking issue grouping member issuesEpic/umbrella tracking issue grouping member issues
Summary
Five findings that share one cause: a concept has no single authoritative definition, so subsystems each
keep their own copy, and the copies drift. Every one was discovered the same way — someone needed a list
that already existed elsewhere and had nothing telling them so.
This is not a tidiness umbrella. Each item has already produced a production defect or made one
undiagnosable.
The pattern, stated once
A canonical source exists (or should), a second copy is written in good faith, nothing compares them, and
the divergence surfaces months later as a bug in an unrelated subsystem. #13512 is the worked example: the
audio-extension allowlist existed in three modules, one of them a security boundary, and the copies had
already drifted apart before anyone looked.
Task tree
Wave 1 — copies that already disagree (a live divergence, not a latent one)
api/knowledge.pyaccepts.mkvthat thecanonical
ALLOWED_AUDIO_EXTENSIONSrejects;audio_connector.pyomits.mp4/.webm. One of thesepaths is an upload boundary, so reconciling changes what the system admits — a decision, not a
refactor. Do first: it is the only item where the copies are known to differ in behaviour today.
Wave 2 — canonical source exists and is not used
autobot-backenditself.Discovery hides it, so nothing fails loudly. Directly caused the CRITICAL(deploy): update rewrites 2000+ .py files under the live interpreter — 22-minute window where late first-imports raise ImportError for symbols that exist #13539 celery bug (the updater had no
authoritative "what must restart after a sync" and used a hand-written list that omitted celery, which
then served 7-day-old code across ten deploys). depends on nothing; unblocks the durable form of
CRITICAL(deploy): update rewrites 2000+ .py files under the live interpreter — 22-minute window where late first-imports raise ImportError for symbols that exist #13539's fix.
Severityexists atautobot_shared/status_enums.py:73and its own docstringclaims analytics, code-intelligence and logging.
ce849accfdemigrated 2 enums; a systematic ASTscan found 15 more — including
ConfidenceLevelin four files and four enums thatapi/schemas_analytics.pyre-declares fromcode_intelligence/. Inventory posted on the issue.Wave 3 — no canonical source has been chosen yet
others and needs an architecture decision before any consolidation, so it should not block Waves 1-2.
ChromaDB with no authority rule. Extends this umbrella from duplicated definitions to duplicated
runtime data, where the same cause has already destroyed user state (knowledge: browser empty + 'unvectorized on every reload' — facts (Redis) wiped 43→0 while 22 ChromaDB vectors remain; facts not durably persisted; vectorized status read from Redis flag not the vector store #12733: 43 facts → 0 while 22
vectors survived). Needs an architecture decision (which store is authoritative for knowledge facts),
so like canonical(frontend): no single backend contract — 8 independent HTTP clients (2 generic) + 22 raw fetch sites, and generated api.ts is bypassed (4 importers vs 74 hand-typed responses) and stale (2424 vs 2152 paths) #12363 it should not block Waves 1-2.
Reference — the worked example
SecurityConstants.ALLOWED_AUDIO_EXTENSIONS,plus a guard test (
repo_tests/audio_extension_allowlist_test.py) that fails when a fourth literalcopy appears. It also documented the two sets it deliberately left alone and tracked them separately as
security(media): audio-extension allowlist has already drifted — knowledge ingestion accepts .mkv the upload boundary rejects, audio connector omits .mp4/.webm #13615, rather than silently widening scope. This is the shape every item here should take.
Acceptance criteria
The umbrella closes when every child closes and these hold — none is owned by an individual child:
audio_extension_allowlist_test.py:a test that fails when a new duplicate of the canonical definition appears. Without it the count regrows —
refactor(types): consolidate 15+ Severity/RiskLevel/Level enums onto constants/status_enums.py:Severity #6689 consolidated 15+ severity enums and 15 more exist today, which is the proof.
scale, a genuinely distinct concept sharing a noun), the guard test names it and says why.
Capabilityis defined in four places with different members and should stay that way; that belongs written down.
what the system accepts or rejects — that is an owner decision recorded on the issue before the change,
not a side effect of a refactor.
to find it without knowing it exists — the reason every one of these was written twice.
Deliberately excluded
Capability(4 definitions, different members — distinct concepts sharing a noun) and three-pointLOW/MEDIUM/HIGH scales that coincide without being related. Listed so future scans do not re-raise them.
the checker compares directories instead of asking the role what it deploys — but they are tracked under
Umbrella: silent failures and telemetry gaps — 4 incidents where systemctl said active and the service was not working #13852 with the observability findings and should not be double-assigned.
Why grouped
Individually each reads as tech debt and gets deprioritised. Together they are one structural gap with a
measurable cost already paid: a security boundary that drifted (#13512/#13615), a week of stale workers
(#13539 via #13915), and a severity consolidation that regrew to 15 duplicates after being "finished"
(#6689 → #13597).