Repository navigation
feat: stop recording capability-file history and skip approval bookkeeping in auto - #357
Merged
Merged
Conversation
…eping in auto Every refreeze synced change records into the hash-chained ledger and copied each tool and skill file into its objects store, and every capture hashed and copied those files only to feed it, yet nothing enforced against that history. In auto, where newly trusted projects now start, each turn also re-read and hashed the whole approval log at turn start and once per external tool after every mutating call, and kept unapproved read-only external tools out of concurrent batches although auto runs them unattended either way. The ledger now records approvals only. Captures keep paths, refreezes write nothing, and approvals no longer copy bytes (a bound file changed since the card is still refused, by its current hash). The refreeze receipt names each tool or skill file added, modified, or removed from the two registries, with no actor attribution, held-generation bookkeeping, or clauses about approvals of removed files. Under auto a turn never reads the ledger: approval events, the per-call approval diff, and the batch content check are skipped. Approval records, their chain verification, and content approval in ask are unchanged. `--ledger` stays accepted, prints one line saying history is no longer recorded and where existing records and objects are kept, and exits 0. The log format is unchanged, so older binaries keep working, and stored objects are never deleted. The frozen prompt drops its `--ledger` pointer, and its budget cap ratchets from 3,500 to 3,450 bytes.
The refreeze receipt compared skills by their index line (name and description), but the fingerprint hashes every SKILL.md byte. A body-only edit therefore refroze without naming any file, and the receipt fell back to "extension files changed", so a skill rewritten by a pull arrived unannounced. A manifest added past the tool cap was not named either. The capture now keeps a cheap in-memory hash of each file's bytes beside its path, and the receipt compares two captured generations file by file from it. A registry restored from a session manifest read nothing, so that comparison alone falls back to loaded tools and indexed skills. The fingerprint itself is unchanged, so persisted sessions resume without a refreeze. Also drop the unused Actor::as_str, port the one-line-per-entry test to the new receipt, and correct docs and comments that still described ledger-recorded changes with actors.
…o first A reply's tool calls are grouped into concurrent batches once, under the mode of that moment, and auto now lets unapproved read-only external tools into a batch. If the user switched from auto to ask while an earlier call in the same reply was still running, the group still ran as a batch under ask, where the content gate declined every call without raising an approval card. Each segment now runs as a batch only when the live mode still matches the mode it was formed under; otherwise its calls take the serial path, which asks. Two test texts that described the removed receipt clauses are corrected.
…s auto A concurrent batch admits every call up front, then starts them behind the parallelism cap, so a call can wait in the queue long after auto admitted it. Auto never asks whether a tool's content is approved, so if the user switched to ask while an unapproved external tool waited, it still started, under ask, with no approval card. Each call now re-reads the mode as it starts. A call that auto admitted without the content question, whose tool is unapproved, is refused once the mode has left auto, with a reason that asks the model to request it again; requested again, it takes the serial path, which raises the card.
A resumed session's registry is rebuilt from its manifest, which kept no record of the bytes its freeze read. The refreeze receipt could then only compare index lines, so a SKILL.md body edited while the session was closed went live under a generic "extension files changed" and the file was never named. The manifest now carries the per-file hashes the freeze read, and a resumed registry compares file by file like a live one. The field is additive: a manifest written before it still loads and compares index lines.
…lity-history The extension pointer keeps main's mcp surface and still drops the ledger history pointer; the frozen payload is 3,361 bytes under the 3,450 cap.
Comments Outside DiffThese findings could not be posted inline.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Every refreeze wrote change records for each tool and skill file into the hash-chained ledger and copied the bytes into its objects store. Every capture hashed and copied those files only to feed that history, and nothing enforced anything against it. In
auto, which newly trusted projects now start in, each turn also re-read and hashed the whole approval log at turn start and again for each external tool after every mutating call. Unapproved read-only external tools were also kept out of concurrent batches, even thoughautoruns them unattended either way. Users paid disk, latency, and lost parallelism for history no one used and approval checksautonever acts on.Summary
objects/. An approval is still refused when a bound file changed since its card was shown, now checked against the file's current hash. Stored objects and older change records are kept, never deleted, and the log format is unchanged, so older logs still verify and older binaries keep working.<path> added,modified, orremoved, computed by comparing the outgoing and incoming registries. A skill body edit is named asmodified, a manifest added past the tool cap is named asadded, and a file that is broken or past the cap is never called removed. The receipt no longer attributes an actor or includes clauses about approvals of removed files. Each entry stays on one line even when a path contains a newline.auto, a turn never reads the ledger. Approval narration, the approval check after each mutating call, and the batch content check are all skipped, and unapproved read-only external tools batch like any other read-only call. A session started inautothat later leaves it does not announce approvals made earlier as new.autoruns serially if the user switches toaskbefore it starts, so the approval card is raised instead of every call being declined silently. A call still queued behind the parallelism cap when the mode leavesautodoes not start if its tool is unapproved: it is refused with a reason to request it again, and the retry takes the serial path and raises the card.askare unchanged.openmax --ledgeris deprecated. It prints one line saying history is no longer recorded and naming the project's ledger directory, then exits 0.--ledgerpointer, and the frozen prompt budget cap ratchets from 3,500 to 3,450 bytes (payload is now 3,361, including themcpsurface name).docs/extending.md,docs/configuration.md,docs/stdio-protocol.md, therefrozenevent doc, and the stdio--spectext to match.Test Plan
an_auto_turn_batches_unapproved_tools_and_never_reads_the_ledger: a fullautoturn reads the ledger zero times and batches unapproved read-only tools (fails on the old code with 14 ledger reads and serial ordering).a_session_built_in_auto_starts_approval_narration_from_what_is_on_record: leavingautodoes not announce existing approvals as new.a_skill_body_edit_is_named_as_a_modified_fileand the past-cap step ina_tool_pushed_past_the_cap_is_not_a_removed_tool: the receipt names body edits and manifests added past the cap (both fail on the old code).a_batch_formed_in_auto_asks_when_the_mode_turns_to_ask_before_it_runs: switching toaskwhile an earlier call in the reply runs raises an approval card, and every call ends ok (fails on the old code).a_queued_batch_call_does_not_start_once_the_mode_leaves_auto: with one parallel slot, switching toaskwhile the first call of an unapproved tool runs keeps the queued second call from starting (fails on the old code with 2 runs and the queued call ending ok).a_skill_body_edited_while_the_session_was_closed_is_named_on_resume: a registry restored from its manifest names a SKILL.md body edit, and a manifest without the hashes still loads (fails on the old code with no change named).a_changed_path_cannot_forge_a_line_in_the_receipt: each receipt entry is one line starting with the project-relative path.an_unapproved_external_tool_batches_only_in_auto: batching depends on the mode, with zero ledger reads inauto.ledger_is_deprecated_and_leaves_existing_records_in_place:--ledgerprints one line, exits 0, and leaves records in place (fails on the old code with 5 lines).cargo test --workspace --lockedexits 0.cargo +1.97.0 clippy --workspace --all-targets --locked -- -D warningsexits 0.The confirmed MCP shutdown issue can leave a subprocess running, but does not block merging.
What we checked:
Summary
The PR adds a one-shot MCP client alongside changes to approval handling, extension refreeze, session I/O, file tools, and release checks. When an MCP server is started through a launcher, a successful list or call can leave the server running after the CLI exits. The earlier approval-bypass and resumed-skill receipt issues are fixed. The remaining shutdown issue is non-blocking.
Reviews (3) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..."