summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-13 14:28:43 +0300
committerPaul Buetow <paul@buetow.org>2026-05-13 14:28:43 +0300
commita73b7973531f2b8632269a8c8359acf69ee61f45 (patch)
tree5f9e96b893fcf1a2ca774c76276a07ecfa565711 /internal
parent27b94f917064948fa33141309a3f08deb40ffde2 (diff)
add compile-time interface assertions for public types (task c4)
Extend the var _ Interface = (*Concrete)(nil) coverage started in j3 to cover the remaining public types not yet guarded: - *file.FdFile → file.File (file/file.go) - streamrow.Row → globalfilter.Candidate (streamrow/row.go; adds globalfilter import — no cycle since globalfilter does not import streamrow) - *streamrow.RingBuffer → eventstream.Source (tui/eventstream/ringbuffer.go; already a type alias for streamrow.RingBuffer) - *probemanager.Manager → tui/probes.Manager (tui/probes/model.go) - All 9 generated *types.*Event types → event.Event in the new file internal/event/interface_assertions.go (non-generated, lives in the event package which already imports types, so no new import cycle) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal')
-rw-r--r--internal/event/interface_assertions.go44
-rw-r--r--internal/file/file.go8
-rw-r--r--internal/streamrow/row.go10
-rw-r--r--internal/tui/eventstream/ringbuffer.go8
-rw-r--r--internal/tui/probes/model.go8
5 files changed, 78 insertions, 0 deletions
diff --git a/internal/event/interface_assertions.go b/internal/event/interface_assertions.go
new file mode 100644
index 0000000..77a43ea
--- /dev/null
+++ b/internal/event/interface_assertions.go
@@ -0,0 +1,44 @@
+package event
+
+import "ior/internal/types"
+
+// --- compile-time interface satisfaction assertions ---
+//
+// Every generated concrete event type in internal/types must satisfy the Event
+// interface (which composes EventIdentity and EventLifecycle). These assertions
+// live in the event package rather than in the generated file so they are not
+// overwritten by mage generate. The event package already imports types, so no
+// new import cycle is introduced.
+
+var (
+ // *types.OpenEvent is the most common event type; it carries open-syscall
+ // enter-event data (fd, flags, pathname).
+ _ Event = (*types.OpenEvent)(nil)
+
+ // *types.NullEvent is used for tracepoints that carry no extra payload
+ // beyond the base header fields.
+ _ Event = (*types.NullEvent)(nil)
+
+ // *types.FdEvent carries a single file-descriptor field (close, dup, etc.).
+ _ Event = (*types.FdEvent)(nil)
+
+ // *types.RetEvent is the exit-side event for all syscalls; it carries the
+ // kernel return value.
+ _ Event = (*types.RetEvent)(nil)
+
+ // *types.NameEvent carries a single filename field (unlink, mkdir, etc.).
+ _ Event = (*types.NameEvent)(nil)
+
+ // *types.PathEvent carries a pathname field for path-only syscalls.
+ _ Event = (*types.PathEvent)(nil)
+
+ // *types.FcntlEvent carries the fcntl command and argument fields.
+ _ Event = (*types.FcntlEvent)(nil)
+
+ // *types.Dup3Event carries the old and new file-descriptor fields for dup3.
+ _ Event = (*types.Dup3Event)(nil)
+
+ // *types.OpenByHandleAtEvent carries the mount-fd and flags for
+ // open_by_handle_at syscalls.
+ _ Event = (*types.OpenByHandleAtEvent)(nil)
+)
diff --git a/internal/file/file.go b/internal/file/file.go
index fc9c320..f933d69 100644
--- a/internal/file/file.go
+++ b/internal/file/file.go
@@ -217,3 +217,11 @@ func (f pathnameFile) String() string {
return sb.String()
}
+
+// --- compile-time interface satisfaction assertions ---
+//
+// *FdFile is the primary public implementation of File used throughout the
+// codebase. The assertion causes a build error if FdFile drifts out of sync
+// with the File interface contract.
+
+var _ File = (*FdFile)(nil)
diff --git a/internal/streamrow/row.go b/internal/streamrow/row.go
index 457fcc0..026aa93 100644
--- a/internal/streamrow/row.go
+++ b/internal/streamrow/row.go
@@ -5,6 +5,7 @@ import (
"time"
"ior/internal/event"
+ "ior/internal/globalfilter"
"ior/internal/types"
)
@@ -121,6 +122,15 @@ func New(seq uint64, pair *event.Pair) Row {
return row
}
+// --- compile-time interface satisfaction assertion ---
+//
+// Row must satisfy globalfilter.Candidate so the TUI eventstream model can
+// pass stream rows directly into Filter.Matches for live filtering. All
+// Candidate methods are defined on the value receiver so both Row and *Row
+// satisfy the interface; we assert the value form as it is the common usage.
+
+var _ globalfilter.Candidate = Row{}
+
// NewWarning creates a synthetic row for non-fatal runtime warnings.
func NewWarning(seq uint64, message string) Row {
now := uint64(time.Now().UnixNano())
diff --git a/internal/tui/eventstream/ringbuffer.go b/internal/tui/eventstream/ringbuffer.go
index 8644b42..8879114 100644
--- a/internal/tui/eventstream/ringbuffer.go
+++ b/internal/tui/eventstream/ringbuffer.go
@@ -15,3 +15,11 @@ const ringBufferCapacity = streamrow.RingBufferCapacity
func NewRingBuffer() *RingBuffer {
return streamrow.NewRingBuffer()
}
+
+// --- compile-time interface satisfaction assertion ---
+//
+// *RingBuffer (= *streamrow.RingBuffer) must satisfy the Source contract so
+// the TUI dashboard and stream views can receive live events without importing
+// the lower-level streamrow package directly.
+
+var _ Source = (*RingBuffer)(nil)
diff --git a/internal/tui/probes/model.go b/internal/tui/probes/model.go
index baf22e8..b7e694f 100644
--- a/internal/tui/probes/model.go
+++ b/internal/tui/probes/model.go
@@ -346,3 +346,11 @@ func truncateText(s string, limit int) string {
}
return string(runes[:limit-3]) + "..."
}
+
+// --- compile-time interface satisfaction assertion ---
+//
+// *probemanager.Manager must satisfy the Manager interface defined in this
+// package. The tui/probes package already imports probemanager, so this
+// assertion adds no new dependency.
+
+var _ Manager = (*probemanager.Manager)(nil)