Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
204 commits
Select commit Hold shift + click to select a range
6a2f41a
internal/catalog: keep all three artificial-analysis indexes and the …
santoshkumarradha Sep 17, 2026
837eb08
config, tui3: the crew reads the whole catalog by default, and both t…
santoshkumarradha Sep 17, 2026
8fd6cda
docs/changes: the crew default family note carries its pull request n…
santoshkumarradha Sep 17, 2026
457f3eb
crewpick: pick one model per seat off the pareto front of bill agains…
santoshkumarradha Sep 17, 2026
5dd78e6
pool/tally: a cell keeps n, sum and sum of squares and reads back mea…
santoshkumarradha Sep 17, 2026
9ceb82a
pool/tally: sheets record observations and paired wins under addresse…
santoshkumarradha Sep 17, 2026
c64b200
pool/tally: sheets merge by adding cells and wins, order-free
santoshkumarradha Sep 17, 2026
58fb841
pool/tally: a deterministic json round trip behind a schema gate
santoshkumarradha Sep 17, 2026
f4f3fa1
pool/index: read a schema-versioned measurement document into a share…
agentfield-bot Sep 17, 2026
f76050a
pool/index: test the reader against the example document, its forward…
agentfield-bot Sep 17, 2026
0d60843
orchestrate: ask an installed tariff before the fallback price table
santoshkumarradha Sep 17, 2026
0769cb4
session: an orchestrated run meters against the catalog's published t…
santoshkumarradha Sep 17, 2026
521e1e0
pool/index: the declared metrics are read in sorted order
santoshkumarradha Sep 17, 2026
e957086
session: a run with no published tariff leaves the installed one alone
santoshkumarradha Sep 17, 2026
e341d3a
docs/changes: notes for the three new packages and the fuel tariff seam
santoshkumarradha Sep 17, 2026
d983323
Merge origin/santos/dev into feat/auto-crew
santoshkumarradha Sep 17, 2026
120bbc3
config: a tier row that says auto resolves through the catalog's own …
santoshkumarradha Sep 17, 2026
0295be5
config: test the auto word, its pick and both ladders' resolution of it
santoshkumarradha Sep 17, 2026
8c50bc0
config: wire the catalog's own front into every door's auto word
santoshkumarradha Sep 17, 2026
8f69b8c
codeaf: the do door wires the auto word before the seats handed in ar…
santoshkumarradha Sep 17, 2026
6fa70e7
docs/changes: the tier row that says auto, and the two rungs it resol…
santoshkumarradha Sep 17, 2026
b4e1522
codeaf: the headless doors seat the catalog before they climb the sea…
santoshkumarradha Sep 17, 2026
576d03c
session: every usage row names the seat the call ran under
santoshkumarradha Sep 17, 2026
99811b0
session: the seat words and their tagged rows are tested
santoshkumarradha Sep 17, 2026
f25f123
outbox: keep measurement rows in an append-only file and deliver them…
agentfield-bot Sep 17, 2026
3faea5c
outbox: test the file format, the cap, the batch sends and the delive…
agentfield-bot Sep 17, 2026
e9fe0ec
poolcfg: resolve pool behaviour from a stored setting and a handed-in…
santoshkumarradha Sep 17, 2026
188e513
poolcfg: cover resolution, the url shapes, ttl clamping and the can-s…
santoshkumarradha Sep 17, 2026
8e97aca
pool: fetch, verify and cache a signed json document
santoshkumarradha Sep 17, 2026
0cb25fb
pool: handle 304 from cache and file urls, add thorough tests
santoshkumarradha Sep 17, 2026
38701fe
pool: test the too-large fallback over http and fix the siglocation doc
santoshkumarradha Sep 17, 2026
defc3b6
pool: the cache-trust doc links Puller.Keys instead of naming it bare
santoshkumarradha Sep 17, 2026
d24414a
pool/pull: the package sits in the directory its import path names
santoshkumarradha Sep 17, 2026
53605d9
session: a repair round is marked by its caller, not by a named model
santoshkumarradha Sep 17, 2026
0843aeb
pool/poolcfg: the host rule is pinned against the shapes that read li…
santoshkumarradha Sep 17, 2026
d252388
docs/changes: the three new pool packages and the seat a usage row names
santoshkumarradha Sep 17, 2026
8f27dff
pool/outbox: a marker retires one row, and only once it is on disk
santoshkumarradha Sep 17, 2026
33cd743
pool/pull: the cache's version comes off the bytes, and a file source…
santoshkumarradha Sep 17, 2026
22a5100
crewpick: a candidate with some of its indexes is estimated, not dropped
santoshkumarradha Sep 17, 2026
b6723bf
docs/changes: the crewpick note says what a partly-scored candidate does
santoshkumarradha Sep 17, 2026
61352eb
config: the four pool names are registered as operator plumbing
santoshkumarradha Sep 17, 2026
e50ed25
config: the crew tables move to the measured seats, and the shipped m…
santoshkumarradha Sep 17, 2026
2dcfc54
manual: the crew pages name the measured seats
santoshkumarradha Sep 17, 2026
6559899
docs/changes: the six crew-table cells that moved
santoshkumarradha Sep 17, 2026
bfcc7ec
config: the crew comments carry the moved shape, and the worker tie i…
santoshkumarradha Sep 17, 2026
84f923c
config: the open frugal line and its mirrors name the worker the row …
santoshkumarradha Sep 17, 2026
e18ad36
config: the default preset wins when the stored rows match two presets
santoshkumarradha Sep 17, 2026
9809457
config, session: the crew examples in the comments name the moved seats
santoshkumarradha Sep 17, 2026
beffd41
manual, docs: the headless model line and the reflex default match th…
santoshkumarradha Sep 17, 2026
ec4e56b
exec: the failed lane is read off the wire's own fact, not a status
santoshkumarradha Sep 17, 2026
ac11b3b
exec: the lane to avoid is the provider's fact, read as a question
santoshkumarradha Sep 17, 2026
c13a39a
orchestrate: the fuel table holds the ids this build ships
santoshkumarradha Sep 17, 2026
2bf0cda
orchestrate, session: every shipped model is pinned to a fuel row
santoshkumarradha Sep 17, 2026
6658ec8
session: the cost test reads the flash-0731 row the table holds
santoshkumarradha Sep 17, 2026
cfa7604
config: the model_pool row, its three choices, and the resolver that …
santoshkumarradha Sep 17, 2026
6826f40
crewpick: a seat's quality blends a measured pool rating by its count
santoshkumarradha Sep 17, 2026
2b4b2c2
crewpick: tests for the seat quality prior and the measured marks
santoshkumarradha Sep 17, 2026
07b33e7
config: the auto pick blends a Model Pool index into seat quality
santoshkumarradha Sep 17, 2026
a6f3730
config: a test for the index moving the auto pick through the prior
santoshkumarradha Sep 17, 2026
e13a4db
docs: a change note for the crew picker's measured quality prior
santoshkumarradha Sep 17, 2026
12f233f
docs: the change note carries this change's pull request number
santoshkumarradha Sep 17, 2026
f787114
pool: the codeaf pool verb — show, status and verify
santoshkumarradha Sep 17, 2026
5efa9ac
docs: the change entry for the pool setting and verb
santoshkumarradha Sep 17, 2026
88fa4d4
cmd/codeaf: the pool entry fits the help page without dropping exec's…
santoshkumarradha Sep 17, 2026
21e570a
docs: the change note carries this change's pull request number and t…
santoshkumarradha Sep 17, 2026
3415336
config, cmd/codeaf, manual: the model_pool row names its reader, and …
santoshkumarradha Sep 17, 2026
c389479
Merge feat/pool-prior into feat/auto-crew: the crew picker takes a me…
santoshkumarradha Sep 17, 2026
232b00c
Merge feat/pool-cli into feat/auto-crew: the model_pool setting and t…
santoshkumarradha Sep 17, 2026
ac076af
cmd/codeaf: a leaf re-dispatched after running out is granted more ro…
santoshkumarradha Sep 17, 2026
8611c91
store: the turns a release handed on, and how many re-dispatches a no…
santoshkumarradha Sep 17, 2026
edcf525
resident: a re-dispatch that banks nothing new is failed rather than …
santoshkumarradha Sep 17, 2026
bcf6ccc
cmd/codeaf: the run's json object says how many times a node was re-d…
santoshkumarradha Sep 17, 2026
fc9a7c3
docs: the change note for the re-dispatch grant and refusal
santoshkumarradha Sep 17, 2026
eafafb1
docs: the change note carries this change's pull request number
santoshkumarradha Sep 17, 2026
6442917
session: a git status with no directory is refused where it is built
santoshkumarradha Sep 17, 2026
4146dbf
session: releaseLanded refuses a tree with no ground and takes the ro…
santoshkumarradha Sep 17, 2026
f1f9f4c
session: the checkout guard reads a linked worktree's own share of th…
santoshkumarradha Sep 17, 2026
9e0fd5a
session: the no-directory status test stands in a repository whose tr…
santoshkumarradha Sep 17, 2026
951af32
session, docs: the gitWith comment reads whole, and the change note f…
santoshkumarradha Sep 17, 2026
32a1ca4
session: releaseLanded leaves the root lock to the landing that holds it
santoshkumarradha Sep 17, 2026
f088139
store: a delivery gate anchor names when a job was first found done
santoshkumarradha Sep 17, 2026
ab32d99
revision: a second unexercised-only finding buys no coverage round
santoshkumarradha Sep 17, 2026
3dd68b8
resident: growth is refused once its spend outweighs the requested work
santoshkumarradha Sep 17, 2026
996f6fb
do: the envelope says when the requested work was first found done
santoshkumarradha Sep 17, 2026
2c9fafa
docs: the change note for the bounded coverage round and the core-don…
santoshkumarradha Sep 17, 2026
4894232
store: a gate is done only when the checks are all that is missing
santoshkumarradha Sep 17, 2026
0710b5c
docs: the change note carries this change's pull request number
santoshkumarradha Sep 17, 2026
00b9dc8
tui3: the model pool row has its place on the settings sheet
santoshkumarradha Sep 17, 2026
3283473
pool/index: the binary carries a seed measurement document
santoshkumarradha Sep 17, 2026
4ba832b
cmd/codeaf: the crew picker reads a seed index with a background refresh
santoshkumarradha Sep 17, 2026
1a864b1
pool/judge: a finished run is scored seat by seat by a model outside …
santoshkumarradha Sep 17, 2026
7b13e1d
manual, docs: the pool section names the seed index the binary carries
santoshkumarradha Sep 17, 2026
0cf5186
pool/judge: the seat-by-seat reading and the judge pick are pinned by…
santoshkumarradha Sep 17, 2026
50a6868
docs: the change entry for the seat-by-seat judge package
santoshkumarradha Sep 17, 2026
1425510
Merge feat/pool-judge into feat/auto-crew: a finished run is scored s…
santoshkumarradha Sep 17, 2026
a35b1c2
docs: the judge change entry carries the pull request it ships in
santoshkumarradha Sep 17, 2026
82954b3
Merge feat/pool-loader into feat/auto-crew: the binary carries a seed…
santoshkumarradha Sep 17, 2026
83b3920
cmd/codeaf: the seed index change entry carries its pull request and …
santoshkumarradha Sep 17, 2026
2d1f02b
docs: the Model Pool paper, its figures and the script and data that …
santoshkumarradha Sep 17, 2026
b7b8b40
config: the crew's seats are picked from a row — table, catalog or le…
santoshkumarradha Sep 17, 2026
f673a6c
docs, manual: the paper gains its system architecture and the seed se…
santoshkumarradha Sep 17, 2026
cc63191
tui3: the picked-from row takes its place beside the crew word, and /…
santoshkumarradha Sep 17, 2026
38bbf1f
manual: the seats are picked from table, catalog or learn, and the ru…
santoshkumarradha Sep 17, 2026
8d782d5
docs: a change note for the picked-from row
santoshkumarradha Sep 17, 2026
1f8e491
Merge fix/exec-lane-reads-the-fact into feat/auto-crew
santoshkumarradha Sep 17, 2026
0f4397e
Merge fix/overrun-regrant into feat/auto-crew
santoshkumarradha Sep 17, 2026
51b6815
Merge fix/session-git-holes into feat/auto-crew
santoshkumarradha Sep 17, 2026
005ec96
Merge fix/unexercised-round-bound into feat/auto-crew: the envelope c…
santoshkumarradha Sep 17, 2026
5e7f0f0
docs: the folded change entries carry the pull request they ship in
santoshkumarradha Sep 17, 2026
45bb1f2
Merge feat/crew-pick into feat/auto-crew: the crew's seats are picked…
santoshkumarradha Sep 17, 2026
6274a6b
docs: the picked-from change entry carries its pull request
santoshkumarradha Sep 17, 2026
dcf8270
pool/tally: Each hands a metric's cells to a caller in a settled order
santoshkumarradha Sep 17, 2026
dc73bef
crewpick: MergePriors folds two priors seat by seat by observation count
santoshkumarradha Sep 17, 2026
4cc4192
pool/record: judged seat scores land in an own sheet and outbox rows
santoshkumarradha Sep 17, 2026
8da59f7
config: the own sheet's cells join the auto prior beside the index's
santoshkumarradha Sep 17, 2026
d73c232
session: judge is the seventh seat word, mapped from no tier and no role
santoshkumarradha Sep 17, 2026
55c1c12
cmd/codeaf: the own sheet is seated beside the index and counted by s…
santoshkumarradha Sep 17, 2026
58b3d54
docs: the recorder change entry and the own sheet named in the pool s…
santoshkumarradha Sep 17, 2026
ef004d8
pool/record: a failed append is returned with the sheet observed all …
santoshkumarradha Sep 17, 2026
e9b5349
session: the tier test's failure word says the vocabulary's seven
santoshkumarradha Sep 17, 2026
8d92e45
Merge feat/pool-recorder into feat/auto-crew: judged seat scores land…
santoshkumarradha Sep 17, 2026
fecc3d1
docs: referee review of the model-pool paper
santoshkumarradha Sep 17, 2026
a66afc9
session: a landed node's record reaches Config.TaskLanded on its own …
santoshkumarradha Sep 17, 2026
62571b3
cmd/codeaf: a landed task is scored by a model outside the crew into …
santoshkumarradha Sep 17, 2026
0a49bc8
cmd/codeaf: the chat door hands its landings to the pool's judge, off…
santoshkumarradha Sep 17, 2026
78da318
Merge docs/pool-paper-review into feat/auto-crew: a referee's review …
santoshkumarradha Sep 17, 2026
72f0a85
docs: revise the model-pool paper after the referee's report
santoshkumarradha Sep 17, 2026
b45a9b4
pool: the judge hook is tested at both doors and said in the manual a…
santoshkumarradha Sep 17, 2026
df1757c
Merge santos/dev into feat/auto-crew
santoshkumarradha Sep 17, 2026
a26996e
docs: the paper is Pareto Crewing; the help page fits its screen again
santoshkumarradha Sep 17, 2026
651e753
Merge dev into feat/auto-crew
santoshkumarradha Sep 17, 2026
5991b1f
manual: catalog and learn picks are named Pareto crewing
santoshkumarradha Sep 17, 2026
02f80dc
Merge feat/pool-judge-hook into feat/auto-crew: the judge scores ever…
santoshkumarradha Sep 17, 2026
354158f
session, cmd/codeaf: the judge hook's comments speak at one volume
santoshkumarradha Sep 17, 2026
4a3c549
cmd/codeaf: the logs entry on the help page fits eighty columns
santoshkumarradha Sep 17, 2026
e4539e6
task: Pool relay runbook, README line and change note
agentfield-bot Sep 17, 2026
32de3d5
task: Pool index mirror workflow and verifier
agentfield-bot Sep 17, 2026
ea49922
Merge branch 'task/pool-index-mirror-workflow-and-v-63fa66' into task…
agentfield-bot Sep 17, 2026
f826f82
relay: the test suite runs from the directory-form command
santoshkumarradha Sep 17, 2026
e7a6d09
Merge the pool relay into feat/auto-crew: one edge function, one stor…
santoshkumarradha Sep 17, 2026
b9f18fa
README: the Model Pool section names the paper and the runbook
santoshkumarradha Sep 17, 2026
2bfcecf
docs: the model-pool tables say which script and data made them
santoshkumarradha Sep 17, 2026
9bd50a6
Merge santos/dev into feat/auto-crew
santoshkumarradha Sep 17, 2026
a2dbaba
Merge the proof run's task into feat/auto-crew: the tables name their…
santoshkumarradha Sep 17, 2026
002b8f2
docs: the figure rule of the paper's Makefile dates by a stamp, not a…
santoshkumarradha Sep 17, 2026
7b02b7e
cmd/codeaf: each seat's judge question gets its own share of the land…
santoshkumarradha Sep 17, 2026
9609e0c
poolcfg: the pool's addresses derive from one relay base, each with i…
santoshkumarradha Sep 17, 2026
ec0a8b2
pool: the outbox rides an install nonce, and pending rows are pushed …
santoshkumarradha Sep 17, 2026
fe31df6
pool: the index signer's key ships in the binary, with a settings row…
santoshkumarradha Sep 17, 2026
235b690
docs: the terminal manual says the pool sends after each run and read…
santoshkumarradha Sep 17, 2026
ff9afb5
docs: the pool client change note
santoshkumarradha Sep 17, 2026
8a55527
Merge the pool client into feat/auto-crew: real addresses, the instal…
santoshkumarradha Sep 17, 2026
9cdacbf
poolcfg: the mirror address is held beside the relay, printed by show
santoshkumarradha Sep 17, 2026
7437a6d
pool: a relay that does not answer falls through to the mirror, a bad…
santoshkumarradha Sep 17, 2026
f2b996d
pool: status says whether the relay answered, and the mirror when it …
santoshkumarradha Sep 17, 2026
7bd4b46
docs: the terminal manual says status reads the relay and the mirror,…
santoshkumarradha Sep 17, 2026
540ecaf
docs: the pool client change note carries the mirror fallback and the…
santoshkumarradha Sep 17, 2026
0f984f9
tui3: the pool key row has a tab
santoshkumarradha Sep 17, 2026
45cf1fa
settings, README: the pool row says what leaves, that it is on, and h…
santoshkumarradha Sep 17, 2026
cc80d72
pool, docs: the seed index and the paper's figures are regenerated fr…
santoshkumarradha Sep 17, 2026
91503a5
docs: the response quotes the regenerated seed's offset
santoshkumarradha Sep 17, 2026
96da968
Merge the pool client's second half into feat/auto-crew: the mirror f…
santoshkumarradha Sep 17, 2026
4bdd6fe
relay: the KV namespace id of the deployed pool
santoshkumarradha Sep 17, 2026
3dcb5a0
cmd/codeaf: the judge's second question is proved to get its own shar…
santoshkumarradha Sep 17, 2026
3b54432
relay: the observability settings live in wrangler.toml, and the runb…
santoshkumarradha Sep 17, 2026
622af4f
Merge the judge-time test into feat/auto-crew
santoshkumarradha Sep 17, 2026
305a409
config, docs: the mirror address pin is registered, and a change note…
santoshkumarradha Sep 17, 2026
534f429
docs: the judge hook's note title fits under a hundred characters
santoshkumarradha Sep 17, 2026
85e75fe
docs: second referee report on the model-pool paper
santoshkumarradha Sep 17, 2026
4bbff65
Merge the second referee report into feat/auto-crew
santoshkumarradha Sep 17, 2026
9ee021a
docs: the paper answers the second referee report
santoshkumarradha Sep 17, 2026
0e0024e
docs: the runbook says how to fire the first publication and when the…
santoshkumarradha Sep 17, 2026
c63dfaa
judge: Candidates lists every paid judge, and Pick is its head
santoshkumarradha Sep 17, 2026
9a6e433
pool: a landing moves to the next judge when one answers nothing
santoshkumarradha Sep 17, 2026
8b1cfdf
Merge the judge's candidate list into feat/auto-crew: no free row, an…
santoshkumarradha Sep 17, 2026
34b1cf0
pool: --key replaces the resolved keys, and a stored key that does no…
santoshkumarradha Sep 17, 2026
96013b7
docs: the pool's --key checks under that key alone, and a key that do…
santoshkumarradha Sep 17, 2026
2a45378
pool: the --key replace tests sign under the key the verb resolves on…
santoshkumarradha Sep 17, 2026
0198c28
catalog: a bounded wait at the warm's door
santoshkumarradha Sep 17, 2026
905b356
config: a read that says when a tier row asks for the rows
santoshkumarradha Sep 17, 2026
8b59753
seats: the headless doors wait for the rows a pick needs
santoshkumarradha Sep 17, 2026
c501712
seats: the doors' wait is pinned at the catalog, the table and the fall
santoshkumarradha Sep 17, 2026
e1f92b1
relay: publish the index behind stale reads under a short lock
santoshkumarradha Sep 17, 2026
b068cd8
relay: cover background republish on missing, stale and fresh reads
santoshkumarradha Sep 17, 2026
be542fc
relay: name the republish interval and note the cron is a floor
santoshkumarradha Sep 17, 2026
3aaf46d
relay: serialise same-isolate publishers behind one in-flight publish
santoshkumarradha Sep 17, 2026
2e6d754
Merge the relay's publish-on-read into feat/auto-crew: a stale index …
santoshkumarradha Sep 17, 2026
bade022
Merge the headless doors' wait for the catalog rows into feat/auto-crew
santoshkumarradha Sep 17, 2026
a48b72a
Merge pool verify's key rules into feat/auto-crew: --key alone, and a…
santoshkumarradha Sep 17, 2026
dc180fd
Merge santos/dev into feat/auto-crew
santoshkumarradha Sep 17, 2026
9597686
pool: the judge's landing leaves a record, and status says what the l…
santoshkumarradha Sep 17, 2026
c12f69a
pool, docs: the seed index and the paper's seed figure are regenerate…
santoshkumarradha Sep 17, 2026
22764b5
Merge spark:/home/santosh/src/trees/c068 into feat/auto-crew
santoshkumarradha Sep 17, 2026
ba93eb7
relay: prime the pool once from the scored runs the seed encodes
santoshkumarradha Sep 17, 2026
96244d9
relay, docs: say how the pool was primed once from the seed's runs
santoshkumarradha Sep 17, 2026
48855c3
docs: the paper says how the pool was primed and that an install hold…
santoshkumarradha Sep 17, 2026
c7e7eea
pool: say how many cells the held index carries on show and status
santoshkumarradha Sep 17, 2026
e55cd2f
manual: say show names how many cells the index holds
santoshkumarradha Sep 17, 2026
da49af6
Merge spark:/home/santosh/src/trees/c090 into feat/auto-crew
santoshkumarradha Sep 17, 2026
db7d46f
Merge spark:/home/santosh/src/trees/c093 into feat/auto-crew
santoshkumarradha Sep 17, 2026
4e1e2e7
pool, relay: the seed is regenerated at this head and the priming scr…
santoshkumarradha Sep 17, 2026
14c36ad
docs: the seed caption counts the runs behind this head's seed
santoshkumarradha Sep 17, 2026
cf4ea35
relay: the priming script names itself to the edge, which refuses the…
santoshkumarradha Sep 17, 2026
fd29d79
docs: the runbook says how to publish at once after loading rows
santoshkumarradha Sep 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .github/workflows/pool-mirror.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: Model Pool mirror

