Repository navigation
Report every injected strategy with graded evidence - #41
Merged
Merged
Conversation
Each strategy injected into a turn is now reported through the Proxy's
/asset/reuse-result as {asset_id, outcome, task_id, reason, evidence}.
The evidence says whether the strategy's steps show up in the turn's
bash commands, touched paths, the code its edits wrote and the final
answer, and carries the last test, build, lint or type check the turn
ran, whether that same check failed earlier (output pipes and redirects
stripped before comparing), and whether the turn was aborted. A turn
that left nothing to compare is sent as tier none with applied partial,
so the Hub adds no soft negative.
The next prompt that corrects or approves a turn sends one L3 follow-up
under <task_id>:correction, and the next session in the same project
sends one L2 follow-up under <task_id>:retention when the edited files
are kept or reverted. The model's own evolver_asset_reuse_result carries
L5 evidence and no longer suppresses the automatic report.
Reports wait in ~/.evolver/state/reports-outbox.json for 8 days and are
retried at every turn end, follow-up and session start. duplicate_report
and ineligible receipts count as delivered; terminal answers (or hub
400/422 from an older Proxy) are settled as rejected and never resent;
hub 404 and everything else is retried. evolver_status lists the Hub's
eligible/counted/weight verdicts and every rejection. Prompts lose keys
and tokens before recall sends them.
The turn-end capture is removed: it posted to /a2a/evolution/record, a
route the Hub does not serve, and appended memory-graph entries nothing
in the plugin reads. Its git snapshots, workspace ids, capture lock and
their settings go with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Once per dsh process, in the background, the plugin now prepares the engine it depends on: an evolver that is missing or older than 2.0.39 is replaced with `npm install -g @evomap/evolver@latest` and its Proxy is started (or restarted after an upgrade) with `evolver lifecycle`; a current evolver whose Proxy does not answer is started. The outcome, or the manual steps when npm or the start failed, reaches the agent as one [Evolver] notice. This replaces the daily upgrade notice, and the first step no longer waits on the version probe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
Starting the engine setup from agent/pre-step too meant every test that primed a step left a background setup running. On CI, with no Proxy settings in HOME, those setups called `evolver lifecycle start` through whichever fake evolver a later test had put on PATH, and sent a bodyless GET /proxy/status to servers that parse every request body. dsh fires agent/session-start before a session's first turn, so it alone starts the setup; the notice still rides the next step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
forrestlinfeng
added a commit
that referenced
this pull request
Oct 14, 2026
Every injected strategy is now reported with graded evidence, with correction and retention follow-ups and a durable outbox; the turn-end capture and its settings are gone. The plugin installs, upgrades and starts Evolver when it is missing, older than 2.0.39, or not running (#41). Co-authored-by: forrestlinfeng <linfengchen@tencent.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
Each strategy injected into a dsh turn is now reported to the Hub with graded evidence, along with correction and retention follow-ups and a durable outbox. The old turn-end capture is removed.
POST /asset/reuse-result. The body is exactly{asset_id, outcome, task_id, reason, evidence}, withevidence = {tier, applied, check?{kind, passed, fail_then_pass}, aborted, stage}(the Hub's strict schema).tier: nonewithapplied: partial, so the Hub adds no soft negative. The reason saysapplied: unknown.bashin the turn.isErroror from failure output, because dsh's bash reports a failing run piped throughtailas success.fail_then_passcompares commands with output pipes (| tail,| head,| grep, …) and redirects removed.<task_id>:correction.<task_id>:retentionwhen the edited files are kept or reverted.~/.evolver/state/reports-outbox.json, 8-day TTL, three states:duplicate_report, or an ineligible receipt (same_owner,daily_cap).terminal: true, orhub 400/hub 422from an older Proxy. Never resent, never written to the local ledger.hub 404and everything else.evolver_statusgainsreuse_reports.delivered, carrying the Hub'seligible/counted/weight(plusreasonwhen ineligible), andreuse_reports.rejectedwithreason/status.receipt.evolver_asset_reuse_resultreturns the Proxy body unchanged, so the verdict fields reach the model.evolver_asset_reuse_resultnow carries L5 evidence (applied: unusedformismatched). It no longer stops the automatic report; the Hub keeps whichever report weighs more.Engine setup (second commit)
Once per dsh process, in the background (triggered by the first
agent/session-start), the plugin prepares the engine:evolvermissing or older than 2.0.39 →npm install -g @evomap/evolver@latest, thenevolver lifecycle start(fresh install) orevolver lifecycle restart(upgrade).evolvercurrent butGET /proxy/statuscannot connect →evolver lifecycle start. A Proxy that answers (even with 401) is left alone.[Evolver]notice on the next step. On failure (e.g. EACCES on the global install, or an olderevolverstill first on PATH) the notice gives the manual steps.evolver --versionprobe.evolver_statusprobes the version fresh on each call.There is no opt-out setting. Tests put fake
evolver/npmscripts on PATH, so CI never installs anything.Behaviour → dsh implementation / gap
session/event→turn/end(completed→ success;aborted/blocked/error/max-tokens→ failed; synthesizedinterruptedsends nothing and leaves the injection for the next turn). Task iddsh:<session>:<turn>uses dsh's own turn number from the session log.~/.evolver/state/injected-<hash>.jsonwith the strategy text. A late recall is reported by the turn that saw it.tools/executewrapper: arguments of every call (command,path/file_path), and the written text ofwrite/edit/str_replace_editor. The file hash before the first edit is taken beforenext().tools/executeonbash, resultisError+ text content.tools/executeonly wraps calls that were allowed to run, so a denied check is not counted as failed.session/event→assistant/message, last non-empty text of the turn.agent/pre-step: the first step's messages withsource.kind === 'user'.source.kind, so anyusermessage counts as the person's. The "label the next prompt" state is in memory, so a dsh restart between a turn and its next prompt drops that one correction.agent/session-start(anysource). Project = realpath ofsession.header.cwd, falling back toprojectDir/DSH_PROJECT_DIR/ cwd. Pending checks are kept in~/.evolver/state/retention-pending.json.header.origin === 'subagent'send no reports.~/.evolver/state(dsh gives plugins no store); rejections inevolver_status.@evomap/evolver-coreroot events, once per report with evidence (never for tiernoneor a rejected report).Removed (delete-first)
src/capture.js,src/capture-coordinator.js,src/git.js, and the workspace-id and memory-graph half ofsrc/workspace.js./a2a/evolution/record(the old record route; there was no/memory/recordcall in this repo), which the Hub does not serve.gitTimeoutMs,gitMaxBufferBytes,hubTimeoutMs,captureDedupeTtlMs,captureLockStaleMs,captureLockWaitMs,untrackedHashMaxBytes. An old config that still sets them parses and ignores them.session/flushlistener existed only for the capture queue.Kept, still in use:
projectDirand the project-dir resolution (nowsrc/project-dir.js), used as the project key for retention.[Evolution Signal]nudge, minus the "attached to the turn outcome" claim).dissatisfaction.js, used by the follow-up label.local-ledger.js(root events)./evolver-statusand/evolver-evolvestill read the full engine's memory graph, which that engine writes.Minimum Evolver
MIN_EVOLVER_VERSIONunchanged).terminaland the verdict fields need the first Evolver release containing EvoMap/evolver-v2-private-dev#1311 (merged to main, not released yet; expected 2.0.43).evidence, so the Hub counts the report as unevidenced (0.1);hub 400/hub 422, which is treated as rejected;eligible/counted/weightfields are returned.Tests
npm test: 154 pass.applied,checks,verification,reuse(contract field set, delivery verdicts for duplicate / ineligible / terminal / hub 400 / 422 / 404 / 5xx / 429 / 401 / network),report-outbox,retention,feedback-label,injected-assets,turn-outcomes, the report log in diagnostics, and prompt redaction.test/reporting.test.jsdrives the plugin through fake dsh hooks against a local Proxy.test/fixtures/fair-play-session.jsoncomes from a recorded dsh session (home path renamed, non-check output shortened). Replaying it gives:L1 / used / test passed / fail_then_pass false(the last check isnpm test … | tail -8, while the earlier failures werenode --test … | tail);tier none / applied partial / reason applied: unknown;fail_then_passacross differenttaillengths;evolver_statusand never resent;Not verified: a live dsh run with a model; behaviour was checked against real dsh session logs and the hook type definitions.
🤖 Generated with Claude Code