- in a wing, an ingest that writes no source page is an error: the note goes to
raw/failed with the warnings in log.md instead of leaving the inbox as
'processed' (model returned [], only invalid types, only clashing entities)
- the wing's source path is deterministic, so Resolve no longer redirects a
source onto another note's page because the model gave both the same title
('Home'); that overwrote the hash and the text
- a batch tie between concept and entity prefers the page already on disk, so
its update is not lost; the wing's own source page keeps its slug even when a
foreign page shares it
- brain_pending lists an unreadable (over-cap) note with the reason instead of
dropping it; the client filter's 4 KiB match-span limit is documented
Each has a test that fails without it (mutation-checked).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Views of each chunk: as is; NFKD + marks/format/fillers dropped + Cyrillic/Greek
lookalikes mapped + dashes normalised, with whitespace collapsed (acme corp,
\s) or removed (acme-\nclient); and a soft hyphen read as a dash. Chunks of 1 MiB
with a 4 KiB overlap bound the folding's allocation (it was ~14x the input: 919
MiB for a 64 MiB note). Documented limits: leetspeak, punctuation splits,
encodings and homoglyphs outside a small table. Mutation-checked.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- client pattern is matched against the text and against an NFKC-folded,
format-character-free, dash-normalised, whitespace-free form
(non-breaking hyphen, zero-width characters, soft hyphen, line splits,
fullwidth letters). x/text/unicode/norm was already in the module graph as an
indirect dependency; this makes it direct, no new download.
- folder/frontmatter wing names must be ASCII (strings.ToLower folds the Kelvin
sign to 'k') and must not be sources/concepts/entities/wiki; such names are
never proposed as a wing, and a reserved default is a startup error
Mutation-checked.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
No model. A subfolder/frontmatter wing must be a plain name of an existing wing
and then places; conflicting signals and client-marker text park; everything
else goes to the default wing. Wings are read from disk per decision.
Mutation-checked.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
From the independent review of #207:
- parked notes are created O_EXCL with -2,-3 suffixes (same-named notes from
different subfolders were overwritten and their originals deleted)
- proposed_wing is emitted only if a plain wing name; a note's own proposal_*
keys are dropped so they cannot outrank the resolver's (first-wins reads)
- CRLF notes: wing: key honoured, one valid frontmatter block on parking
- KnownWings skips wiki dirs that are not canonical lower-case names
- adds the wingmigrate dry-run/apply command
Each fix has a test that failed first and a mutant that fails it.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Off by default (retired layout unchanged). On: eligibility from
classification.yaml, local ingest LLM as classifier, BM25 as cross-check,
INGEST_WING_THRESHOLD (default 0.9, rejected outside [0,1]). Build failure
is fatal when explicitly enabled.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A first backtest showed BM25 summed over a wing's top hits favours big wings
(0/4 agreement). Best-page scoring is volume-robust; pinned by a test that
failed before the change.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Explicit subfolder/frontmatter wins; otherwise a classifier and an
independent scorer must agree above a threshold on a known, eligible wing.
Anything else is an Exception for a human. Never creates a wing, never
assigns an ineligible (client/untagged) wing. Mutation-checked: dropping the
eligibility, known-wing, scorer, threshold or conflict check fails a test.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>