Adding the `ProjectionKeySelection` import to the projection cache moved its
`Config`/`inject` declaration down one line, so the config catalog's source
reference is regenerated. Only the source location changes.
The fold blank matrix counted every band that no row box covered, including
a band whose rows on both sides had already faded to opacity 0. Such a band
shows the same background as those rows. Kept intermediate replies move with
the layout while closing groups stay in place, so that band could exceed the
transient limit in side/composer/steps without any visible difference.
A band now counts when a visible row borders it on either side, with the
viewport top and the composer treated as visible. A synthetic-DOM case keeps
a band beside a visible row failing the measurement.
- Export `ProjectionKeySelection` (the read faces' key selection) and reuse it
from the projection cache instead of restating the union twice. The Cordis
catalog can now resolve the type its generated signatures reference.
- Make `wire.summary` a plain boolean: omitted means `true`, and a key whose
map entry carries the summary mark declares `false` so the runtime key set
and the client view type agree. The type no longer forbids a declaration.
- Describe the mark accurately: it has no runtime representation; `wire.view`
and `viewSchema` are typed with `SessionProjectionViewValue`, which strips it,
so the registration erase only widens the state type.
- Say plainly in the package README, the subsystem page, the client field
comments, and the Agent Note that a list row carries the summary projection
and never the full projection: a connected Session's store may hold more
values, but those are outside the list contract.
- Document the summary vocabulary on the subsystem page with `ts type-equiv`
blocks for the mark, its stripping, the excluded-key test, the summary value
type, and the key selection; split the prose paragraph.
- Revert the behavior-neutral cache-double refactors in three specs, and record
in the Agent Note why no upgrade guide accompanies the wire change and how a
consumer migrates.
The group-tree JSDoc and the ui-chat README stated that every reply stays outside whole-Turn folding and named only the collapse-timing setting. They now distinguish All replies from Final answer only and link the new setting.
The seeded-history check measured the folded final answer 16px below the Turn control. Hidden process rows separate the two, so the answer now keeps the 12px reply gap.
The producer/consumer matrix points at the declaring line of each event. Adding
the `imageLimits` JSDoc and map-entry wrap moved the `api-session/*` declarations
in `packages/api/session-controller/src/types.ts` down by four lines, so the
graph pair is regenerated. Only source locations change.
`imageLimits` is a boot constant every Session shares: the unit stores no
per-Session state (`stateSchema: z.null()`, `apply: state => state`) and its
view returns `ctx.attachments.imageLimits`. A list row therefore repeated one
host-wide capability fact on every row. It now carries the summary mark like
the three log-derived units, so a summary read skips it while an opened Session
still receives it through `session/follow`, the control baseline, and
`session.projections`.
No other logic changes: the registration, its schema, its constant view, and
the host-side prompt validation keep reading `ctx.attachments` directly.
A folded Turn gave its final answer the control's 16px clearance through
compactAnswer and data-turn-process-answer, because hidden process rows
keep the answer from matching the control's adjacent-row rule. With every
reply kept, the final answer no longer follows the control, so that 16px
only widened the gap above it. In both choices the margin also switched
from 12px to 16px when the closing rows became hidden at the end of a
next-message fold, moving the answer down about 4px.
A reply separated from the control by folded rows now keeps the 12px reply
gap in both choices; only a row directly following the control receives
16px, and no reply changes its spacing when a fold finishes.
Settings goldens gain the Replies After Collapse row; folded-Turn aria
goldens for plan review, goal turns, and turn-tail actions include their
intermediate replies. The folded layout checks measure the intermediate
reply that now follows the Turn control at the 12px reply gap.
Whole-Turn folding chose the final answer by position, so a Turn that
continued after answering (a notice reply, record keeping, or a tool call)
hid the real answer with the process. A folded Turn now hides only its
process; every assistant-step reply row stays visible.
Settings -> General -> Replies After Collapse (ui-chat.foldedReplies,
default "all") switches back to the previous final-answer-only rule; the
choice applies immediately and is hidden in Verbose.
The note records why a Session-list row carries a summary key set instead of
every registered client view: the type-only exclusion mark with its
registration interlock, the derived stable key set reused through the existing
key-taking read faces, the nullable-wrapper rule for `todos`, and the estimated
payload effect of omitting `turnOutline`, `sessionStats`, and `todos`. It lists
the rejected alternatives (a summary-specific read face, a hardcoded key list,
post-hoc filtering, opt-in summaries, and lazy per-value reads) and the costs
the decision accepts.
The catalog pages embed the declaring source location of each documented type.
Adding the summary-exclusion import and map-entry JSDoc to
`packages/todo/tool-todo/src/types.ts` moved `TodoItem` and `todo/write` two
lines down, so both catalog languages and their pairing record are regenerated.
No type fingerprint changes: `verify-persistence-changes` still reports 65
roots matching 16 history records.
A second `gen-persistence-catalog` run is required after a schema change: the
page and the machine inventory are generated in one pass, and the page reads
the inventory as it was on disk.
`docs/persistence-schema.json` records the declaring source location of every
persisted type. Adding the summary-exclusion import and map-entry JSDoc to
`packages/todo/tool-todo/src/types.ts` moved two declarations down by two
lines, so the generated catalog is regenerated. No persisted type, field, or
history record changes: `verify-persistence-changes` reports 65 roots matching
16 history records, and the release/format catalogs are unchanged.
A Session-list row no longer carries every registered client view: the three
units whose values a list row never renders (`turnOutline`, `sessionStats`,
and `todos`) are excluded, which removes the whole-log turn outline and the
figure and todo payloads from every row. An opened Session is unchanged —
`session/follow`, the `session/control` baseline, and `session.projections`
still serve every projected key.
The exclusion is one type-level mark plus one registration interlock:
`SessionProjectionSummaryExcluded<T>` marks a map entry, and
`ProjectionDefinition.wire` requires `summary: false` exactly on a marked key
and rejects it everywhere else, so the mark and the declaration cannot drift.
A nullable entry keeps `null` outside the wrapper, so `todos` stays
`TodoItem[] | null`. `summaryKeys()` returns the derived set, stable until a
registration or its disposal changes the key table, and the existing
key-taking read faces (`cachedSnapshot`, `viewCheckpoint`) accept that set
directly, so summaries need no separate read face and no per-read key copy.
`packages/api/session-controller/src/list.ts` passes the set to the live and
cold cached faces; `cachedPredecessorTitle` is untouched.
Client types only: `SessionSummary.projectionValues` narrows to
`SessionProjectionSummaryValues`, `SessionProjectionSnapshot.values` keeps
every view value with the mark stripped, and no wire field or client name
changed. The cache, subsystem page, and package README document the summary
rule and the two read faces.
Set the autonomy ranges to hint 0-10, assist 15-25, pair 30-50, copilot
55-85, and auto 90-100 in the skill and the template level line, and
refill the example accordingly.
Sharpen the stage criteria where trial runs disagreed: grade design by
who supplied the adopted structure, count only the author in the first
four stages, ignore process and ordering instructions, define the main
change, keep review at n/a until a comment is handled, and separate
copilot from pair by whether every non-wording item got a human
response. Clarify the Changes categories, test evidence, disclosure
placement, language, and when to update the description.
Refs #6034
Correct the downlink-write activity contract for compressed frames: a write
that does not complete at once counts, and a frame above the threshold
deflates asynchronously so its completion always counts. The Host compresses
only its own outbound frames; uplink compression remains the peer's choice.
Stabilize the compressed-write liveness test with a 500 ms heartbeat interval
and assert the bounded half: after the downlink stops, missing Pongs still
terminate the socket.
Refs #6476
Start the template's review line as n/a, as the skill requires at PR
creation, and prompt for an Issue reference under Motivation. Read the
skill's stages only from its Stages and criteria section and reject a
stage name that does not pair one English word with a Chinese name.
Point the GIF disclosure row at record-browser-gif instead of copying
part of its list, merge the calibration notes into one TODO, replace the
design skeleton wording, and reduce the root AGENTS.md rule to a pointer.
Refs #6034
Restore the `ws` default `maxPayload`: the pre-change mux passed no limit, so
the 1 MiB ceiling was an unrelated breaking change. Remove the exported
constant and the oversize-frame test, and drop the matching docs.
Pin the per-frame compression threshold and the accepted compressed-write
liveness consequence with regression tests, correct the queued-write
documentation, move the Agent Note to `implemented/`, and sync the Remote
duplex stream note with `websocketCompression`.
Refs #6476
Replace the pr-declare skill with dsh-pr-description, a repository-only
skill (user-invocable: false) that owns how deepseek-harness PR
descriptions are written and updated: section rules, Issue references,
test design, change-specific disclosures, and the Human and Agent Roles
section with its levels, stages, grading rules, and update timing. The
skill no longer fetches an external specification, asks the user for a
level, or adds badges.
Reduce the pull request template to a skeleton that points to the skill,
point root AGENTS.md at the skill, and make the template test check that
the template's role level line and stage placeholders match the skill.
Closes#6034
Add a `websocketCompression` Gateway config field (`'deflate'` by default,
`'none'` to disable) and negotiate `permessage-deflate` on `/api/remote.mux`.
Frames whose JSON text reaches 1024 characters are compressed in the mux send
path, because `ws` ignores its `threshold` option under the default context
takeover. `maxPayload` is bounded by `max(streamInboxBytes, 1 MiB)` so one
compressed frame cannot inflate past the fixed ceiling.
Fixes#6476
After a stop, steering still pending is claimed with the next prompt and the
AgentLoop logs it first. Once the first of those rows is durable, the
remaining echoes follow the new Turn's process control, which renders empty
while the Turn runs. The 16px clearance after that control applied to them
and moved each echo by 10px before its durable row replaced it. The clearance
now applies after a visible control to every row, and after any control only
to rows that are not local echoes, so the echoes keep the input gap.
Also state that a switch lifted within a move's duration plays the rest of
it, that the steering entrance approximates the status's previous position,
and that the runtime-context notice placement follows from the README rule.
* fix(agent-instructions): budget the user-global and project chains separately
The user-global and project instruction files shared one maxBytes and the user-global files were the broadest, so a large project chain omitted them first. Each chain now renders under maxBytes on its own and the results share one system-reminder frame: unchanged output when everything fits or one chain is empty, at most twice maxBytes otherwise. The project chain keeps its omit-broadest-first, truncate-last rule; reconciliation batches follow the same split; the maxBytes key and the baseline identity are unchanged.
Tests cover the fast paths, both chains fitting only separately, each chain over its own budget, the 2 × maxBytes boundary at exact and tiny limits, multibyte content, reconciliation batches, and a resumed single-budget baseline receiving the user-global file as one transition. The agent-instructions-budget snapshot is refreshed and agent-instructions-budget-chains is added. README, Config.maxBytes JSDoc, the configuration catalog, a new Agent Note, and an upgrade guide state the per-chain bound.
* fix(agent-instructions): keep loaded order in merged frames and note the unshared chain budget
A merged frame now lists sections, omissions and truncations in the loaded order, so a reconciliation batch renders its items in one order whether or not it fits a single budget. The guard comment states only the invariant and points to the Agent Note; the intro selection states its rule. The README names the unshared budget between chains.
---------
Co-authored-by: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com>
The running status now renders after the transcript rows and before the
steering echoes that are still waiting, so the mid-steer accessibility
snapshots list the status ahead of the interjection echo. Refreshed with
DSH_SNAPSHOT=refresh on the steering scenarios; no other golden changed.
A pinned tail zeroed both running status moves. Following scrolls absorb
output growth, so the status keeps its on-screen position for the first
output, but admitted steering still moves the status past its pending
echo below it: in a long transcript at the floor the status jumped the
height of that echo with no motion. The input-fold switch keeps zeroing
both moves; the pinned switch now repeats only the first-output slide's
structure, so the entrance after an admitted steering row keeps its
duration while the page scrolls by the added slot. Update the README and
the CSS check that the pin applies to the slide structure alone.