Adds a parallel LLM path that reviews the whole org snapshot — Preseem
APs, SNMP signals, backhaul, agents, and the insight types the rules
already covered — and emits novel observations as ai_observation
insights (source=ai). Existing rule-based insights and per-insight
enrichment continue unchanged.
- lib/towerops/llm/network_snapshot.ex builds the bounded snapshot
- lib/towerops/llm/network_insight_prompt.ex builds the prompt and
parses the LLM's JSON observations array
- lib/towerops/workers/ai_network_insight_worker.ex runs nightly at
03:30 UTC (after the rule pass + per-insight enrichment) and on
the superuser regenerate button
- preseem/insight.ex extends @valid_types with "ai_observation" and
@valid_sources with "ai"
- insights_live/index.ex includes the new worker in the regen list
and adds an "AI" source badge style
Bumps the SnmpKit Manager timeout-options test threshold from 500ms
to 3000ms (was flaking on loaded dev machines), and scopes
list_unenriched_insights/1 assertion in insights_test:573 to the
test's org so cross-suite leaks don't fail the count.
Migrate three pure-function modules from Elixir to Gleam:
- polling_offset: deterministic hash-based polling offset (pure Gleam, no FFI)
- changelog_parser: text parsing logic in Gleam, thin Elixir wrapper for File I/O
- user_agent_parser: regex-based UA parsing in Gleam with Erlang FFI for
atom-keyed map conversion
Add gleam_regexp dependency for regex support in Gleam modules.
Update all call sites and tests to use Gleam module atoms.
Reviewed-on: graham/towerops-web#103
Set up mix_gleam archive, gleam_stdlib, and gleeunit deps. Add Gleam
compiler to all Dockerfiles, CI workflows, nix shell, and .tool-versions.
Rewrite Numeric, QueryHelpers, and URLValidator from Elixir to Gleam with
full ExUnit test coverage. Update all callers to use the Gleam modules
directly via :towerops@module syntax. Remove duplicate sanitize_like/1
private functions in snmp.ex and trace.ex.
Reviewed-on: graham/towerops-web#98
- Remove all 25ms and 50ms sleeps from agent_channel_test
- Add poll_until helper for async DB operations (early exit on success)
- Reduce timeout test sleeps from 100ms to 60ms
- Reduce polling delays from 10ms to 5ms in multiple tests
- Remove unnecessary timestamp and background task sleeps
- Reduce circuit breaker recovery sleep from 150ms to 110ms
Performance: 30.3s → 28.3s (6.6% faster)
Total improvement from baseline: 52s → 28.3s (45.6% faster)
Test Performance Improvements:
- Reduce SNMP test timeouts from 2000ms to 100ms (walk and bulk tests)
- Reduce AgentChannelTest assert_push timeouts from 2000ms to 1000ms
- Reduce Process.sleep delays: 200ms → 50ms, 100ms → 25ms
- Results: Top 10 slowest 14.1s → 10.5s (26% faster)
CI Test Fixes:
- MIBStubsTest: Increase performance threshold from 10ms to 20ms for slower CI runners
- LoginHistoryCleanupWorkerTest: Fix boundary test using 364 days instead of 365
to account for timing difference between test setup and worker execution
Overall: 7422 tests, 0 failures, suite runs in 57.4s
- Fetch MAC address from Gaiia custom fields during inventory sync
- Remove name-based device matching (model names caused false matches)
- Keep IP-only matching for device suggestions
- Make unmapped rows clickable in the Gaiia mapping table
- Point authenticated logo link to /dashboard instead of /orgs
- Fix flaky monitor test teardown race condition
- Fix CLOAK_KEY placeholder in nix shell (invalid base64)
- Fix error HTML test assertion to match actual template
- Fix Gaiia sync: read 'subnet' field instead of 'block' for IP blocks
- Fix Gaiia sync: extract nested status name from subscription objects
- Fix security headers tests for environment detection
- Fix mobile auth tests to use raw_token
- Fix LiveView test assertions to match actual template content
- Fix SNMP config test expectations for test environment
- Refactor: resolve all Credo complexity/nesting issues
- Extract helper functions in NetBox sync, VISP sync, Sonar sync
- Flatten nested conditionals in settings, integrations, alerts
- Use with/validate_present pattern for connection testing
Improve coverage from 37.97% to 40.64% with tests for:
- PDU types in SNMPv3 messages (get_next, get_response, set, getbulk)
- Context engine ID and context name (empty, non-empty, both)
- Message max size variations (minimum 484, custom values)
- Multiple varbinds in v3 messages
- Error responses with various error_status values (0-5)
- Reportable flag variations (true/false)
- USM security model
- All SNMP value types (counter64, gauge32, ip_address, opaque, oid)
- Exception values (no_such_object, no_such_instance, end_of_mib_view)
- Message ID edge cases (0, max 2147483647)
- Discovery message consistency
Tests verify message encoding completes without crashes
even when V3 security processing is involved.
Coverage: 1,391 → 1,419 tests, all passing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added complete test coverage for MIB.Error module (16.13% -> target 100%):
**Error Creation:**
- All supported error types (syntax, semantic, import, type, constraint, etc.)
- Error creation with line and column information
- Error creation with context maps
- Suggestion generation for common mistakes
**Error Types Tested:**
- unexpected_token with various combinations (expected/actual/value)
- unexpected_eof with expected values
- unterminated_string
- invalid_number and invalid_identifier
- file_not_found with path
- import_error with symbol and module
- duplicate_definition with name
- Generic error types
**Suggestion Generation:**
- MAX-ACCESS vs ACCESS typo
- deprecated 'mandatory' vs 'current'
- OBJECT-TYPE vs OBJECT-IDENTITY confusion
- Unterminated string hints
- File not found with RFC/MIB name detection
- Import error dependency hints
**Error Formatting:**
- Format with/without line and column
- Format with/without suggestions
- Multiple suggestion formatting
- Edge cases (nil values, empty strings, non-standard types)
**Edge Cases:**
- All nil fields
- Large line numbers
- Zero/negative line/column values
- Various context data types
- Mixed token value types
- Empty options handling
53 new tests added
Test count: 1,211 -> 1,264 (all passing)
Added comprehensive test coverage for previously untested functionality:
- IP address parsing (valid IPs, invalid inputs, IPv6 rejection)
- Zero-filling behavior for incomplete IPs (Erlang :inet standard)
- Type inference for all SNMP types (integers, strings, lists, booleans, nulls)
- Value decoding for all SNMP types (strings, integers, IPs, OIDs, exceptions)
- Value encoding with type inference and validation controls
- Unsigned32 validation (valid ranges, overflow, underflow)
- Coercion edge cases (IP addresses, unsigned32, octet_string, OIDs, booleans)
Fixes:
- Corrected type inference expectation for large integers (returns :unsigned32)
- Fixed boolean assertion to use equality check instead of pattern match
- Documented :inet.parse_address zero-fill behavior for incomplete IPs
Total: 97 tests, all passing
Fixed 2 failing tests in HostParser that were using unreliable hostname resolution. Changed tests to use malformed IP addresses that will always fail validation consistently.
Added tests for SnmpKit.SNMP bang methods (get_bulk!, bulk_walk!) which have actual implementation logic beyond delegation.
All 954 SNMPkit tests now pass (0 failures).
- Remove unused Ecto.Query import from device_poller_worker_test
- Update route paths from /orgs/:slug to /dashboard after navigation refactor
- Fix HostParser tests to match actual hostname resolution behavior
- Update UserAuth redirect assertions to expect /dashboard instead of /devices
- Fix DashboardLiveTest missing organization context
- Fix OrgLive.NewTest to verify organization creation correctly
All 4850 tests now passing with zero failures and zero warnings.
Optimized the 10 slowest tests from 4.7s to ~2.5s (47% reduction):
Property-based tests:
- Reduced max_runs from 50/100 to 10 iterations (still provides good coverage)
- ApiTokensTest: 3 property tests now run 10 iterations instead of 50-100
- EquipmentTest: 3 property tests now run 10 iterations instead of 50-100
Network timeout tests:
- Manager IPv6 tests: reduced timeout from 100ms to 25ms (75% faster)
- Tests already expect failures, so shorter timeouts don't affect validity
Database optimization:
- MemoryPoolTest: converted individual insert to bulk insert_all
- Added proper updated_at timestamp for MemoryPool (required by schema)
Async processing:
- AgentLatencyEvaluatorTest: reduced Process.sleep from 500ms to 100ms
- Worker processes reliably within 100ms threshold
All 3,686 tests pass with no failures.
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>