Commit Graph
50 Commits
Author SHA1 Message Date
kyleandClaude Opus 5.5 c8d0e2b44a run-plan: per-session timeout (SESSION_MAX, default 90 min)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 03:12:26 -07:00
kyleandClaude Opus 5.5 5ce625be33 p5a: split task 06 (too large: looped 3h) into 06-api-pdf and 07-api-cache-pages; old 07 is 08
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 03:12:07 -07:00
kyleandClaude Opus 5.5 6a3b6dab71 run-plan: give opencode an empty stdin (1.15 waits for EOF on a piped stdin and hangs in the background)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 22:38:33 -07:00
kyleandClaude Opus 5.5 7fa5bd21b2 p5a: fix a deadlock in the given TestFetchIf (lock held across a request); run notes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 21:45:57 -07:00
kyleandClaude Opus 5.5 cfde35397a P5a plan: PDF documents — seven Ornith tasks with acceptance tests first
docs/plans/p5a: 01 kind+fetch limits, 02 pdftext child + runner, 03 dcache PDF tables,
04 pdfpool, 05 pdfdoc render (map/pages/grep), 06 api, 07 digest citations, metrics, CLI,
skill, unit, README. Given tests compile against a panic-only skeleton and fail there for the
intended reasons; PDFs for tests are built by internal/pdftest (given), plus two qpdf-encrypted
fixtures.

