Move POI alerts to FYI

This commit is contained in:
2026-01-10 19:35:55 +00:00
parent c13a4f3247
commit c28e3ecc4b
2 changed files with 55 additions and 28 deletions

View File

@@ -327,6 +327,7 @@ final class ContextOrchestrator: NSObject, ObservableObject {
if pois.isEmpty { if pois.isEmpty {
logger.info("no points of interests found") logger.info("no points of interests found")
} }
// POIs are FYI-only; do not compete for the right-now winner.
for poi in pois.prefix(2) { for poi in pois.prefix(2) {
let subtitle = poiSubtitle(for: poi) let subtitle = poiSubtitle(for: poi)
let confidence = min(max(poi.confidence, 0.0), 1.0) let confidence = min(max(poi.confidence, 0.0), 1.0)
@@ -344,7 +345,6 @@ final class ContextOrchestrator: NSObject, ObservableObject {
actions: ["DISMISS"] actions: ["DISMISS"]
) )
poiItems.append(item) poiItems.append(item)
rightNowCandidates.append(.init(item: item, confidence: confidence, isEligibleForRightNow: true))
} }
case .failure(let error): case .failure(let error):
fetchFailed = true fetchFailed = true
@@ -402,7 +402,14 @@ final class ContextOrchestrator: NSObject, ObservableObject {
return return
} }
let eligibleUnsuppressed = rightNowCandidates.filter { ranked in let poiCandidateCount = rightNowCandidates.filter { $0.item.type == .poiNearby }.count
if poiCandidateCount > 0 {
logger.warning("dropping poi candidates from right-now ranking count=\(poiCandidateCount)")
}
let eligibleUnsuppressed = rightNowCandidates
.filter { $0.item.type != .poiNearby }
.filter { ranked in
!store.isSuppressed(id: ranked.item.id, type: ranked.item.type, now: nowEpoch) !store.isSuppressed(id: ranked.item.id, type: ranked.item.type, now: nowEpoch)
} }

View File

@@ -45,7 +45,7 @@ struct OrchestratorView: View {
Button("Recompute Now") { orchestrator.recomputeNow() } Button("Recompute Now") { orchestrator.recomputeNow() }
} }
Section("Feed") { Section("Winner") {
if let feed = orchestrator.lastFeed, let winner = feed.winnerItem() { if let feed = orchestrator.lastFeed, let winner = feed.winnerItem() {
Text(winner.title) Text(winner.title)
.font(.headline) .font(.headline)
@@ -54,14 +54,33 @@ struct OrchestratorView: View {
.font(.subheadline) .font(.subheadline)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} }
Text("type \(winner.type.rawValue) • prio \(String(format: "%.2f", winner.priority)) • ttl \(winner.ttlSec)s") LabeledContent("Type") { Text(winner.type.rawValue) }
LabeledContent("Bucket") { Text(winner.bucket.rawValue) }
LabeledContent("Priority") { Text(String(format: "%.2f", winner.priority)) }
LabeledContent("TTL") { Text("\(winner.ttlSec)s") }
if let poiType = winner.poiType {
LabeledContent("POI type") { Text(poiType.rawValue) }
}
if let startsAt = winner.startsAt {
LabeledContent("Starts at") { Text("\(startsAt)") }
}
LabeledContent("ID") {
Text(winner.id)
.font(.caption) .font(.caption)
.textSelection(.enabled)
}
} else {
Text("No winner yet")
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
}
if feed.feed.count > 1 {
Divider()
} }
Section("Feed") {
if let feed = orchestrator.lastFeed {
if feed.feed.isEmpty {
Text("No feed items yet")
.foregroundStyle(.secondary)
} else {
ForEach(feed.feed, id: \.id) { item in ForEach(feed.feed, id: \.id) { item in
VStack(alignment: .leading, spacing: 6) { VStack(alignment: .leading, spacing: 6) {
HStack { HStack {
@@ -85,6 +104,7 @@ struct OrchestratorView: View {
} }
.padding(.vertical, 4) .padding(.vertical, 4)
} }
}
} else { } else {
Text("No feed yet") Text("No feed yet")
.foregroundStyle(.secondary) .foregroundStyle(.secondary)