Status snapshots carry the base commit the host recorded with the head
(baseSha). ForgeService.diff passes it to the provider when the latest
status names the requested head, and forge-github starts the compare read
from it while its GraphQL read confirms the head; a stale head or another
base cancels and joins the early read.
- Shift-chosen commits must follow each other as first parents; the picker
says why it keeps a run that leaves the line, and the Host refuses one with
forgePanel/commits-not-linear for the Branch scope and change requests.
- The Branch scope lists its newest maxCommits commits with
--no-show-signature, so log.showSignature cannot corrupt the listing.
- Viewed marks merge with the stored entry on each write and follow the
storage event, so tabs of one Session keep each other's marks.
- .gitattributes patterns follow Git's wildmatch rules, checked against
git check-attr; change digests include file mode lines.
- GitHub commit pagination refuses a repeated cursor or a changed count;
commits validates the repository before its host like the other reads.
- The commit list is read once per head, base, or refresh; the lens menu
hides the count of the disabled Tests lens.
A repository's root .gitattributes now decides a file's review layer first:
dsh-review-layer names test, interface, or implementation, and
linguist-generated still places a file in the test layer. The testPaths and
interfacePaths settings add globs before the built-in rules and are empty by
default. The built-in rules follow the default conventions of common
languages and tools instead of treating every JSON or YAML file and every
name containing config as interface. This repository declares its own locale
dictionaries, snapshot tree, pairing records, and types modules.
- forge-github: repeat a compare read without --allow-escape-sequences when
a gh older than 2.97 rejects the option; such a gh prints escape sequences
unchanged, so every version reads every diff (checked with gh 2.96.0 and
2.100.0 on a pull request whose patch holds an ESC byte).
- client-ui-forge: a stale refusal now re-runs the read effect, so a status
that arrived during the read, including a failed poll that keeps the
earlier head, starts the next read at once instead of leaving the changes
view loading.
- forge: ctx.forge.diff polls at once only for the first stale read at a head
commit; later stale reads at it wait for the regular poll, which bounds the
read-poll loop while GitHub's answers briefly disagree.
- forge-github: review thread pages share the byte budget of a complete
check read.
- client-ui-forge: a truncated count shows its "+" even when it is zero.
- READMEs: document the batch deadline and rewritten-base limitations.
The changes view gains a lens of All, Interface, Implementation, and Tests
that spans the file tree above it, a switch that hides test files from the
tree and the diff, and a viewed checkbox on each file header that collapses
the file. The toolbar counts viewed files and V toggles the file being read.
Marks are kept per Session, source, path, and change digest in browser
storage, so a file that changes again reads as changed since viewed. All
commits beside Submit review, and beside the base branch of the Branch scope,
shows one commit or a Shift run of commits.
ForgeProvider.diff now takes the head commit it must describe. The GitHub
provider reads headRefOid before and after `gh pr diff` and returns the new
ForgeFailure code `stale` when either read names another commit, so the
forge panel never caches a patch under a head it does not describe. A stale
read polls the change request at once, and the changes view waits for the
next status before reading again.
Status polling pages reviewThreads up to the new `maxReviewThreads` setting
(default 1,000) instead of counting only the first 100, and sets
ChangeRequestSnapshot.threadsTruncated when the count is a lower bound.
Type the approval denial helper with a closed ApprovalErrorCode, state
that a cancellation is recognized by the signal reason or an Error named
AbortError, note that ApprovalError names a denial rather than a thrown
class, and separate JOB_CONTROLLER_UNAVAILABLE from a missing jobs
service. The jobs README describes JobError as the seam's export rather
than as current caller behavior, and the terminal test asserts one
concurrent send failure.
Refs #7869
Tool bodies that lack a calling Agent, an injected service, or an open
turn get one shared HarnessError with the TOOL_CONTEXT_UNAVAILABLE
code, instead of each tool throwing a plain Error. The stacked
per-area refactors adopt it at their call sites.
Refs #7869
A ToolGuard may return a ToolGuardDenial with optional ToolErrorInfo,
and a post-execute block may supply info; the registry records it on
the failed result. checkGuards now returns the normalized denial.
String guards and blocks without info keep their existing results.
Refs #7869
An ask that approval does not grant now denies with ApprovalError and
APPROVAL_REJECTED, APPROVAL_CANCELLED, or APPROVAL_UNAVAILABLE, so a
user rejection is routable on tool/result like other structured
failures. Model-facing reasons are unchanged.
Refs #7869
A started tool body that throws the signal's reason or an AbortError
without HarnessError identity now keeps its message and carries
AbortError / ABORTED, so the cancellation is routable like the
registry's own cancellation results. HarnessErrors and distinct
failures that settle during cancellation stay unchanged.
Refs #7869
MarkdownDelegate gains renderCode for fences whose language is final; ChatView
declares conversation.chat.markdown.fence and registers math and diff/patch
layers. Hoc slots accept an optional dispatch key, render children at most
once, share compiled chains per key, and contain layer crashes to the failing
occurrence.
Refs #7926
The worktree service now records each checkout it creates as a
`plugin:worktree/created` record, folds them in its own `worktree`
projection with fork-aware ownership, and reclaims a clean, unreferenced
checkout when the Session that created it is archived. The Forge panel
reads the service's record and forwards its cleanup state; it no longer
writes a `created` record, owns a retention projection, or gates every
Session's directory access.
Admission registers the attempt inside the Workspace write queue and
returns; inspection runs afterwards, reading cold Sessions through the
projection cache when mounted and from their log otherwise, with subagent
children of an archived ancestor counted as archived. Only a path being
removed holds `working-directory/access`, whose request now carries the
access's `signal`, and listeners withdraw before the drain. Ignored files
no longer retain a checkout, matching Git's non-force removal; processes
and terminals are not consulted.
The Forge bundle mounts one `worktree` service: the `forge-worktree` row
and the `optional-forge-panel` group that isolated a second service are
gone, and `forge-panel` is a top-level row. `canRemove`, `remove`, the
`forgeWorktreeRetention` projection, and `ForgeWorktreeCleanup` are
removed; `WorktreeService.cleanupOf`, `WorktreeCleanup`, and the
`worktree/cleanup` Host event replace them. The upgrade guide moves to
the current version directory and covers the id removals.
Discover offers Update for a plugin installed from a pinned Git commit
when the plugin index lists a newer commit of the same repository
directory. The Plugins page update removes the installed copy, installs
the target with an expected-package check that undoes a wrong install
with its modules, and reinstalls the removed commit when the target
fails. A network failure reaching the target's host stops the update
before anything is removed.
List registry cancellation results and tools/execute wrapper results
as structured error sources, name cancellation errors AbortError with
the ABORTED code, state that approval rejections and guard denials carry
no code yet, and allow per-failure classes with their own fields.
Refs #7869