Removes the LLM classifier, the substring 'BM25' scorer, the agreement gate, the backtest and the old migrate/wingmigrate tooling: measured at 2 of 55 pages placed (#208), and the migration was built for the per-wing facts layout this branch replaces. wing now holds the decision types, the Router and KnownWings. INGEST_WING_ROUTING=1 builds the Router (default wing INGEST_DEFAULT_WING=web-clip, client pattern from INGEST_CLIENT_BLOCK or CLAUDE_INGEST_CLIENT_BLOCK); a bad default or pattern is fatal at startup. Watcher tests rewritten for the Router, including a deliberate subfolder into any existing wing, typo'd folders parked, forged-key and edit-while-placing cases. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
54 lines
1.9 KiB
Go
54 lines
1.9 KiB
Go
// Package wing decides which brain wing an incoming raw note belongs to
|
|
// without the human typing it (hyperguild#205, #208).
|
|
//
|
|
// An earlier design classified each note with a local model and cross-checked
|
|
// it with a text score. Measured against pages whose wing a human had chosen,
|
|
// the model was right 60% of the time with a saturated self-reported
|
|
// confidence, and the cross-check was right 11% of the time, so the gate it
|
|
// formed placed 2 of 55 pages (hyperguild#208). The Router that replaced it
|
|
// decides with rules only: a deliberate folder or frontmatter wing, else one
|
|
// default wing; nothing it cannot decide safely is guessed.
|
|
package wing
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
)
|
|
|
|
// Source says how a Decision was reached.
|
|
type Source string
|
|
|
|
const (
|
|
Explicit Source = "explicit" // subfolder or frontmatter named the wing
|
|
Default Source = "default" // no signal; the configured default wing
|
|
Exception Source = "exception" // needs a human
|
|
)
|
|
|
|
// Note is what the Placer sees of an incoming raw note.
|
|
type Note struct {
|
|
Dir string // first subfolder under raw/, "" when dropped at the top
|
|
FrontmatterWing string // `wing:` from the note's frontmatter, "" if absent
|
|
Text string
|
|
}
|
|
|
|
// Decision is the outcome. For an Exception, Wing holds the proposal when
|
|
// there was one (so a reviewer can approve it) and is empty otherwise.
|
|
type Decision struct {
|
|
Wing string
|
|
Source Source
|
|
Confidence float64
|
|
Reason string
|
|
}
|
|
|
|
// Placer decides where a raw note goes. Router is the production
|
|
// implementation; the interface lets the watcher stay ignorant of how.
|
|
type Placer interface {
|
|
Resolve(ctx context.Context, n Note) Decision
|
|
}
|
|
|
|
func exception(w string, conf float64, reason string) Decision {
|
|
return Decision{Wing: w, Source: Exception, Confidence: conf, Reason: reason}
|
|
}
|
|
|
|
func norm(s string) string { return strings.ToLower(strings.TrimSpace(s)) }
|