# Mirrors the relay's signed index document onto the `model-pool` orphan data
# branch, under pool/index.json and pool/index.json.sig, so it can be served
# and linked from GitHub. The branch holds the signed document and its
# signature, and nothing derived from them — no count, no leaderboard, no
# extracted statistic.
on:
schedule:
# Every six hours.
- cron: '0 */6 * * *'
workflow_dispatch:

permissions:
contents: write

concurrency:
group: pool-mirror
cancel-in-progress: false

jobs:
mirror:
runs-on: ubuntu-latest
steps:
# Gets relay/verify.mjs, the only thing this workflow needs from the tree.
- uses: actions/checkout@v4

# -fsS: fail the job on any non-200, print an error on any other failure.
- name: Fetch the signed document and its signature
run: |
set -euo pipefail
curl -fsS -o index.json https://codeaf.agentfield.ai/pool/index.json
curl -fsS -o index.json.sig https://codeaf.agentfield.ai/pool/index.json.sig

# The value is the public key copied from relay/wrangler.toml, and it is a
# literal: no secret is needed to verify a signature. A bad signature or
# any non-2xx fetch fails the job before anything is published.
- name: Verify the signature
env:
POOL_PUBLIC_KEY: WOAo+g/oKxAV9vVqv2Q14w1TyyyiouwFO2fC0zgcps0=
run: node relay/verify.mjs index.json index.json.sig "$POOL_PUBLIC_KEY"

