Delete @deepseek-ai/dsh-invariants, every package's ./invariant companion
and its tests, the invariant gates and Vitest setup, the scoped-event
resolver generator, and the INVARIANT-coded listener rethrow paths.
Update docs, READMEs, Agent Notes, and add an upgrade guide.
Move the auto-growing textarea into ui-primitives as InlineEditor and use it
for both the queued-message and goal editors. It also refits when its width
changes and treats keyCode 229 as IME composition.
Tighten goal-round-driver docs and regression assertions for the withdrawn
queued round: continuation disarms when the cancelled turn belonged to other
work, and the removal is a durable canceled next-turn splice.
Render one Button for both layouts so crossing the fit threshold keeps focus,
anchor the tooltip on the wrapper so a disabled compact entry still names
itself, observe each tab, and rename the tab in the user and subsystem docs.
Rebind the scrollbar thumb to the l2 pair on the elevated goal strip, treat
keyCode 229 as IME composition, and re-measure the editor when the inline
error changes its width.
The classification was recorded before the subtree scan, so a run that found and
removed package ACEs under the requested directory still reported NOT_THIS_CLASS
or PRECONDITION with an empty packageObjects, contradicting README and SKILL. The
scan now runs first, so the verdict and packageObjects describe what the run
actually repairs.
A report-file write failure now prints REPORT_IO_FAILED with the path and the
error on stderr instead of silently leaving an incomplete report behind.
Shrink the linked Session entry to a chat icon button with a Linked session
tooltip when the detail strip cannot fit it, hide the tab list scrollbar,
and rename the English Delivery records tab to Records.
A goal round queued behind human work stayed in the inbox after Stop. The
next human prompt claimed that stale round first, pre-step rejected it, and
the driver exited with the human prompt still parked until another send.
The goal edit field was a single-line input: Enter always saved, a newline
could not be entered, and a long objective scrolled sideways on one line.
Use an auto-growing textarea capped at six lines, matching the queued-message
editor: Enter saves, Shift+Enter breaks the line, IME confirmation does not
save, Escape cancels.
Clarify acknowledgement and first-failure semantics, update configuration and timeout terminology, and explain request-side fixture checks without changing execution logic or recorded expectations.
The desktop archive probe called the script with only -Path, which the new
interface refuses, so it now passes -AllowRoot and -Out. The skill no longer
suggests running the repair confined: the confined token cannot write a DACL, so
that run would report the sandbox's own restriction as a missing right.
The subtree walk bounds its first enumeration too, and a directory whose stat
fails counts as unreadable instead of vanishing. The removal decision says
inherited copies follow their repaired source, and the pre-flight comment names
grant targets as well. Add the third behavior test the rewrite dropped: an
inherit-only FullControl ACE survives a grant.
The approval rule and the stop template are the text a user reads, so they now
name Windows file permissions and permission entries; ACL and ACE stay in the
model-facing technical sections and the report.
The stop paragraph now says only the user can lift confinement, names the term
the Chinese UI shows (完全权限), and offers both options that switch opens: keep
working under full access, or have the agent keep investigating the ACL problem
from the report's mechanism and evidence. A bilingual template carries the same
message, and the surrounding skill text is tightened to stay inside its budget.
The stop path told the agent to switch the session to full access, which only the
user can do. Ask them to switch it instead, keep the agent out of that decision,
and record the same wording in the windows-acl-skill snapshot.
Tool output keeps only its tail, so a long repair run lost its early observations
and nothing durable held the full record set. Every run now writes each REPORT
record to \`-Out\acl-report-*.jsonl\` and ends with a \`RECAP\` line carrying the
verdicts, changes, verifications, refusals and scans, followed by the report path
and the counts. Verification re-reads stop repeating an ACE list the run already
printed, and the localised icacls rendering leaves the record.
The skill now tells the agent what to do when a repair stops: name the blocking
object and right, unblock the user by switching the session to full access
temporarily (stating that confinement is off and that this is a workaround), and
ask for feedback with this session so the unhandled scenario reaches the team,
quoting the report records because only what reaches the conversation travels.
Also from review: the subtree walk reports directories it could not read instead
of claiming a complete walk, a grant target without effective WRITE_DAC is refused
before any change rather than failing mid-repair, grant targets require complete
observations, and repair sources are ordered ancestor first for scanned paths too.
The recorded session embeds the skill description and the loaded instructions,
so the review-driven edits to SKILL.md need the same two-line fixture update.
Review found the unified run had dropped the grant pre-check: a target without
effective WRITE_DAC was attempted anyway, failed, marked a recovery attempted, and
the rollback could not restore it either, ending in restore_pending_then_stop with
a command that cannot run. Refuse that target before any change, and gate grants on
complete observations the way package removals already are.
Repair sources are now ordered ancestor first for chain and scan-discovered paths
alike; the old reverse made a deeper scanned source come first. The subtree walk
reports directories it could not read instead of claiming a complete walk, and the
docs record the authorized-root trigger plus one recovery pair per change.
Restore the two behavior tests the rewrite dropped: a deny sharing the removed
allow's SID, and an inherited source outside -AllowRoot with an in-root explicit
child.
The recorded session embeds the skill's catalog description and the loaded
instructions, so the keyless replay diffed the previous two-step text against
the shipped one. Replace both with the shipped text; nothing else changes.
The note still described a diagnosis-then-repair workflow with a mode choice.
Record what shipped: one invocation for both repairs, the bounded subtree walk
under a directory the caller cannot provision, the authorized root repairing and
restoring itself, and the per-object recovery record plus script.