Commit graph Huginn/crates/huginn-daemon
Author SHA1 Message Date
Meta Vens
f0566fd1bb read floor: Mind holds one decoded, indexed image, a fold of its receipts advanced per admission; a read pulls nothing and no longer grows with history (squash of hands/eureka-substrate-mind-read-floor cb86f58..2bed30c; Soul s1-s2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 11:26:27 +01:00
Meta Vens
cb86f58a7d wear-facts: a Mind's first line shows the wear her own mind holds, specs with no report, open Soul findings and quiet campaigns on what she stewards, each leading to a record she can open (squash of hands/eureka-body-wear-facts ab61a53..6014554; Soul s1-s2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 07:06:16 +01:00
Meta Vens
545d6319bf repo-activity: a Mind hears of changes in her stewarded repos, on her first line and by one organ notice on change; a repo the anonymous read cannot reach is named, never a failed read (squash of hands/eureka-body-repo-activity 5a294ed..eee0b14; Soul s1-s4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 04:54:26 +01:00
Meta Vens
0af7fd2501 huginn-sources: pin the Qdrant source delete's filter
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 22:16:17 +01:00
Meta Vens
d49ada3e68 huginn-sources: clippy slice refs in the reserve-bound test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 22:00:50 +01:00
Meta Vens
d9a4c27e70 huginn-sources: fix the slow-reserve stub's CRLF and the revert test's premise
The failed-upsert revert test now expects chunks of two commits, since
nothing is deleted before the new chunks land.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:58:34 +01:00
Meta Vens
5874717c88 huginn-sources: embed before deleting; the reserve gets a CPU's bounds
Source refresh now upserts a repo's new chunks first and deletes what is
left in scope under another commit afterwards, so a failed embed never
removes indexed content (embed-outage-empties-repo). The cursor is still
dropped before the first write.

The pool's reserve endpoints use EmbedBounds::RESERVE (30 s a text, 60 s
floor) instead of the GPU default (reserve-bounded-like-a-gpu).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:54:54 +01:00
Meta Vens
cf790b6142 index: take_search's doc comment back on take_search
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:21:42 +01:00
Meta Vens
44b3bf5e91 Merge eureka-body/source-search-index-safety (cursor, catalog, retire, CLI e2e; report h3)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:21:23 +01:00
Meta Vens
2f36f63e80 ollama: pin the batch bound's arithmetic (cargo-mutants survivor)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 09:17:55 +01:00
Meta Vens
715ec58180 sources: Refreshed::is_clean decides the exit, where a test reaches it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 09:10:07 +01:00
Meta Vens
39decde8a2 embedder: connect bound, a read bound sized to the batch, one budget across retries; tests with endpoints that stall and refuse mid-batch
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 09:05:47 +01:00
Meta Vens
6a0ab4a7ab live source smoke: follow the Catalog the forge now answers
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 09:00:54 +01:00
Meta Vens
e47532c122 sources: a retire error skips that repo; a case-only rename keeps no stale points
Retirement aborted the run on the first repo whose delete failed; it now logs,
names the repo in Refreshed.failed and goes on, leaving that repo's cursor and
mirror to be found again. Names are compared as written, so a repo the forge
now spells in another case is retired under its old spelling instead of kept by
a case-insensitive match while its points carried the old name (Soul
retire-edge-cases).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 08:58:19 +01:00
Meta Vens
6c1cef8729 sources: retire nothing when the forge's catalog is empty or does not sum to its X-Total-Count
Retirement read the repo list as complete, so an empty or truncated answer
would have deleted every repo it failed to name (Soul catalog-shrink-retires).
The catalog now carries a shortfall: the pages summed before filtering are
checked against X-Total-Count, and a missing header counts as unvouched. The
run refuses to retire on a short or empty catalog, refreshes the repos it did
see, says so in Refreshed.retirement_withheld, and huginn-sources exits 1.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 08:57:38 +01:00
Meta Vens
3f380df0fe sources: drop a repo's cursor before its first delete, so a failed run is re-ingested whole
A failed run from A to B followed by a head C that reverts the files to A's
content diffed A..C as empty and kept the deleted chunks deleted (Soul
cursor-revert-hole: 32 of 40 chunks, cursor at C). With the cursor gone the
next run takes the whole-repo path whatever head it finds.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 08:56:21 +01:00
Meta Vens
5cde349a09 pool tests: no waiting on reads that are not running; a failed read waits for its retry time
Closes the pool mutation survivors (reading, ready, judge's retry time).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 08:29:52 +01:00
Meta Vens
1fee2e434e pool: a read awaiting a model to adopt stays to be judged
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 08:12:26 +01:00
Meta Vens
c74dd530de daemon: embeds through the endpoint pool, GPUs together and the CPU last
query-embed-on-cpu, follow-up daemon-embedder-gpu-pool: huginn-daemon takes
repeated --ollama-url (GPU hosts) and --reserve-ollama-url (CPU hosts) and
builds the same EmbedderPool as huginn-sources, through one ollama::pool
constructor. A lone --ollama-url is a pool of one.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 07:56:22 +01:00
Meta Vens
13647f9220 pool: identities are read off the batch's clock and held to the collection's model
pool-blackhole-stalls: each due endpoint's identity is read on its own thread
under a 5 s bound, and a batch waits for reads only while no healthy primary
exists to start on, so a dark endpoint never delays work a healthy one can do.
pool-pins-first-identity: the pool is told the model the collection was built
with (Embedder::built_under, called by reconcile and refresh before the
identity read) and never writes with an endpoint serving another; it adopts a
model only when there is no collection, in list order.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 07:54:57 +01:00
Meta Vens
99d3c05b09 pool: simpler admission guard (clippy)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:58:55 +01:00
Meta Vens
e3d289fec8 sources tests: the batch test belongs after the last test, not inside it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:57:34 +01:00
Meta Vens
1cfb905306 tests for the mutation survivors: char bound and newline accounting, catalog paging, batch bound, a source search through the daemon, the shared queue bound and abandon by ticket
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:56:22 +01:00
Meta Vens
bd39f95cfe pool: type alias for a piece's outcome; the mismatch test re-admits the endpoint after its model changed
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:55:01 +01:00
Meta Vens
bc8e071bf7 embedder pool in the shared index module (GPUs concurrent, CPU reserve, per-endpoint identity); huginn-sources uses it; the failover chain is deleted
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:51:57 +01:00
Meta Vens
040ae57d53 daemon: a source search is a Search with no mind part (keeps the Handled/Routed sizes clippy already accepted)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:44:49 +01:00
Meta Vens
b16c0619a0 daemon: box the mind search so Pending stays small (clippy)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:43:27 +01:00
Meta Vens
393a0aff62 live smoke: refresh one small public repo into a scratch source collection, search it, delete it; the Qdrant source port can be pointed at a scratch collection
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:40:22 +01:00
Meta Vens
528deb296b sources tests: do not hold the fake's lock across its own accessor
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:32:51 +01:00
Meta Vens
6a66425931 source-search: compile fixes (startup bound, mirror init, test literal)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:27:50 +01:00
Meta Vens
1c227f5907 huginn-daemon: source index (chunker, git mirrors, forge catalog, refresh with embedder failover, SourceIndex on Qdrant), huginn-sources bin, daemon/worker source search not gated by the mind's index
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 06:25:25 +01:00
Meta Vens
eadc2bfadc Qdrant search test: the limit is pinned by value at 1, 12 and 200
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 21:32:56 +01:00
Meta Vens
68f93b69dc Daemon test: a large top_k reaches the index whole
Twenty members, top_k 15 and 200: the index limit and the row count are both
asserted. Unverified at this commit: built and tested once at the end of the batch.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 21:05:03 +01:00
Meta Vens
2041fa8467 Qdrant search: the test parses the request body as JSON; the live smoke excludes a non-member
filter and params are asserted by value, so must_not and a top-level exact
fail. live_index_smoke searches a strict subset that leaves out the nearest
point. Unverified at this commit: built and tested once at the end of the batch.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 21:05:02 +01:00
Meta Vens
0cfb4fa278 Index test: the ticket test hands the sink the member it expects back
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 19:54:52 +01:00
Meta Vens
d7b1b1d116 A semantic query returns up to top_k members of its selection, with scores
The mind decides membership (Mind::members) before the index is asked; the
index scores exactly the members (Qdrant has_id + exact) and the page carries
one cosine score per row. Deletes OVERSAMPLE_MAX, the x4 oversample, the
unfiltered VectorIndex::search contract and check_semantic.

Not yet compiled when committed: the first Yggdrasil run follows.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 19:51:29 +01:00
Meta Vens
ea28b8cbc0 Decoder reports field path and error class, never a caller value; status says Unreadable
The shared request decoder (envelope.rs) no longer quotes decoder text or
envelope fields: a refusal names the field path and the class. MindStatus.persona
is PersonaStatus {Absent, Stored, Unreadable}, so whoami answers in the persona
door's own terms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:32:48 +02:00
Meta Vens
e95e2d57aa Merge origin/main (f003801) into huginn-persona-state
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:30:51 +02:00
Meta Vens
dbdb4e86f8 Huginn holds an instance's persona document, validated and receipted
put_persona replaces the mind's gamecult.persona_state.v0 whole through the
commit primitive: schema-valid against the published file, personaId is the
instance, canonical provenance, CAS on updatedAt, monotone updatedAt. The
document is an opaque seventeenth stored type, one per mind. Wire operations
persona_get and persona_put, MindStatus.persona, HuginnClient methods and the
eureka-state persona tools. Published wire schemas follow in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:30:48 +02:00
Meta Vens
7375687188 Pin Rust 1.95.0 and clear the twelve clippy lints red at main
rust-toolchain.toml owns which rustc and clippy judge the tree. View in
HuginnMindResponse is boxed so the large_enum_variant allow on the wire
type is deleted; the PipelineDocument allow keeps a sharpened reason.
Type aliases, is_multiple_of, slice::from_ref and a literal refused()
clear the rest. Wire bytes and schemas are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:21:13 +02:00
Meta Vens
44c010c9da Leaf: CodeLocation.symbol and CutSpec.reads, additive at epoch v2 through the value_types! = absent marker
Adds Absent, Symbol, ReadAnchor and read_window_is_bounded, the marker in
value_types!, the workspace fixtures and the reads admission test. The
golden file and the six published schemas are not regenerated yet, so the
golden, schema and wire-schema tests fail at this commit (it builds).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:29:53 +02:00
Meta Vens
09e1b9792b Relicense the workspace AGPL-3.0-only, own the CultLib rev once, index every schema
Add the AGPL-3.0 text as LICENSE and set the workspace license to
AGPL-3.0-only (rulings license-split, leaf-relicensed-agpl); the leaf's
provenance (Epiphany ef956865, PolyForm Noncommercial, relicensed by its sole
copyright holder 2026-10-09) is recorded in its Cargo.toml and README.

One [workspace.dependencies] entry per CultLib crate now owns the revision;
the crates inherit it. index.json lists Huginn's two wire schemas too, and the
catalogue test drops its huginn. prefix exclusion: every schema file is listed.
README and AGENTS stop naming Epiphany notes as the owner of the cut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 15:15:10 +02:00
Meta Vens
c46b0ec183 Rename the pipeline leaf to eureka-pipeline and take it as a path dependency
Package and lib become eureka-pipeline / eureka_pipeline; the crate joins the
workspace; huginn-mind's git dependency on GameCult/Epiphany is replaced by
the path, and Cargo.lock is regenerated (the Epiphany source entry is gone).
Every epiphany_pipeline mention in huginn-mind, huginn-daemon and eureka-state
is renamed. The schema-publication test reads ../../schemas/cultnet. The
leaf's license-file key (../LICENSE, which Huginn has no file for) is dropped.
Type ids, the epoch and every schema_id string are untouched. Schemas README
and the pipeline section of schemas/cultnet/README.md are rewritten for the
new home; README and AGENTS no longer say the leaf is pinned by git. New test:
the catalogue lists exactly the schema files beside it.

Not yet built or tested; verification follows on Yggdrasil.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:09:16 +02:00
Meta Vens
9dd6d8007a Pin CultLib 8fc74c7 in every crate, and the pipeline leaf that follows it
eureka-state on Windows could not reach the daemon: the cultnet-rs RUDP
client bound 127.0.0.1, and a loopback-bound socket cannot send to
10.77.0.1 (os error 10051). CultLib 8fc74c7 binds the unspecified address
for a remote endpoint. The daemon and the client move together, because
the ack cuts between the revs changed the RUDP handshake.

epiphany-pipeline moves to Epiphany 73edee5, which pins the same CultLib,
so one cultcache-rs is in the graph and the pipeline's CultCache types
stay Huginn's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 14:36:44 +02:00
Meta Vens
4f5d0b1a7e Move the deferred-body bound to the wire vocabulary both sides read
MAX_DEFERRED_BODY_BYTES was the daemon's constant, but a client caps its
content fetch at the same number, and the client crate cannot depend on the
daemon. It moves to huginn-mind::wire next to the response schema it bounds;
the daemon imports it, the pin test stays in bodies.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:32:54 +02:00
Meta Vens
debe7ce9e7 Move the operation envelope to huginn-mind: one spelling for client and daemon
envelope.rs (encode/decode request and response, OperationFailure,
FAILURE_SCHEMA) leaves huginn-daemon for huginn-mind, next to the wire types
it wraps. The daemon imports it and no longer re-exports it. base64 moves
with it; the daemon keeps base64 because serve.rs measures and decodes
payloads. schemars leaves the daemon, whose only user was the envelope's
OperationFailure derive. The two envelope tests run unchanged from their new
home on huginn-mind fixtures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:30:21 +02:00
Meta Vens
9497001d34 Pin settle-at-reconcile and the first-reconcile wait in take_search
Two mutants survived Soul pass 4: dropping `self.settle()` from reconcile,
and dropping `!projector.stale()` from take_search. One test each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:59:57 +02:00
Meta Vens
cfd9694de0 Pin that an index found whole at start-up was built
Losing a collection the worker found whole at start-up is a rebuild. The
mutation that left Build::Unbuilt in place on a matching label survived,
because nothing observed the difference until the collection was lost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:03:56 +02:00
Meta Vens
8a9ade959d Drop a racy queue peek from the hung-embedder test
The test read the queued search's due moment through the sink's lock right
after asking, but the worker can take the search first: it failed under the
load of cargo-mutants' baseline run. The stamp is pinned without a worker in
the_sink_owns_the_searchs_deadline_and_tells_the_loop, which is the test that
owns it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:36:51 +02:00
Meta Vens
e99dc4404e Decide and take a search under one guard; a refill is a rebuild; a first build is lag
S1. serve_search absorbed the inbox and judged pending under one lock and
popped the search under a second, so an admission acknowledged before the
search was asked could be missed. The absorb, the judgement and the take are
now one critical section, and take_search never takes a search while the inbox
is non-empty or anything ahead of it is owed.

S2. The projector carries Build (Unbuilt, Built, Rebuilding). A collection made
again (label mismatch, or lost after it was once built) is Rebuilding until the
entries it owes are written; settle() is the one place that clears it, so a
failure mid-refill does not end the rebuild. Rebuilding reports Reconciling.
unsearchable stays the only refusal predicate.

S3. A mind whose index was never built is Unbuilt: its first build reports
Behind, so the search waits and answers whichever side looked first. Only a
rebuild of an index that exists refuses.

S5. ServeOptions::search_timeout is deleted. The sink owns the deadline
(Backoff::search_deadline, stamped on every search) and the serve loop asks
the daemon for it (IndexSink::search_deadline), so the loop's wait and the
worker's bound are one value. A mind with no identity and documents owed is
Reconciling, so a search is taken and refused rather than left for a spinning
worker.

S4. A test pins that a later call's bound shrinks as the search spends time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:28:22 +02:00