- name: Mirror onto the model-pool branch
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
mkdir -p mirror
cd mirror
git init -q
git remote add origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

# The data branch shares no history with the tree; adopt it when it
# exists and start an orphan when this is the first run.
if git fetch -q origin model-pool; then
git checkout -q -B model-pool FETCH_HEAD
else
git checkout -q --orphan model-pool
fi

mkdir -p pool
if [ ! -f pool/README.md ]; then
cat > pool/README.md <<'EOF'
# model-pool

This orphan branch holds the Model Pool's published index document and
its detached signature, and nothing derived from them.

- `pool/index.json` — the signed index document.
- `pool/index.json.sig` — the detached Ed25519 signature (standard
base64) over the exact bytes of `pool/index.json`.

Both files are copies of what the relay serves; there is no count, no
leaderboard and no extracted statistic here. Verify them with:

```
node relay/verify.mjs pool/index.json pool/index.json.sig <public-key-base64>
```
EOF
fi

cp ../index.json pool/index.json
cp ../index.json.sig pool/index.json.sig

git add -A
if git diff --quiet && git diff --cached --quiet; then
echo "No change; nothing to publish."
exit 0
fi

version=$(node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync('../index.json', 'utf8')).version))")
git commit -q -m "pool: index version ${version}"
git push -q origin model-pool
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,22 @@ request goes to the provider that has been fastest for that kind of call.
Providers built in: OpenRouter, DeepSeek, GLM, Kimi, MiniMax, Qwen, Ollama and
any OpenAI-compatible endpoint.

