Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
id: itd-2610071035233981
slug: bob-asks-for-an-answer-in-a-shape-he-defines-and-gets
spec_id: null
kind: null
suggested_kind: null
reclassification_history: []
builds_on: []
severity: minor
origin: researcher-authored
production_mode: hand-written
---

# Bob gets answers in the exact JSON shape he asks for

## Press Release

> Bob asks for an answer in a shape he defines and gets exactly that shape. He sends a JSON schema with his request, the way OpenAI clients already do, and Dessau makes the model answer only with JSON that fits it, so his script can read the answer without checking and retrying. A schema Dessau cannot apply is refused with the reason before the model starts, rather than producing an answer that does not fit.

## Why This Matters

> _Why this matters to the user — replace before planning._

## Mechanism

> _Prompted (the claim-recording gradient): why the authors expect this to work, as a falsifiable "we expect X because Y" — not the outcome restated. Replace this line with the claim, or with the exact token `None stated.` alone on its line to record the claim as considered and declined._

## Scope Conditions

> _Required (the claim-recording gradient): the population, platform, scale, or assumptions this claim holds under, one per top-level bullet — `abcd intent plan` stamps each with a persistent identity. Replace this line with those bullets, or with the exact token `None stated.` alone on its line._

## Acceptance Criteria

> _Required (the itd-1 discipline): add at least one Given-When-Then bullet describing the verifiable bar for "shipped" before this draft can be planned._

## Open Questions

_None recorded yet._

## Audit Notes

_Empty. Populated by intent-auditor when intent moves to shipped/._
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
id: itd-2610071035236103
slug: alice-fits-a-longer-conversation-or-one-more-model-into-the
spec_id: null
kind: null
suggested_kind: null
reclassification_history: []
builds_on: []
severity: minor
origin: researcher-authored
production_mode: hand-written
---

# Alice fits a longer conversation, or one more model, into the same memory

## Press Release

> Alice fits a longer conversation, or one more model, into the same memory. In a model's settings she turns on compact conversation memory, and Dessau keeps that model's working memory for each conversation at about half its usual size, so the window it serves can grow or another model can stay loaded beside it. Alice chooses this per model, because a model kept compact answers one request at a time and may answer very long prompts slightly less exactly; the setting tells her both before she turns it on, and nothing turns it on by itself.

## Why This Matters

> _Why this matters to the user — replace before planning._

## Mechanism

> _Prompted (the claim-recording gradient): why the authors expect this to work, as a falsifiable "we expect X because Y" — not the outcome restated. Replace this line with the claim, or with the exact token `None stated.` alone on its line to record the claim as considered and declined._

## Scope Conditions

> _Required (the claim-recording gradient): the population, platform, scale, or assumptions this claim holds under, one per top-level bullet — `abcd intent plan` stamps each with a persistent identity. Replace this line with those bullets, or with the exact token `None stated.` alone on its line._

## Acceptance Criteria

> _Required (the itd-1 discipline): add at least one Given-When-Then bullet describing the verifiable bar for "shipped" before this draft can be planned._

## Open Questions

_None recorded yet._

## Audit Notes

_Empty. Populated by intent-auditor when intent moves to shipped/._
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
id: itd-2610071035237873
slug: bob-s-coding-assistant-picks-up-where-it-left-off-without
spec_id: null
kind: null
suggested_kind: null
reclassification_history: []
builds_on: []
severity: minor
origin: researcher-authored
production_mode: hand-written
---

# Bob's assistant picks up where it left off after Dessau unloads the model

## Press Release

> Bob's coding assistant picks up where it left off without waiting for Dessau to reread the whole conversation. When Dessau unloads a model to make room, or restarts, it keeps the work it had already done on Bob's long prompts on this Mac's disk, in Alice's own account, and uses it again when the same conversation returns, so his next answer starts in a second or two rather than after the model has reread tens of thousands of tokens. Nothing from one model's saved work is ever used for another model or another version of it, and Alice can see how much disk it uses and clear it.

## Why This Matters

> _Why this matters to the user — replace before planning._

## Mechanism

