[Bugfix] Auto-refresh quest_root SUMMARY.md on every artifact.record#82
Open
droidlyx wants to merge 1 commit intoResearAI:mainfrom
Open
[Bugfix] Auto-refresh quest_root SUMMARY.md on every artifact.record#82droidlyx wants to merge 1 commit intoResearAI:mainfrom
droidlyx wants to merge 1 commit intoResearAI:mainfrom
Conversation
`SUMMARY.md` at the quest root is the canonical compact snapshot for external observers (operators inspecting quest progress without parsing events.jsonl, cross-quest agents browsing prior quests). To be useful it has to be current. The intended path was `refresh_summary` called from stage skill prose at meaningful checkpoints. In practice agents almost never call it: across 4 observed quests on the same studio, the count was 0 / 1 / 1 / 0 over 9-24h of active work. Agents have richer state in events.jsonl, `get_quest_state`, and memory cards, so the SUMMARY write is never on their critical path. Stop relying on agents to maintain a side-file. After this change, every successful `record(...)` writes a fresh SUMMARY.md to `quest_root` as a side effect (recursion-guarded against the `summary_refresh` report itself). The auto-refresh: - only writes `quest_root/SUMMARY.md` (NOT the worktree's), so it cannot leave a worktree dirty and block subsequent `git switch` / `git worktree` operations during normal artifact flows; - does not record a `summary_refresh` audit artifact (would pollute events.jsonl with one auto-refresh report per record). Explicit `refresh_summary()` calls still record the audit artifact (default `record_artifact=True`) and still write both worktree + quest_root SUMMARY.md, preserving the existing contract. Wraps in try/except so a refresh failure cannot abort the record.
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.
[Bugfix] Auto-refresh quest_root SUMMARY.md on every artifact.record
What changed
A single change in
src/deepscientist/artifact/service.py:refresh_summarygains arecord_artifact: bool = TrueparameterFalse, the SUMMARY.md files are written but nosummary_refreshaudit artifact is recorded. DefaultTruepreserves existing behavior for explicit callers.record(...)callsrefresh_summary(record_artifact=False)automatically after every successful record (with a recursion guard for thesummary_refreshreport itself)quest_root/SUMMARY.mdnow stays current as a side effect of normal artifact writes. Agents no longer need to remember to callrefresh_summaryfor the snapshot to reflect reality.Why
SUMMARY.mdat the quest root is the canonical compact quest snapshot — the file an external observer (operator inspecting progress without parsing thousands ofevents.jsonlentries) or a cross-quest agent (bash_exec ls -t ~/DeepScientist/quests/*/SUMMARY.mdunder shared memory mode) reads to see what a quest is doing. To be useful it has to be current.The intended update path was an
idea/experiment/analysis-campaign/write/review/decision/finalizeskill callingartifact.refresh_summary(...)at meaningful checkpoints. There are 5 such prose nudges insrc/prompts/system.md.In practice, agents almost never call it. Across four observed quests on the same studio:
refresh_summarymirror PR)Agents have richer state in
events.jsonl,mcp__artifact__get_quest_state(detail=summary), memory cards, and their own context window, so the SUMMARY.md write is never on their critical path. The artifact reaches its intended audience (external observers and cross-quest browsers) only when an agent happens to remember.The structural fix is to stop relying on agents to maintain a side-file and let the daemon do it as a side effect of artifact writes.
After this change:
artifact.record(...)updatesquest_root/SUMMARY.mdautomatically. No agent action.events.jsonlis not polluted withsummary_refreshreports for each auto-refresh — only the file is touched.quest_root/SUMMARY.md, not to the active worktree'sSUMMARY.md. This preserves the worktree's clean working-tree state (a worktree-side write without commit would block subsequentgit switch/git worktreeoperations during normal artifact flows).artifact.refresh_summary()calls still record the audit artifact and still write both worktree + quest_root SUMMARY.md (defaultrecord_artifact=True), preserving the existing surface for callers who want the audit trail and the branch-versioned summary.Recursion guard
refresh_summary(record_artifact=True)callsrecord(...)to log asummary_refreshreport. The auto-hook inrecord(...)would then callrefresh_summaryagain — infinite loop.Guarded explicitly:
The
record_artifact=Falsepath also avoids the recursion entirely — the auto-hook never records, so even without the kind guard, depth is bounded at one. The kind guard makes the bound explicit and survives future refactors.Performance
refresh_summaryreads up to 20 recent artifact JSONs and writes one markdown file. ~10ms per call locally; for a typical 70-100-record quest that's <1 second of cumulative overhead. The auto-hook is wrapped intry / exceptso a refresh failure cannot abort an artifact record.Tests
Two new tests in
tests/test_memory_and_artifact.py:test_record_auto_refreshes_quest_root_summary_without_extra_artifact— records areportartifact, assertsquest_root/SUMMARY.mdis updated to mention the record (auto after report <id>), and asserts nosummary_refreshaudit artifact was emitted as a side effect.test_record_skips_auto_refresh_when_record_is_summary_refresh— callsrefresh_summary()explicitly (defaultrecord_artifact=True), asserts exactly onesummary_refreshaudit artifact exists (no recursion-driven duplication).Existing
refresh_summarytests still pass:test_refresh_summary_mirrors_to_quest_root_when_active_workspace_is_worktreetest_refresh_summary_writes_once_when_workspace_equals_quest_roottest_activate_branch_preserves_head_and_redirects_main_run(regression caught and fixed during development: an earlier draft wrote SUMMARY.md inside the worktree without committing, leaving the working tree dirty and blockinggit switchduringactivate_branch. The merged design only writes toquest_rootin auto-refresh mode.)Local sweep:
Outcome on this branch: same pre-existing failures as
origin/mainat the same commit, no new failures introduced (4 pre-existing failures unrelated to this PR remain on main).Documentation
No docs change.
refresh_summary's contract (it refreshes the quest's compact state) is unchanged; this PR only changes when it fires and whether it records an audit trail.The 5
artifact.refresh_summary(...)prose nudges insrc/prompts/system.md(experiment / analysis-campaign / write / review / finalize) become redundant after this PR — they were the prose half of the same goal, now subsumed by the server-side auto-hook. Removing those prose lines is a small follow-up cleanup and out of scope here.Compatibility / migration
refresh_summary's signature gains a keyword-onlyrecord_artifactparameter, defaulting toTrue. All existing callers (the MCP tool, tests, manual invocations) preserve their previous behavior without changes.record(...)'s return shape and side effects are unchanged. The added side effect is a single file write per record (idempotent — the same content is reproducible from the recorded artifacts).read_visibility_modecross-quest gating recently merged: SUMMARY.md maintenance happens regardless of whether agents are allowed to read sibling quests' SUMMARY.md across quest boundaries. The two changes are orthogonal.AI assistance disclosure
Prepared with AI assistance. Each change was authored, reviewed line by line, and verified end-to-end via
pytest tests/test_memory_and_artifact.py tests/test_mcp_servers.pybefore submission. No commit is unreviewed AI output.