Rip out Ollama: direct_route only, no LLM layer
Pete moves to a remote host without Ollama access. Every source must declare a direct_route channel; the classifier, explainer, semantic dedup, !explain summaries, feed_hint, and the recent_headlines / classification_log tables are gone. Deterministic dedup (canonical URL, headline_norm, per-channel cooldown) remains.
This commit is contained in:
@@ -19,16 +19,14 @@ matrix:
|
||||
|
||||
func TestLoadValid(t *testing.T) {
|
||||
yaml := validMatrix + `
|
||||
ollama:
|
||||
base_url: "http://localhost:11434"
|
||||
model: "gemma4:27b"
|
||||
timeout_seconds: 60
|
||||
storage:
|
||||
db_path: "/tmp/test.db"
|
||||
sources:
|
||||
- name: "Test Source"
|
||||
feed_url: "https://example.com/rss"
|
||||
tier: 1
|
||||
poll_interval_minutes: 20
|
||||
direct_route: "tech"
|
||||
enabled: true
|
||||
`
|
||||
cfg := loadFromString(t, yaml)
|
||||
@@ -39,15 +37,15 @@ sources:
|
||||
if cfg.Matrix.UserID != "@pete:example.org" {
|
||||
t.Errorf("user_id = %q", cfg.Matrix.UserID)
|
||||
}
|
||||
if cfg.Ollama.TimeoutSeconds != 60 {
|
||||
t.Errorf("timeout = %d, want 60", cfg.Ollama.TimeoutSeconds)
|
||||
}
|
||||
if len(cfg.Sources) != 1 {
|
||||
t.Fatalf("sources = %d, want 1", len(cfg.Sources))
|
||||
}
|
||||
if cfg.Sources[0].Name != "Test Source" {
|
||||
t.Errorf("source name = %q", cfg.Sources[0].Name)
|
||||
}
|
||||
if cfg.Sources[0].DirectRoute != "tech" {
|
||||
t.Errorf("direct_route = %q, want tech", cfg.Sources[0].DirectRoute)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvVarExpansion(t *testing.T) {
|
||||
@@ -60,9 +58,6 @@ matrix:
|
||||
password: "${TEST_PETE_PASS}"
|
||||
channels:
|
||||
tech: "!tech:example.org"
|
||||
ollama:
|
||||
base_url: "http://localhost:11434"
|
||||
model: "gemma4:27b"
|
||||
storage:
|
||||
db_path: "/tmp/test.db"
|
||||
sources: []
|
||||
@@ -76,15 +71,14 @@ sources: []
|
||||
|
||||
func TestDefaults(t *testing.T) {
|
||||
yaml := validMatrix + `
|
||||
ollama:
|
||||
base_url: "http://localhost:11434"
|
||||
model: "gemma4:27b"
|
||||
storage:
|
||||
db_path: "/tmp/test.db"
|
||||
sources:
|
||||
- name: "S"
|
||||
feed_url: "https://example.com/rss"
|
||||
tier: 1
|
||||
poll_interval_minutes: 20
|
||||
direct_route: "tech"
|
||||
enabled: true
|
||||
`
|
||||
cfg := loadFromString(t, yaml)
|
||||
@@ -95,9 +89,6 @@ sources:
|
||||
if cfg.Matrix.DisplayName != "Pete" {
|
||||
t.Errorf("display_name default = %q, want Pete", cfg.Matrix.DisplayName)
|
||||
}
|
||||
if cfg.Ollama.TimeoutSeconds != 30 {
|
||||
t.Errorf("timeout default = %d, want 30", cfg.Ollama.TimeoutSeconds)
|
||||
}
|
||||
if cfg.Posting.MinIntervalSeconds != 300 {
|
||||
t.Errorf("min_interval default = %d, want 300", cfg.Posting.MinIntervalSeconds)
|
||||
}
|
||||
@@ -110,27 +101,6 @@ sources:
|
||||
if cfg.Storage.RecentWindowHours != 24 {
|
||||
t.Errorf("recent_window default = %d, want 24", cfg.Storage.RecentWindowHours)
|
||||
}
|
||||
if cfg.Storage.ClassificationLogDays != 7 {
|
||||
t.Errorf("classification_log default = %d, want 7", cfg.Storage.ClassificationLogDays)
|
||||
}
|
||||
if cfg.Sources[0].PollIntervalMinutes != 20 {
|
||||
t.Errorf("poll_interval default = %d, want 20", cfg.Sources[0].PollIntervalMinutes)
|
||||
}
|
||||
}
|
||||
|
||||
// shortMatrix returns a minimal valid matrix block for validation error tests.
|
||||
func shortMatrix(overrides string) string {
|
||||
base := `
|
||||
matrix:
|
||||
homeserver: "https://h"
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
`
|
||||
if overrides != "" {
|
||||
return overrides
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
func TestValidationErrors(t *testing.T) {
|
||||
@@ -143,7 +113,6 @@ matrix:
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {base_url: "http://l", model: "m"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
`},
|
||||
{"missing user_id", `
|
||||
@@ -151,7 +120,6 @@ matrix:
|
||||
homeserver: "https://h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {base_url: "http://l", model: "m"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
`},
|
||||
{"missing password", `
|
||||
@@ -159,7 +127,6 @@ matrix:
|
||||
homeserver: "https://h"
|
||||
user_id: "@p:h"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {base_url: "http://l", model: "m"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
`},
|
||||
{"no channels", `
|
||||
@@ -167,25 +134,6 @@ matrix:
|
||||
homeserver: "https://h"
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
ollama: {base_url: "http://l", model: "m"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
`},
|
||||
{"missing ollama base_url", `
|
||||
matrix:
|
||||
homeserver: "https://h"
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {model: "m"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
`},
|
||||
{"missing ollama model", `
|
||||
matrix:
|
||||
homeserver: "https://h"
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {base_url: "http://l"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
`},
|
||||
{"missing db_path", `
|
||||
@@ -194,7 +142,6 @@ matrix:
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {base_url: "http://l", model: "m"}
|
||||
storage: {}
|
||||
`},
|
||||
{"invalid tier", `
|
||||
@@ -203,12 +150,14 @@ matrix:
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {base_url: "http://l", model: "m"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
sources:
|
||||
- name: "S"
|
||||
feed_url: "https://e.com/rss"
|
||||
tier: 5
|
||||
poll_interval_minutes: 20
|
||||
direct_route: "tech"
|
||||
enabled: true
|
||||
`},
|
||||
{"missing source name", `
|
||||
matrix:
|
||||
@@ -216,11 +165,42 @@ matrix:
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {base_url: "http://l", model: "m"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
sources:
|
||||
- feed_url: "https://e.com/rss"
|
||||
tier: 1
|
||||
poll_interval_minutes: 20
|
||||
direct_route: "tech"
|
||||
enabled: true
|
||||
`},
|
||||
{"enabled source missing direct_route", `
|
||||
matrix:
|
||||
homeserver: "https://h"
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
sources:
|
||||
- name: "S"
|
||||
feed_url: "https://e.com/rss"
|
||||
tier: 1
|
||||
poll_interval_minutes: 20
|
||||
enabled: true
|
||||
`},
|
||||
{"direct_route not in channels", `
|
||||
matrix:
|
||||
homeserver: "https://h"
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
sources:
|
||||
- name: "S"
|
||||
feed_url: "https://e.com/rss"
|
||||
tier: 1
|
||||
poll_interval_minutes: 20
|
||||
direct_route: "gaming"
|
||||
enabled: true
|
||||
`},
|
||||
}
|
||||
|
||||
@@ -237,37 +217,25 @@ sources:
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirectRouteNullable(t *testing.T) {
|
||||
func TestDisabledSourceSkipsDirectRouteCheck(t *testing.T) {
|
||||
// A disabled source without direct_route must not fail validation.
|
||||
yaml := `
|
||||
matrix:
|
||||
homeserver: "https://h"
|
||||
user_id: "@p:h"
|
||||
password: "pw"
|
||||
channels: {tech: "!t:e"}
|
||||
ollama: {base_url: "http://l", model: "m"}
|
||||
storage: {db_path: "/tmp/t.db"}
|
||||
sources:
|
||||
- name: "Direct"
|
||||
- name: "Off"
|
||||
feed_url: "https://e.com/rss"
|
||||
tier: 1
|
||||
direct_route: "politics"
|
||||
enabled: true
|
||||
- name: "LLM"
|
||||
feed_url: "https://e.com/rss2"
|
||||
tier: 1
|
||||
direct_route: null
|
||||
enabled: true
|
||||
poll_interval_minutes: 20
|
||||
enabled: false
|
||||
`
|
||||
cfg := loadFromString(t, yaml)
|
||||
|
||||
if cfg.Sources[0].DirectRoute == nil {
|
||||
t.Fatal("direct source should have non-nil DirectRoute")
|
||||
}
|
||||
if *cfg.Sources[0].DirectRoute != "politics" {
|
||||
t.Errorf("direct_route = %q, want politics", *cfg.Sources[0].DirectRoute)
|
||||
}
|
||||
if cfg.Sources[1].DirectRoute != nil {
|
||||
t.Errorf("null source should have nil DirectRoute, got %v", cfg.Sources[1].DirectRoute)
|
||||
if cfg.Sources[0].DirectRoute != "" {
|
||||
t.Errorf("expected empty direct_route, got %q", cfg.Sources[0].DirectRoute)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user