## Model Pool

The picker can choose models from what other installs have found. It is on by
default: what an install sends is computed, text-free numbers about the models
it ran (role, model, a number, which model judged, door, size bucket, day) under
a per-install nonce, never code,
prompts, paths or an identity, and `codeaf pool status` shows exactly what is
waiting to go. Turn it off with `model_pool = off` on the settings sheet or
`CODEAF_MODEL_POOL=off`; `read` uses the pool and sends nothing. The relay
publishes a signed index the crew picker reads under `picked from = learn`. The index is mirrored on the `model-pool` branch at
`pool/index.json`. The design is [Pareto Crewing](docs/design/model-pool/pareto-crewing.pdf);
the relay's code is under `relay/`, with a [runbook](docs/design/model-pool/RUNBOOK.md)
that includes running your own.

[![pool updated](https://img.shields.io/github/last-commit/Agent-Field/CodeAF/model-pool?label=pool%20updated)](https://github.com/Agent-Field/CodeAF/tree/model-pool)

## Standing orders

Rules, reminders and watches are one thing, and you set them up by saying them.
Expand Down
21 changes: 16 additions & 5 deletions cmd/codeaf/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ func buildBrain(w *chatWindow, session string, opts brainOptions) (*chatBrain, e
// then let the machine form print underneath, which said one fact twice.
return nil, err
}
// A tier row that says auto is answered from this catalog (config.AutoModels),
// so the word is wired BEFORE the seats handed in are applied — a door whose
// ladder answered the word before this line resolved it from nothing. The
// read is the same non-blocking one, never a fetch.
modelCatalog := catalog.LoadLazy(context.Background(), catalog.Options{
BaseURL: settings.BaseURL, APIKey: settings.APIKey, Dir: settings.ProfileDir,
})
config.AutoModels = modelCatalog.ModelsNow
wirePoolIndex(settings.ProfileDir)
if opts.seats != nil {
applySeats(&settings, *opts.seats)
} else {
Expand All @@ -180,9 +189,6 @@ func buildBrain(w *chatWindow, session string, opts brainOptions) (*chatBrain, e
// to a tool the user has not been able to reach yet — the surface has not
// been drawn. Asking it in front of the first frame buys nothing and can
// cost fifteen seconds of dead terminal.
modelCatalog := catalog.LoadLazy(context.Background(), catalog.Options{
BaseURL: settings.BaseURL, APIKey: settings.APIKey, Dir: settings.ProfileDir,
})
// Every client built below shapes its requests against these rows: which
// knobs a model accepts is the catalog's answer, not a guess.
settings.Models = modelCatalog
Expand Down Expand Up @@ -545,9 +551,14 @@ func buildBrain(w *chatWindow, session string, opts brainOptions) (*chatBrain, e
fanIn = store.DependencyFanIn{}
}
// Ordinary leaves retain the byte-identical headless envelope, raised by
// exactly what their own fan-in measures — see gatheringGrant. Reflexes use
// the deliberately tiny rung budget and a seconds-scale watchdog.
// exactly what their own fan-in measures — see gatheringGrant. A leaf
// re-dispatched after running out is granted more than the attempt that
// ran out, or it would buy the same truncated ending again — see
// regrantAfterRunningOut; the wall below follows the larger grant because
// it is arithmetic over the same number. Reflexes use the deliberately
// tiny rung budget and a seconds-scale watchdog.
turns, tokens := gatheringGrant(chatLeafTurns, chatLeafTokens, fanIn)
tokens = regrantAfterRunningOut(tokens, int(node.Attempt))
leafRoom := exec.SubharnessFor(subharness)
wallLeft := remainingWall(ctx)
deadline := leafRoom.DeadlineWithin(tokens, wallLeft)
Expand Down
10 changes: 10 additions & 0 deletions cmd/codeaf/chatv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,15 @@ func openV3Launch(proc *v3Process, opts v3Options) (*v3Launch, error) {
media = v3ImageGen(mediaSettings)
}

// The Model Pool's judge reads every landing through the engine's one hook.
// It is built here, where the seats above are wired, so the answer to
// "may this process read the pool at all" is one posture for the whole
// door: a mode that forbids reading builds no hook, and a nil hook is the
// engine's own nothing. The ask is built once and a client is made from it
// per call, each billed to the judge's own seat.
taskLanded := poolJudgeHook(settings, settings.ProfileDir, workspace,
config.AutoModels, poolJudgeAsk(settings, settings.ProfileDir), time.Now)

cfg := session.Config{
Workspace: workspace,
Model: chosen,
Expand All @@ -905,6 +914,7 @@ func openV3Launch(proc *v3Process, opts v3Options) (*v3Launch, error) {
Sources: settings.Sources,
CompactEnabled: !opts.NoCompact,
SessionFile: transcript,
TaskLanded: taskLanded,
// The folder this conversation keeps everything in (Decision 26). It is
// the zero Place for a launch opened on a flat legacy transcript, which
// is what keeps that session deriving its sidecars the way it always did.
Expand Down
2 changes: 1 addition & 1 deletion cmd/codeaf/chatv3_crew_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func TestABrokenRowLeavesTheLastGoodCrewInPlace(t *testing.T) {
t.Fatal(err)
}
want, _ := config.CrewModels(config.CrewMax)
if model, _ := roles.Resolve(roles.Source(source), roles.RolePlanner, "vendor/conversation"); model != "moonshotai/kimi-k3" {
if model, _ := roles.Resolve(roles.Source(source), roles.RolePlanner, "vendor/conversation"); model != want[config.ModelTierMastermind] {
t.Fatalf("after the row parsed again the planner resolves to %q, want the max crew's %q",
model, want[config.ModelTierMastermind])
}
Expand Down
6 changes: 6 additions & 0 deletions cmd/codeaf/chatv3_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,12 @@ func hostOptions(fleet *engineFleet, welcome remote.Welcome, pick bool) (tui3.Op
}
discovery := catalog.Options{BaseURL: settings.BaseURL, APIKey: settings.APIKey, Dir: profileDir}
models := catalog.LoadLazy(context.Background(), discovery)
// A tier row that says auto is answered from this catalog (config.AutoModels):
// the same non-blocking read, never a fetch, and set once at start-up.
config.AutoModels = models.ModelsNow
// The pool's index is seated beside it, read once here and refreshed in the
// background, against the same profile the catalog was read from.
wirePoolIndex(profileDir)
// The refresh key in /model asks the same router THIS machine's list came
// from, and refills the same shelf — the list is this laptop's list of
// names on both doors (chatv3_modelshelf.go).
Expand Down
4 changes: 4 additions & 0 deletions cmd/codeaf/chatv3_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ func openV3ProcessWith(door string, askKey bool) (*v3Process, error) {
BaseURL: settings.BaseURL, APIKey: settings.APIKey, Dir: settings.ProfileDir,
}
models := catalog.LoadLazy(context.Background(), discovery)
// A tier row that says auto is answered from this catalog (config.AutoModels):
// the same non-blocking read, never a fetch, and set once at start-up.
config.AutoModels = models.ModelsNow
wirePoolIndex(settings.ProfileDir)
shelf := newV3ModelShelf(models, discovery)
shelf.setSources(settings.Sources)
return &v3Process{
Expand Down
57 changes: 57 additions & 0 deletions cmd/codeaf/context_budget_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,60 @@ func TestAFoldsGrantIsSizedForThePassItActuallyMakes(t *testing.T) {
t.Fatalf("an unsized window granted %d tokens, want the process-wide %d", unknown, want)
}
}

// A RE-DISPATCH IS GRANTED MORE ROOM THAN THE ATTEMPT THAT RAN OUT, or the
// identical budget buys the identical truncated ending. The runner's overrun
// settle releases a leaf that ran out back to pending with its banked turns,
// and while the grant was attempt-blind the next claim re-entered the same
// brief under the same meter and stopped at the same place — one truncation,
// paid for as many times as the round cap allowed.
func TestARedispatchIsGrantedMoreRoomThanTheAttemptThatRanOut(t *testing.T) {
// Attempt zero keeps the grant byte for byte: a leaf on its first claim
// has run out of nothing yet.
if room := regrantAfterRunningOut(chatLeafTokens, 0); room != chatLeafTokens {
t.Fatalf("a first claim was granted %d tokens, want the flat %d it has always had",
room, chatLeafTokens)
}

// Half again per re-dispatch, compounding, and strictly more room each
// time — the growth is the whole point of sending a node round again.
previous := chatLeafTokens
for attempt := 1; attempt <= 3; attempt++ {
room := regrantAfterRunningOut(chatLeafTokens, attempt)
if room <= previous {
t.Fatalf("re-dispatch %d was granted %d tokens, no more than the %d before it",
attempt, room, previous)
}
previous = room
}
// The exact arithmetic, in the integers the grant is stated in: three
// halves, applied per attempt, never rounded up by a shortcut.
if got, want := regrantAfterRunningOut(chatLeafTokens, 2), chatLeafTokens*3/2*3/2; got != want {
t.Fatalf("attempt 2 was granted %d tokens, want the twice-grown %d", got, want)
}

// The ceiling holds at attempts no run can reach, and the ladder stops
// there rather than stepping over it.
for _, attempt := range []int{10, 100} {
if room := regrantAfterRunningOut(chatLeafTokens, attempt); room != overrunGrantCeiling {
t.Fatalf("attempt %d was granted %d tokens, want the ceiling %d",
attempt, room, overrunGrantCeiling)
}
}

// A leaf whose fan-in already measured more than the ceiling keeps every
// token it measured. The bound is on what the ladder adds, and a
// re-dispatch handed less room than its first attempt would be the
// identical-budget defect back by another door.
_, measured := gatheringGrant(chatLeafTurns, chatLeafTokens,
store.DependencyFanIn{Count: 8, Bytes: 8 << 20})
if measured <= overrunGrantCeiling {
t.Fatalf("the wide join measured %d tokens, too small to ask the question", measured)
}
for _, attempt := range []int{1, 3, 100} {
if room := regrantAfterRunningOut(measured, attempt); room != measured {
t.Fatalf("a join measured at %d tokens was re-dispatched at %d on attempt %d",
measured, room, attempt)
}
}
}
51 changes: 51 additions & 0 deletions cmd/codeaf/coredone_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"path/filepath"
"testing"
"time"

"github.com/Agent-Field/codeaf/internal/store"
)

// THE ENVELOPE SAYS WHEN THE REQUESTED WORK WAS FIRST FOUND DONE, in seconds
// from the run's start, off the journal's own gate event — and leaves the key
// out when no gate ever said so, because a fabricated instant is worse than an
// absent one.
func TestTheEnvelopeSaysWhenTheRequestedWorkWasDone(t *testing.T) {
graph, err := store.Open(filepath.Join(t.TempDir(), "coredone.db"))
if err != nil {
t.Fatal(err)
}
defer graph.Close()

const gated, ungated = "session-gated", "session-ungated"
spliceForErrand(t, graph, gated, []store.NodeSpec{{ID: "task-1", Brief: "add the flag"}})
spliceForErrand(t, graph, ungated, []store.NodeSpec{{ID: "task-2", Brief: "add the other flag"}})
if err := graph.RecordDeliveryGate("task-1", store.DeliveryGate{Pass: true}); err != nil {
t.Fatal(err)
}
_, at, ok, err := graph.DeliveryGateAnchor("task-1")
if err != nil || !ok {
t.Fatalf("the passing gate has no anchor: ok=%t err=%v", ok, err)
}
started := at.Add(-7 * time.Second)

gatedOutcome := headlessOutcome{started: started}
priceErrand(graph, gated, 0, &gatedOutcome)
fields := envelopeFields(t, errandEnvelope(gatedOutcome))
got, present := fields["core_done_seconds"]
if !present {
t.Fatal("a gate found the work done and the envelope says nothing about when")
}
if seconds, ok := got.(float64); !ok || seconds < 6.9 || seconds > 7.1 {
t.Fatalf("core_done_seconds = %v, want about 7", got)
}

// And absent when no gate ever said the work was done.
ungatedOutcome := headlessOutcome{started: started}
priceErrand(graph, ungated, 0, &ungatedOutcome)
if _, present := envelopeFields(t, errandEnvelope(ungatedOutcome))["core_done_seconds"]; present {
t.Fatal("a run whose gate never found the work done reported when it was")
}
}
Loading