From aae899e881daa4586ff3cb3d8d4c32e9113213f5 Mon Sep 17 00:00:00 2001 From: Josh Mabry Date: Fri, 28 Aug 2026 15:49:02 -0700 Subject: [PATCH] chore(changelog): give every unreleased fragment a linked marketing title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `scaffold()` builds the public changelog from `_titles()`, which takes each bullet's **bold lead** — or, with no bold, falls back to the first clause and ships a run-on truncated mid-sentence. Six unreleased fragments had no bold lead at all, so this release's Context Architecture v2 work would have appeared on the marketing changelog as six half-sentences. `_strip_md` also drops `(ADR ...)` parentheticals wholesale, so a ref written as `(ADR 0108 D4, #3242)` lost the PR number along with the ADR id — six more fragments had no link in their title. Splitting them into `(#NNNN) (ADR 0108 Dx)` keeps both: the changelog body cites the ADR, the marketing title keeps the link. Verified by running the real extractor over every fragment: 29/29 now produce a titled, linked, single-sentence entry. Also corrects two wrong ADR references: #3190 cited D6 (the delivery budget) but implements D3 (capability-derived prompt), and #3191 cited D2 (projection) but implements D5 (prompt observability). No behavior change; fragments are unreleased and collate at release time. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01WEMxBi71vjtmmmziFCMcby --- changelog.d/3188.added.md | 6 +++++- changelog.d/3190.added.md | 5 ++++- changelog.d/3191.added.md | 5 ++++- changelog.d/3230.fixed.md | 5 ++++- changelog.d/3232.added.md | 5 ++++- changelog.d/3234.removed.md | 4 +++- changelog.d/3242.added.md | 2 +- changelog.d/3243.added.md | 2 +- changelog.d/3244.added.md | 2 +- changelog.d/3245.fixed.md | 2 +- changelog.d/3246.added.md | 2 +- changelog.d/3247.added.md | 2 +- changelog.d/3248.fixed.md | 2 +- changelog.d/3249.added.md | 2 +- changelog.d/3252.added.md | 2 +- changelog.d/3255.fixed.md | 2 +- changelog.d/3256.fixed.md | 2 +- changelog.d/3258.added.md | 2 +- 18 files changed, 36 insertions(+), 18 deletions(-) diff --git a/changelog.d/3188.added.md b/changelog.d/3188.added.md index d6e9bc9b4..7c4589aa6 100644 --- a/changelog.d/3188.added.md +++ b/changelog.d/3188.added.md @@ -1 +1,5 @@ -- Context projection (ADR 0108 D2): derived context frames (memory, skills, working state, tool-delta notices) are now delivered ephemerally via `wrap_model_call(request.override)` instead of being checkpointed as conversation history. This eliminates stale context accumulation in long-running threads and reduces checkpoint size. +- **Per-turn context is delivered, not stored (#3188) (ADR 0108 D2).** + Derived context frames (memory, skills, working state, tool-delta notices) are now + delivered ephemerally via `wrap_model_call(request.override)` instead of being + checkpointed as conversation history. This eliminates stale context accumulation in + long-running threads and reduces checkpoint size. diff --git a/changelog.d/3190.added.md b/changelog.d/3190.added.md index 90fe8a68f..d4b679e5a 100644 --- a/changelog.d/3190.added.md +++ b/changelog.d/3190.added.md @@ -1 +1,4 @@ -- Capability-derived operating model (ADR 0108 D6): the system prompt's operating model and guidelines sections now reference only tools that are actually bound, eliminating instructions for unavailable capabilities in stripped deployments and subagents. +- **The system prompt describes only the tools the agent actually has (#3190) (ADR 0108 D3).** + The operating model and guidelines sections now reference only tools that are actually + bound, so capability-stripped deployments and subagents stop receiving instructions for + capabilities they cannot use. diff --git a/changelog.d/3191.added.md b/changelog.d/3191.added.md index 2caac878f..7a384b4af 100644 --- a/changelog.d/3191.added.md +++ b/changelog.d/3191.added.md @@ -1 +1,4 @@ -- Prompt observability (ADR 0108 D2): the projected context (memory, skills, working state, tool-delta notices) is now captured alongside each prompt snapshot, closing the gap where dynamic context frames were absent from the last-call and per-task views. +- **Prompt snapshots capture the context the model was actually given (#3191) (ADR 0108 D5).** + The projected context (memory, skills, working state, tool-delta notices) is now captured + alongside each prompt snapshot, closing the gap where dynamic context frames were absent + from the last-call and per-task views. diff --git a/changelog.d/3230.fixed.md b/changelog.d/3230.fixed.md index cf4d2b691..e7e85ece8 100644 --- a/changelog.d/3230.fixed.md +++ b/changelog.d/3230.fixed.md @@ -1 +1,4 @@ -- Thread `bound_tool_names` through cache warmer and ACP runtime so capability-stripped deployments warm the correct prompt prefix and receive only the operating-model sections for their bound tools. +- **The cache warmer and the ACP runtime warm the prompt the agent will actually send (#3230).** + `bound_tool_names` is threaded through both, so capability-stripped deployments warm the + correct prefix instead of a different one, and receive only the operating-model sections + for their bound tools. diff --git a/changelog.d/3232.added.md b/changelog.d/3232.added.md index 87b69c505..102a80dc8 100644 --- a/changelog.d/3232.added.md +++ b/changelog.d/3232.added.md @@ -1 +1,4 @@ -- Subagent roster dedup (ADR 0108 D3): the system prompt's subagent section now lists only the 3 lead-visible subagents (researcher, dream, distill), omitting 7 workflow-internal ones that the lead agent never picks directly — a ~2,000 char prompt reduction. +- **The subagent roster lists only the subagents the lead can actually pick (#3232) (ADR 0108 D3).** + The system prompt's subagent section now lists the 3 lead-visible subagents (researcher, + dream, distill) and omits 7 workflow-internal ones the lead never delegates to directly — + a ~2,000 character prompt reduction. diff --git a/changelog.d/3234.removed.md b/changelog.d/3234.removed.md index 8ea23d015..b39e63c59 100644 --- a/changelog.d/3234.removed.md +++ b/changelog.d/3234.removed.md @@ -1 +1,3 @@ -- Removed legacy `context`/`context_sections` state channel (ADR 0108 D2 cleanup): knowledge context delivery now uses only the ephemeral middleware projection path introduced in #3226 — the old checkpointed state keys are removed from the graph schema. +- **The legacy `context`/`context_sections` state channel is gone (#3234) (ADR 0108 D2).** + Knowledge context delivery now uses only the ephemeral middleware projection introduced in + #3226; the old checkpointed state keys are removed from the graph schema. diff --git a/changelog.d/3242.added.md b/changelog.d/3242.added.md index 39fbda5aa..e6ca857e7 100644 --- a/changelog.d/3242.added.md +++ b/changelog.d/3242.added.md @@ -1,4 +1,4 @@ -- **Memory rows now say when they enter the prompt (ADR 0108 D4, #3242)**. A new +- **Memory rows now say when they enter the prompt (#3242) (ADR 0108 D4).** A new `delivery_policy` column on the knowledge store — `always` (every turn, what `domain="hot"` has always meant), `retrieved` (on a relevant query; the default, and what an untyped row reads as) or `on_demand` (only through `memory_recall`) — rides diff --git a/changelog.d/3243.added.md b/changelog.d/3243.added.md index 15e359f34..7e938b95e 100644 --- a/changelog.d/3243.added.md +++ b/changelog.d/3243.added.md @@ -1 +1 @@ -- **One context projection for every runtime (ADR 0108 D8).** The per-turn volatile composer is now a standalone function, `graph.projection.compose_projected_context()`, that both the native `KnowledgeMiddleware` and external runtimes (`runtime/context.py`, the ACP path) call. An external brain is fed exactly what the native loop injects — the `` envelope, always-on hot memory, trust-ranked and namespace-scoped RAG hits, the budgeted `` index, and `` — with the incognito rule and the injection log applied identically; `middleware.knowledge: false` now withholds memory on the ACP runtime too, and injection rows are recorded only for attributable turns. Per-turn native output is unchanged for a given cache state (golden-tested). The digest loader now runs only on turns that can use the digest (not incognito or goal turns) — main refreshed the cache unconditionally; per-turn output for a given cache state is unchanged. The result is a typed `ProjectedContext`. +- **One context projection for every runtime (#3243) (ADR 0108 D8).** The per-turn volatile composer is now a standalone function, `graph.projection.compose_projected_context()`, that both the native `KnowledgeMiddleware` and external runtimes (`runtime/context.py`, the ACP path) call. An external brain is fed exactly what the native loop injects — the `` envelope, always-on hot memory, trust-ranked and namespace-scoped RAG hits, the budgeted `` index, and `` — with the incognito rule and the injection log applied identically; `middleware.knowledge: false` now withholds memory on the ACP runtime too, and injection rows are recorded only for attributable turns. Per-turn native output is unchanged for a given cache state (golden-tested). The digest loader now runs only on turns that can use the digest (not incognito or goal turns) — main refreshed the cache unconditionally; per-turn output for a given cache state is unchanged. The result is a typed `ProjectedContext`. diff --git a/changelog.d/3244.added.md b/changelog.d/3244.added.md index fa56d9207..2fc3c3bb6 100644 --- a/changelog.d/3244.added.md +++ b/changelog.d/3244.added.md @@ -1 +1 @@ -- **The four prompt contracts are documented and size-gated (ADR 0108, #3244)**. `docs/explanation/prompt-contracts.md` spells out what goes into the lead, subagent, external/ACP and provider-transformed prompts — builder, section order, exclusions, knobs — with a measured size table, and `tests/test_prompt_budgets.py` turns that table into CI goldens: per-section ceilings at measured x1.2 plus the structural invariants (lead-visible roster only, capability-derived doctrine never names an unbound tool, ACP prefix equals the lead prompt, provider transforms preserve the composed text). A prompt that silently grows now fails the build with the actual and allowed sizes printed. +- **The four prompt contracts are documented and size-gated (#3244) (ADR 0108).** `docs/explanation/prompt-contracts.md` spells out what goes into the lead, subagent, external/ACP and provider-transformed prompts — builder, section order, exclusions, knobs — with a measured size table, and `tests/test_prompt_budgets.py` turns that table into CI goldens: per-section ceilings at measured x1.2 plus the structural invariants (lead-visible roster only, capability-derived doctrine never names an unbound tool, ACP prefix equals the lead prompt, provider transforms preserve the composed text). A prompt that silently grows now fails the build with the actual and allowed sizes printed. diff --git a/changelog.d/3245.fixed.md b/changelog.d/3245.fixed.md index d0f63b5d5..acae3f397 100644 --- a/changelog.d/3245.fixed.md +++ b/changelog.d/3245.fixed.md @@ -1 +1 @@ -- **Layered knowledge stores no longer break memory_list, fact dedup, and snapshot export** (#3245). `LayeredKnowledgeStore.list_chunks()` returned tier-tagged dicts while every other store returns `Chunk` rows, so with a commons configured the `memory_list` tool crashed, fact consolidation silently stopped de-duplicating, and the agent snapshot's knowledge seed exported empty. Rows are now `Chunk` objects with a `tier` field ("private" / "commons"); the console's tier badges are unchanged. +- **A configured commons no longer breaks memory listing, fact dedup and snapshot export (#3245).** `LayeredKnowledgeStore.list_chunks()` returned tier-tagged dicts while every other store returns `Chunk` rows, so with a commons configured the `memory_list` tool crashed, fact consolidation silently stopped de-duplicating, and the agent snapshot's knowledge seed exported empty. Rows are now `Chunk` objects with a `tier` field ("private" / "commons"); the console's tier badges are unchanged. diff --git a/changelog.d/3246.added.md b/changelog.d/3246.added.md index 53d953361..637aa9dbb 100644 --- a/changelog.d/3246.added.md +++ b/changelog.d/3246.added.md @@ -1,4 +1,4 @@ -- **Every memory now has a write lifecycle (ADR 0108 D7, #3246)**. A chunk is typed +- **Every memory now has a write lifecycle (#3246) (ADR 0108 D7).** A chunk is typed on the way in — the store stamps an omitted `memory_kind` from its domain and an omitted `review_state` from who wrote it: rows the operator adds through the console start `confirmed`, rows the agent stores or ingests start `pending`. diff --git a/changelog.d/3247.added.md b/changelog.d/3247.added.md index fd0c8f897..36b476368 100644 --- a/changelog.d/3247.added.md +++ b/changelog.d/3247.added.md @@ -1 +1 @@ -- **Injected context is now bounded and policy-driven (ADR 0108 D6, #3247)**. A new `context.budget_pct` (default 8% of the model window, never below 16k chars) caps everything injected per turn; over budget the lowest-priority parts shed first — recalled knowledge, then the prior-session digest, then skill descriptions one at a time (names never drop) — while working state and always-on memory are never shed. Always-on memory is now selected by `delivery_policy="always"` rather than the `hot` domain (every hot write already carries it), so a fact on any domain can be pinned always-on, and rejected or expired rows never enter the prompt. The prompt preview API carries the budget summary and per-section `truncated` flags; the inspector renders them in a follow-up. +- **Injected context is now bounded and policy-driven (#3247) (ADR 0108 D6).** A new `context.budget_pct` (default 8% of the model window, never below 16k chars) caps everything injected per turn; over budget the lowest-priority parts shed first — recalled knowledge, then the prior-session digest, then skill descriptions one at a time (names never drop) — while working state and always-on memory are never shed. Always-on memory is now selected by `delivery_policy="always"` rather than the `hot` domain (every hot write already carries it), so a fact on any domain can be pinned always-on, and rejected or expired rows never enter the prompt. The prompt preview API carries the budget summary and per-section `truncated` flags; the inspector renders them in a follow-up. diff --git a/changelog.d/3248.fixed.md b/changelog.d/3248.fixed.md index 0d3aa3033..9ae4e9f6f 100644 --- a/changelog.d/3248.fixed.md +++ b/changelog.d/3248.fixed.md @@ -1 +1 @@ -- **The ACP brain's persona (AGENTS.md) and the external ContextAssembler prefix now describe only the tools the operator MCP bus actually exposes (#3248)**. Both are derived from the same allowlist the sidecar is handed (the configured names, or every tool when unset) under the sidecar's own boot assumptions, resolved at the first turn — never guessed — so the persona no longer names `set_goal`, `schedule_task`, tasks or "subagents" when the bus does not serve them, and the prefix carries no Subagent Delegation roster or doctrine for unexposed capabilities. Fixed on the way: a standalone operator-MCP sidecar now registers the plugin bundle's goal verifiers (verifier-gated goal and watch tools were served as nothing while the host claimed all of them) and applies the fork tool denylist, the operator MCP filters `tools.disabled`/`tools.hidden` names it previously kept serving, `create_watch` can be exposed when watches are enabled, the operating model names `task` only when it is bound, `PROTOAGENT_MCP_TRUST` reaches the spawned sidecar, and `GET /api/mcp/exposed` reports the sidecar's set under an ACP runtime. +- **The external agent is told about the tools its bus actually serves (#3248).** The ACP brain's persona (AGENTS.md) and the external `ContextAssembler` prefix now describe only what the operator MCP bus exposes. Both are derived from the same allowlist the sidecar is handed (the configured names, or every tool when unset) under the sidecar's own boot assumptions, resolved at the first turn — never guessed — so the persona no longer names `set_goal`, `schedule_task`, tasks or "subagents" when the bus does not serve them, and the prefix carries no Subagent Delegation roster or doctrine for unexposed capabilities. Fixed on the way: a standalone operator-MCP sidecar now registers the plugin bundle's goal verifiers (verifier-gated goal and watch tools were served as nothing while the host claimed all of them) and applies the fork tool denylist, the operator MCP filters `tools.disabled`/`tools.hidden` names it previously kept serving, `create_watch` can be exposed when watches are enabled, the operating model names `task` only when it is bound, `PROTOAGENT_MCP_TRUST` reaches the spawned sidecar, and `GET /api/mcp/exposed` reports the sidecar's set under an ACP runtime. diff --git a/changelog.d/3249.added.md b/changelog.d/3249.added.md index 656ab8870..a5f9fa9e7 100644 --- a/changelog.d/3249.added.md +++ b/changelog.d/3249.added.md @@ -1 +1 @@ -- **Confirm, reject, or re-open agent-written memories from the console (ADR 0108 D7, #3249)**. Knowledge → Store and Memory → Hot memory rows show a review chip, pending rows get Confirm / Reject actions, and a pending-review filter queues everything awaiting a verdict. Commons rows stay read-only. +- **Confirm, reject, or re-open agent-written memories from the console (#3249) (ADR 0108 D7).** Knowledge → Store and Memory → Hot memory rows show a review chip, pending rows get Confirm / Reject actions, and a pending-review filter queues everything awaiting a verdict. Commons rows stay read-only. diff --git a/changelog.d/3252.added.md b/changelog.d/3252.added.md index 8e7418ca8..f9baaa506 100644 --- a/changelog.d/3252.added.md +++ b/changelog.d/3252.added.md @@ -1 +1 @@ -- **The prior-session digest is now evaluated, not blindly injected (ADR 0108 D9, #3252)**. A session's own summary is never listed as a "prior" session (it was the newest entry in its own digest from turn 2 on), a new `context.prior_sessions` policy picks what the digest recalls — `newest` (default, unchanged), `relevant` (only sessions matching the turn's query via session-search FTS, falling back to newest), or `off` (on-demand `session_search`/`recall_session` only) — and under the context budget the digest sheds entry by entry (oldest or lowest-rank first) instead of vanishing whole. +- **The prior-session digest is now evaluated, not blindly injected (#3252) (ADR 0108 D9).** A session's own summary is never listed as a "prior" session (it was the newest entry in its own digest from turn 2 on), a new `context.prior_sessions` policy picks what the digest recalls — `newest` (default, unchanged), `relevant` (only sessions matching the turn's query via session-search FTS, falling back to newest), or `off` (on-demand `session_search`/`recall_session` only) — and under the context budget the digest sheds entry by entry (oldest or lowest-rank first) instead of vanishing whole. diff --git a/changelog.d/3255.fixed.md b/changelog.d/3255.fixed.md index 250d09a69..3f87fca7f 100644 --- a/changelog.d/3255.fixed.md +++ b/changelog.d/3255.fixed.md @@ -1,4 +1,4 @@ -- **The `self_improvement` policy knobs accept a bare `on`/`off` in YAML.** These are +- **The `self_improvement` policy knobs accept a bare `on`/`off` in YAML (#3255).** These are `off | propose | auto` strings, but YAML 1.1 parses a bare `off` as the boolean false and `on` as true — so `skills: on` was stored as the string `"True"`, and `soul_md: off` landed on the right answer only because a magic `or "off"` literal in the parse happened diff --git a/changelog.d/3256.fixed.md b/changelog.d/3256.fixed.md index b50089952..70ca1b518 100644 --- a/changelog.d/3256.fixed.md +++ b/changelog.d/3256.fixed.md @@ -1,4 +1,4 @@ -- **The context budget follows the model a chat tab is actually using.** The console lets +- **The context budget follows the model a chat tab is actually using (#3256).** The console lets each tab pick its own model, but everything sized off the model's context window — the projected-context budget, the skill-index cap, the tool-result pruning trigger — was frozen when the graph was compiled. A tab switched to a smaller model kept the default model's diff --git a/changelog.d/3258.added.md b/changelog.d/3258.added.md index 13eec21fb..e96d47951 100644 --- a/changelog.d/3258.added.md +++ b/changelog.d/3258.added.md @@ -1,4 +1,4 @@ -- **Remembering something now records which session you were in when it happened.** The agent's +- **Remembering something now records which session you were in when it happened (#3258).** The agent's own memory writes carried no provenance: `memory_recall` has cited each row's source session since ADR 0069 D5, but only harvested and operator-written rows ever set it, so anything the agent chose to remember came back uncited. It now stamps the originating session, read from the