> _Prompted (the claim-recording gradient): why the authors expect this to work, as a falsifiable "we expect X because Y" — not the outcome restated. Replace this line with the claim, or with the exact token `None stated.` alone on its line to record the claim as considered and declined._

## Scope Conditions

> _Required (the claim-recording gradient): the population, platform, scale, or assumptions this claim holds under, one per top-level bullet — `abcd intent plan` stamps each with a persistent identity. Replace this line with those bullets, or with the exact token `None stated.` alone on its line._

## Acceptance Criteria

> _Required (the itd-1 discipline): add at least one Given-When-Then bullet describing the verifiable bar for "shipped" before this draft can be planned._

## Open Questions

_None recorded yet._

## Audit Notes

_Empty. Populated by intent-auditor when intent moves to shipped/._
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

> The user's directory is theirs: a tool never creates directories beside the
> user's projects or anywhere the user did not hand over; session and agent
> scratch (a worktree, a verifier's copy, an export) goes under ~/.abcd/ keyed
> scratch (a worktree, a verifier's copy, an export) goes under ~/.abcd.noindex/ keyed
> on the root-commit SHA, or the checkout's .abcd/.work.local/ tier — see
> .abcd/development/principles/the-users-directory-is-theirs.md.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -844,3 +844,23 @@ with a switch.
Verdict proposed: FILE-AS-IS with both switches. Verdict adopted after the two
reviews: one switch, an ADR the routing had not named, and pins and grace
protected. Grade: routing survived in part.

## 2026-10-07 — SOTA research on MLX serving performance, routed to seven records

Request: "Conduct SOTA on how to optimise performance of MLX models. What do
other servers offer that Dessau doesn't (yet)?" The research note stayed in
the local tier; its gap table was routed.

| part | type | home |
|---|---|---|
| Prompt cache with no byte limit | defect (runtime) | iss-2610071035130302 |
| Twice as many requests admitted as charged | defect (runtime) | iss-2610071035138788 |
| Batching default never measured here | evidence task | iss-2610071035147427 |
| MTP speculative decoding | waiting on upstream | iss-2610071035141725 |
| Per-model compact KV memory | capability | itd-2610071035236103 (draft) |
| Prompt cache kept on disk across unloads | capability | itd-2610071035237873 (draft) |
| Structured output to a schema | capability | itd-2610071035233981 (draft) |
| Vision, embeddings, rerank; mlx-vlm pin bump | held | not filed |

Verdict proposed: SPLIT into four issues and three drafts, with the rest held.
Verdict adopted: the same, unchanged. Grade: routing survived.
4 changes: 4 additions & 0 deletions .abcd/work/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,3 +452,7 @@
- 2026-10-04 — **A context probe's bounds carry the provenance they were made under, and are dropped when it moves** (iss-2610032241096901; branch `fix/probe-resume-clamps-window`; `impact: fix`). The record offered two remedies: clamp `b.hi` to the served window on resume, or drop bounds made under another provenance. Dropping fits the measurement model in `internal/registry/measurement.go`, where a figure holds only under the runtime, budget, decode concurrency and served window it was taken under and moving any one makes it stale; clamping repairs only `hi`, leaves `lo` verified above the new window and a guard reading taken under the old budget, and still stamps the mixed result current. So the bounds record `Sources.Provenance` at creation, and take their ceiling `hi` from that same read's served window rather than from the candidate list, so the bound and the stamp cannot come from two reads either side of a move; a resume under a different one starts over, a run whose provenance moves with no yield between saves nothing and stays queued or due, and a saved figure is stamped with the bounds' provenance and judged against what is in force once it is written (`probeSources.Save` re-judges after `SetMeasurement`), so a settings save landing between the last check and the save marks the figure stale instead of leaving it current; the settings save's own re-judging may already have run by then, so it alone does not catch that move (amended after the independent review). Reproduced by two tests that saved 32,231 and 64,365 tokens under a served window of 8,192 before the change. What would show this wrong: a saved measurement whose window is above the served window it is stamped with.
- 2026-10-04 — **A settings save re-judges measurements after the pool takes the new budget** (iss-2610042040451551; branch `fix/probe-provenance-followup`; `impact: fix`). `SetConfig` ran `refreshStaleness` before `Pool.SetMemoryBudget`, and the provenance's `BudgetBytes` reads the pool, so a budget save was judged against the old budget: a figure stamped 82,463,372,083 bytes read current under 41,231,686,041 until the next start. Not every figure, though: the provenance's `ServedContext` comes from `ServedWindow`, which derives an automatic window from the configuration's budget (`memoryBudget`, that is `enforcedBudget(Config().MaxResidentBytes)`), already stored by then, so a model whose automatic window follows the budget did read stale (`served_context`). The miss was a model with a set window, no KV charge, or an automatic window clamped at its declared size. Two remedies: move the re-judging after the budget is applied, or have `provenanceFor` read `BudgetBytes` from the configuration as well. The pool's figure was kept: it is what enforces the budget, the probe's memory guard measures against it (`probeSources.Available`), and `TestTheProvenanceIsWhatThePoolAndTheRuntimeSay` pins the provenance to it. So the provenance reads two homes, the pool for the budget and the configuration for the served window. They agree once a save has finished (the app is the pool's only writer and hands it `enforcedBudget` of the stored figure), but not between the configuration's store and `SetMemoryBudget`. A probe reading the provenance in that interval gets a mixed reading: its check before saving rejects a figure whose bounds were made under another reading, and a figure stamped with the mixed reading itself is judged against the finished settings by the re-judging that now runs last. That is why the reordering is still right: the re-judging moved to after `SetMemoryBudget` and `RefreshCharges`, once every setting the save changed is in force, and never sees a mixed reading. It also lifts a recorded load failure at once when a save moves only the budget, which `docs/context-probe.md` already promised (`TestABudgetOnlySaveLiftsALoadFailure`); before, the mark stood until the next start. What would show this wrong: a save that moves the budget leaving a measurement stamped with the old budget reading current.
- 2026-10-04 — **The 0.10.0 cut, codename Prellerhaus**, by hand on the 0.9.3 precedent, on the maintainer's instruction of 2026-10-04 ("autonomously cut a new release", then "fix all four, then cut"). The version is a minor because the release carries `impact: breaking` entries (the refused sampling values, the empty-prompt and non-string prompt refusals, the mlx-lm 0.32.0 runtime, the removal of shared-cache mode among them) and the project is below 1.0; `build/CODENAME` is unchanged, as at 0.8.0 and 0.9.0. Before the roll, the four fixes the 2026-10-04 handoff named as release essentials were built test-first on their own lanes, each reviewed independently (Opus; the gateway change adversarially on Fable) and merged on `integrate/0.10.0`: the non-string completions prompt refusal (iss-2610040805353721, adr-2610042021365934), a bridged history that opens on the user (iss-2610032306154631), the self-test honouring pins (iss-2610032241098944), and a resumed context probe dropping bounds made under other settings (iss-2610032241096901). The reviews' findings were fixed in the same cut rather than stepped over: a stuck Discord channel after an unanswered message (iss-2610042030092101, major), the bridge fallback's byte budget (iss-2610042030098334), the self-test loading a pinned model it could not then unload (fixed by skipping pinned, unloaded models, mirroring the probe), a budget change judged against the old budget (iss-2610042040451551); smaller ones were captured with remedies. itd-2610030857275099 and itd-2610031024247803 ship (specs closed, fidelity reviews ingested; criterion 9 of the first is recorded not met, pending itd-2610030656210408 step 2, iss-2610042101435880). The two open majors are deferred out loud with `deferred_after: "v0.10.0"`: iss-2609190242198542 (four of six live Discord checks passed on 2026-10-04; two postponed by the maintainer) and iss-2609200815308397 (the client builds and its script checks pass; the appearance switch is unchecked by hand). The roll is manual, as `abcd launch` still cannot cut this repository; the receipts protocol does not apply because `release.yml` arms no semantic gate. Retention after verification deletes the v0.9.3 release and keeps its tag.
- 2026-10-07 — **A staged update holds the old version aside until the new one has loaded and answered once, and puts it back when that first load fails** (iss-2610042101430192; branch `fix/staged-update-keeps-old-copy`; `impact: fix`). This narrows the 2026-10-03 reading of "removed after the new one passes readiness" as the directory checks alone: those checks stay what a swap is held to, and readiness for the old copy's removal is now the pool's own readiness — a load whose probe was answered (`LoadFinished` with no error), which is the first successful load, not one Dessau starts for the purpose (an update nobody asked to serve is still not loaded into memory). A first load that fails on its own, transient or not (an interrupted one does not count), puts the old version back through the same swap an update makes, claimed as a download so a Download, a Delete or Close waits for it; its record is rewritten with its own version, no load failure, `update_failed: "load"`, and the newer commit still offered. The held copy is in memory and on disk only, with no new registry field: across a restart the newest complete aside copy beside a model folder that checks out is held again (this supersedes the 2026-10-03 line that removed such a copy at start as stale), but its version is not known any more, so one put back after a restart is recorded as version unknown. A delete removes it with the model, since the next start would otherwise put it back; a later update replaces it. Rejected: a registry field carrying the old version across restarts (a new persisted field for one edge), and restoring only on non-transient failures (a fallback that waits for a hand retry after every timeout). What would show this wrong: a tester whose good update was rolled back by a slow first load, or an aside copy that outlives both a successful load and a start.
- 2026-10-07 — **The update check reads an LFS `config.json` from the content CDN, and a version whose config it cannot hold to the listed hash is `cannot_check`, never offered** (iss-2610042101439623; branch `fix/update-check-lfs-config`; `impact: fix`). The check treated the Hub's hand-off of an LFS `config.json` to its CDN (`ErrCrossOrigin`) as "offer it", so a newer version that names a `model_file` was marked `available`. `SmallFileAt` now takes the listed `File`: a git file still goes through `do` and its origin rule unchanged; a file the listing keeps in LFS with a 64-hex sha256 goes through `doContent`, which follows the CDN hop as the download does — the 2026-09-19 exception, extended to this one read and only where a sha256 anchors the bytes — drops the token from any hop off the Hub's origin, refuses a listed size past the 1 MiB bound before asking, and holds the body to the sha256 (`ErrContentMismatch`). Off-origin with no sha256, a mismatch, or past the bound records the new `cannot_check` status (card "newer version not checked", Update refused in Go and on the panel); a CDN or Hub that does not answer stays "unreachable" as before. Chosen over a status alone because reading the file is what names a version that ships code, which is the mark the card exists to show. What would show this wrong: a CDN that needs the token, which would turn every gated repository's LFS config into `cannot_check`.
- 2026-10-07 — **The idle clock counts client requests at the gateway, beside the pool's per-model figures** (iss-2610041945030758; branch `fix/idle-clock-counts-unreachable`; `impact: fix`). The idle check read only `Pool.Residency()`: each resident entry's `InFlight` and `lastUsed`. An entry that leaves the pool (unloaded, stopped by the health watch, crashed, evicted, reaped) takes its last use with it, and a request the pool never admitted (still uploading, refused, failed before a model was chosen) never touched one; so an unreachable request on a wedged model that was then taken out left no trace, and the remaining models' 17:34 last use was over the hour by 18:45. The pool was left alone: a pool-wide clock there would still miss requests that never reach `Acquire` and would put the change inside `internal/runtime`. Instead `selftest.Clients` counts every request to the completion routes and every `Ask` from the handler's start to its return, the gateway holds it through `Options.Clients` (wired in `cmd/dessau` from `App.Clients`), and `selftest.Activity` carries `Requests` and `LastRequest` to `heldBy`. The context probe drives its model through the gateway, so a last request no later than the loop's own latest release (`touched`) is discounted, as the pool's stamp of that release already is; the cost is that a client request that never reached the pool and ended entirely inside a run is discounted too. What would show this wrong: an idle job starting within the threshold of a client request that ended unreachable, or one held for the threshold after the probe's own run.
- 2026-10-07 — **The decision-model over-charge is folded into the decision-model spec, with no stopgap** (iss-2610041945038826; spc-2610030846273729 steps 2 and 4). Diagnosis showed that the charge is the automatic served window filling the budget, which applies to every model, not a decision-model KV reservation. The maintainer chose the spec over a joint-head stopgap with a guessed figure, and over reopening the 2026-09-20 window derivation for all models.
Loading