feat: Activity capability integration + query ergonomics (M6)#35
Merged
Conversation
Make inventory auditable and queryable for operators (issue #34, the final milestone of #15). Audit — platform Activity capability: - ActivityPolicy per inventory kind (12) under config/milo/activity/policies/, with audit rules (create/update/delete, ordered specific→fallback, system users excluded) and event rules keyed on the inventory.miloapis.com/event-type annotation. Mirrors the dns-operator / network-services-operator layout. - Controllers now emit best-effort events.k8s.io/v1 Events on Ready transitions (Normal "Ready", Warning "NotReady" carrying the specific condition reason). Events feed human-readable timelines; conditions remain the machine-readable status. Shared EventRecorder helper in internal/controller/events.go (mirrors conditions.go); a single emit call in each controller's status-patch path covers every exit, including the initial reference-NotFound state so create-then-resolve lifecycles read cleanly. - Display values are carried in inventory.miloapis.com/-prefixed annotations so CEL summary templates stay simple. - RBAC: controller gains create;patch on events.k8s.io Events. - Deployment: config/milo is a kustomize Component pulled in by the milo-integration component (policies only ship where the Activity system runs); POD_NAME wired via downward API for ReportingInstance. Query — operator ergonomics: - docs/querying-and-activity.md: operator guide for kubectl/datumctl queries, topology label selectors, and reading inventory activity (CEL filter examples + a worked Circuit→Provider lifecycle). Tests: - Unit tests for the Ready-transition gate and event construction (annotations, reason/type, regarding, nil-safety, error swallowing). - Existing envtest suite passes unchanged (emission is a no-op when no recorder is wired). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
|
how's my driving @scotwells |
This was referenced Jun 3, 2026
kevwilliams
approved these changes
Jun 4, 2026
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.
Part of #34 (final milestone, M6, of the physical-inventory plan #15). This PR does not close #34 — the milestone also covers
PolicyPreviewfixtures, the printer-column/topology audit, and confirming the activity-scoping model, tracked below.Makes inventory auditable (who changed what, when) and queryable for operators, via the platform Activity capability + kubectl-style query ergonomics. Scope is the
milo-os/inventoryrepo only; client work is downstream (already filed + linked, see below).What's in this PR
Audit — Activity capability integration
ActivityPolicyper kind (12) underconfig/milo/activity/policies/+kustomization.yaml. Each has audit rules (create / update / delete, ordered specific→fallback,system:users excluded, referencing realspec/objectReffields) and two event rules keyed on theinventory.miloapis.com/event-typeannotation. Mirrors the dns-operator / network-services-operator layout.events.k8s.io/v1Events on Ready transitions: NormalReadyand WarningNotReady(carrying the specific condition reason, e.g.ProviderNotFound). Events are emitted in addition to conditions. SharedEventRecorderininternal/controller/events.go(mirrorsconditions.go); one emit call sits in each controller's status-patch path, so it fires on every exit — including the initial reference-NotFoundstate, so create-then-resolve lifecycles read cleanly. Display values ride ininventory.miloapis.com/-prefixed annotations to keep CEL templates simple. Failures are logged and swallowed.create;patchonevents.k8s.ioEvents (regeneratedrole.yaml).config/milois a kustomize Component pulled in bymilo-integration(policies only ship where the Activity system runs).POD_NAMEwired via downward API forReportingInstance. Validated:kustomize buildthrough the milo-integration path renders all 12 policies.Query — ergonomics for operators
docs/querying-and-activity.md— operator guide:kubectl/datumctl getcolumns,topology.inventory.miloapis.com/*label selectors, and reading inventory activity (datumctl activity query --filterCEL examples + a workedCircuit→Providerlifecycle matching the exit criteria).Tests
regarding, nil-safety, error swallowing).go test ./internal/controller/(full envtest suite, 53 specs) passes; emission is a no-op when no recorder is wired, so existing specs are unchanged.Design decisions settled here
defaultnamespace (Kubernetes convention for cluster-scoped subjects; overridable viaINVENTORY_ACTIVITY_NAMESPACE);regardingpoints at the cluster-scoped object. Activities surface to staff/operators (platform-scoped), not per-project surfaces. Still needs confirmation with the Activity service owners — the one genuine unknown.Remaining M6 work (not in this PR; #34 stays open until done)
PolicyPreviewfixtures per policy (audit CRUD + event rules) — validate against a live Activity API.topology.*; Cable and Circuit do not — these are connective assets that can span topology, so single-value labels may not fit. Needs a decision rather than a blind fill.Downstream (already filed + linked off #34)
🤖 Generated with Claude Code