Owner changes for the run: vendor go-pdfkit/extract v0.3.0 + reader v0.6.0 (pinned via
tools.go until task 02); AGENTS.md, tools/run-plan.sh (enforces a Co-Authored-By trailer for
the model), docs/implementer-log.md, `make gate`; gofmt (whitespace) on clean.go and guard;
TestUnsupportedType uses a zip now that PDFs are supported; requestDeadline 90→210 s and
writeTimeout 120→240 s for the PDF path's worst case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 20:47:38 -07:00
kyleandClaude Opus 5.5 3f2b78d4aa docs: P5a — PDF documents (pure-Go extract in a re-exec'd child, per-page cache, map, pages/grep, 2-worker pool)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 20:19:39 -07:00
kyle 4372673184 p2.7: prometheus /metrics
Default GET /metrics is Prometheus text; JSON stays at /metrics.json
and ?format=json. :8443 needs the metrics caller bearer; loopback
stays open. Restricted callers have no per-caller series and no
tavily:restricted gauge.
2026-09-23 21:49:38 -07:00
kyle c19a58d1e3 docs: P2.7 prometheus /metrics
Design only. JSON stays at /metrics.json and ?format=json.
2026-09-23 21:36:48 -07:00
kyle e62cfc8660 p3: no Tavily daily cap for restricted callers
Restricted searches skip the cap check. Credits land on
tavily:restricted so they never raise the fleet row. Fleet at cap
still falls through.
2026-09-23 16:27:07 -07:00
kyle 1c57845ebd p3: keep original URLs on RRF/dedupe; rerank=false is not a merge
CanonicalURL is the dedupe key only. Hits keep the first source's
original URL, including a trailing slash. Dedupe has the same rule.
2026-09-23 16:04:45 -07:00
kyle b6e1cdf825 p3: map Brave LLM Context; RRF merge; per-source no_rerank
Live llm/context hits live in grounding.generic plus a URL-keyed
sources map, not a sources array. Fan-in uses reciprocal-rank fusion
instead of cosine. no_rerank keeps that source's own order as a prefix.
2026-09-23 16:02:21 -07:00
kyle eb4e46d036 p3: blind titles, cap snippets, equalise k; abort cached dumps
Exempt title from the vendor-token check. Truncate snippets to 160
chars and clip all four packs to the same per-query k. run.py fails
cached replies with a rerun message instead of a config mismatch.
2026-09-23 15:32:45 -07:00
kyle 7558eca46d p3: bake-off collector that refuses a mislabelled dump
run.py records one named config at a time. Sift dumps fail if
sizes.sources_ok does not match --config. Hermes Tavily uses the
live-tool request shape, not sift. Raw dumps stay gitignored.
2026-09-23 15:29:46 -07:00
kyle 35e2356541 p3: actually blind bake-off packs
Rewrite A-D to [{rank, url, title, snippet}] only. Fail closed if
searxng/brave/tavily/hermes appear outside url or snippet. Self-test
and a 28-query fake-dump dry run pass.
2026-09-23 14:13:26 -07:00
kyle 9a8dae3948 p3: harvest 28 bake-off queries with targets and blind protocol
Kyle-approved fleet harvest. Sibling targets (domain/page or open).
Runner labels A-D; mapping stays in a sealed key file until scoring.
2026-09-23 14:09:42 -07:00
kyle 8ca3adec9e cli: do not fall through to ~/.config from a non-default HERMES_HOME
A restricted profile shares the Unix user with the fleet. If its
$HERMES_HOME/sift/client.toml is missing, returning ~/.config/sift
would silently use the fleet key. Non-default HERMES_HOME now pins
the profile path so loadClient errors instead.
2026-09-23 12:39:17 -07:00
kyle 429f6b207e p3: tavily parse errors degrade; retry DNS on search
A 200 with a bad Tavily body is tavily: error, not an empty success
that would cache for the hour. Upstream clients stay in the source
list if DNS is down at boot and retry the pin on Search; /healthz
lists them as unresolved until a pin lands.
2026-09-23 12:22:31 -07:00
kyle f748e695b1 p2.6: warn when permit_restricted has no key
CheckMappings now logs WARN for each permit_restricted name missing
from keys.toml, so a missing straylight-gs key is visible at start
and on reload instead of passing silently.
2026-09-23 12:19:10 -07:00
kyle d7873403ff p3: search API, pinned sources, cache, CLI
POST /v1/search and /v2/search fan in SearXNG, Brave LLM Context, and
Tavily from config-fixed endpoints. Public sources refuse private A
records; SearXNG is a loopback-only client, not the fetch guard.

Cache keys include caller class. Restricted callers search like the
fleet; logs omit query, hosts, URLs, and upstream errors. Degraded
results are not stored. Tavily sends search_depth=basic and drops
answer. Missing keys surface in /healthz.

Default-on sources stay off until the bake-off. Query harvest is not
in this commit.
2026-09-23 12:17:51 -07:00
kyle 3687636ed7 p2.6: partition dcache by caller class; pin restricted workspace
Digest, chunk-embed, and question-embed keys include fleet|restricted so
a fleet caller cannot observe a restricted cache hit. Digest.Run takes
the class from permit_restricted.

A permit_restricted caller whose keys.toml workspace is not
guardian-star is refused at Search (no Honcho request) and flagged at
serve start and keys reload.

docs: P3 restricted callers search like the fleet; cache/logs isolate.
2026-09-23 11:51:39 -07:00
kyle 7be4ed1d43 p2.5: redact reason/err for permit_restricted logs
Guard messages embed the hostname (resolve <host>, no addresses for
<host>). Restricted callers now log a coarse reason class and err=-.
Test dumps slog records and forbids the hostname anywhere in them.

docs: P3 review — fail-closed search, cache class, public dialer
2026-09-23 11:47:37 -07:00
kyle 2d376d3ad1 docs: P3 spec — search API, sources, cache, bake-off
No code. Default-on sources left to the bake-off. Restricted-caller
paid-engine question left open for Kyle.
2026-09-23 11:43:03 -07:00
kyle 85113f9c0b p2.5: log host=- for permit_restricted callers
Scrape, fetch, refused, fetch-failed, and internal lines redact the
host for callers in context.permit_restricted. final_url stays in the
response. Test captures slog records, not the journal.
2026-09-23 11:40:45 -07:00
kyle e36da19f57 p2.4: restricted workspace for permitted callers
guardian-star context is allowed only when the authenticated caller is in
permit_restricted and mapped to that workspace. Fleet callers remapped to it
still refuse. CLI client.toml: SIFT_CLIENT, then $HERMES_HOME/sift, then ~/.config.
2026-09-23 08:33:58 -07:00
kyle 14eb7808ce docs: skill matches shipped P2 (no search, recover, fallback cap)
sift search is P3 and not built — keep web_search until then.
Recover ladder is Wayback then archive.today. digest.fallback
means clean text capped at ~6k tokens.
2026-09-23 06:00:50 -07:00
kyle 767c12c1af p2.3: pin chunk 0, hybrid score, keep question on retry
Question-mode selection always keeps the lead chunk, then fills
the budget by 0.7 cosine + 0.3 term overlap. prompt_version 2.
too-large embed retry no longer halves the question (index 0).
2026-09-23 03:18:29 -07:00
kyle 5dbc7e4094 p2.2: cap embed inputs at 3000 runes, retry too-large 500
Link-heavy chunks estimated under EmbedMaxTok still overflow
Dixie's 2048-token embed slot. Cap every embed input at 3000
runes. A 500 whose body contains 'too large' halves inputs and
retries once. Fallback logs the truncated upstream body.
2026-09-23 03:03:11 -07:00
kyle 16a7d678d3 p2.1: honcho-embed, wayback http/204, memento, keys owner
Embed requests send dixie.embed_model (default honcho-embed).
Wayback accepts http://web.archive.org, rewrites to https, skips
non-200 closest.status. Memento-Datetime is parsed as an HTTP date
and future/garbage values become empty snapshot_at. keys add writes
via temp+fchown/chmod/rename so root does not clobber keys.toml.
Digest fallback is capped at the 6k-token budget.
2026-09-23 02:41:46 -07:00
kyle 2db001e0d7 p2: 120s write timeout and flags after the URL
WriteTimeout 30s was cutting digest mid-flight (queue+fetch+digest)
and tailscale then 502'd. 120s write, 90s handler deadline.
sift fetch URL --question now parses; extra positionals error.
2026-09-23 00:28:59 -07:00
kyle a992216ec0 p2: widen document fence for space and zero-width
Strip U+200B–U+200D, U+2060, U+FEFF before fencing. Match
(?i)<\s*/?\s*document so </ document> cannot sit outside the frame.
2026-09-23 00:09:14 -07:00
kyle ff87a04f94 p2: fence document tags, atomic fleetctx, harden workspace
Neutralise </document and <document in page text. Counters are
atomic.Uint64. Workspace names are [A-Za-z0-9_-] and PathEscaped;
foreign workspace_id rows are dropped. Wayback closest.url must be
https://web.archive.org. archive.today snapshot_at is Memento-Datetime
or null.
2026-09-23 00:01:04 -07:00
kyle 2f9d3d97e6 p2: digest with in-sift FIFO, SQLite caches, Honcho context, recover
Dixie is capped (max_inflight 2, queue_depth 8, queue_wait 20s) and
never queued on llama-server. Streaming chat, thinking off, 45s
fallback to clean. Digest and chunk-embedding caches are
content-addressed SQLite (Honcho context is not cached). Recover
uses the guarded Fetcher. guardian-star is refused in code.
2026-09-22 23:54:49 -07:00
kyleandClaude Opus 5.5 505e113b64 docs: P2 scope line matches §2a caches
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 23:47:24 -07:00
kyleandClaude Opus 5.5 9f8d9f4f13 docs: P2 — bounded in-sift queue; digest + chunk-embedding caches pulled forward
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 23:47:09 -07:00
kyleandClaude Opus 5.5 cb0cb83fb9 docs: P2 spec — digest (bounded, streaming, thinking off), Honcho context (guardian-star refused), recover ladder
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 23:43:40 -07:00
kyle 0598c8985b p1.1: note IPv4-only self-IP assumption
Trace via 1.1.1.1 never learns a delegated v6 prefix.
2026-09-22 23:01:19 -07:00
kyle 447842f860 p1.1: dynamic self-IP deny (DDNS/trace, keep previous, atomic swap)
Discover WAN via ddns:<host> then trace:<url> before listen. Persist to
self_ip.json. Previous addresses stay denied for keep_previous. Failure
keeps the last known set. /healthz reports age and source.
2026-09-22 22:59:08 -07:00
kyle dca635fb62 p1: vendorHash = null when vendor/ is committed
buildGoModule refuses a hashed fetch if vendor/ exists. Keep vendor/;
the check path already uses GOPROXY=off GOFLAGS=-mod=vendor.
2026-09-22 22:27:24 -07:00
kyle fac1462e7b p1: ExecStart must invoke sift serve
P1 split the binary into subcommands. Without `serve`, the unit exits 2
on `unknown command`.
2026-09-22 22:11:28 -07:00
kyleandClaude Opus 5.5 d404657820 docs: P1.1 dynamic self-IP deny (DDNS/trace discovery, keep previous, atomic swap)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 22:06:20 -07:00
kyle 8e3a6cd339 p1: cap jq output, log refusals, fail contract without SDK
jq results are bounded (10k items / output cap) and return 400 when
exceeded. 401/403 log caller, host, and reason. make contract exits 1
unless firecrawl-py is present (SIFT_CONTRACT_SKIP_SDK=1 to skip).
2026-09-22 22:02:38 -07:00
kyle 9444a35322 p1: /v2/scrape, /v1/fetch, auth, CLI, contract tests
Single Fetcher.Fetch on the Guard that holds DenyPrefixes. skipTlsVerification
is ignored. No 502. keys add writes the secret only to --out. Release binary
has no -test-allow-prefix.
2026-09-22 21:54:01 -07:00
kyleandClaude Opus 5.5 6cb206fb27 docs: P1 spec — clean fetch, auth, CLI, contract facts from firecrawl-py 4.17.0, talos wiring
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:38:29 -07:00
kyle 099b94979c p0: IANA special-purpose deny table, extra deny prefixes
Block 6to4/Teredo/NAT64-local/site-local/benchmarking/reserved
ranges from the IANA registries (families, not decoded embeds).
Guard.DenyPrefixes / -deny-prefix covers hairpin WAN /32s; home
addresses stay on-box, not in git. Control is tcp/tcp4/tcp6 only.
2026-09-22 21:33:52 -07:00
kyleandClaude Opus 5.5 3b41d6ffbc plan: UA decided — default sift/<ver>, config override, measure bot-blocks
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:28:04 -07:00
kyle 2607d56e4c p0: skeleton, dialer-Control URL guard, flake, Makefile
Go service with /healthz, SSRF guard (parse + resolve-all + Control),
exhaustive tests, NixOS module, and Makefile as source of truth for
build flags. nix flake check runs make test lint.
2026-09-22 21:26:13 -07:00
kyleandClaude Opus 5.5 7d4f090a12 skill: sift as the explicit first step for fetch/search; plan §4.3 CLI client, --recover, UA policy
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:25:57 -07:00
kyleandClaude Opus 5.5 1e915ce715 plan: Makefile for non-Nix hosts (source of truth for build flags)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:15:29 -07:00
kyleandClaude Opus 5.5 e9aea1829e plan: Go instead of Python (Kyle's preference); dialer-Control SSRF check, gojq
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:05:59 -07:00
kyleandClaude Opus 5.5 94876864e5 sift: implementation plan
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:00:00 -07:00