chore: retarget check-sync's sentinel gate to the worker's real system prompt #488
No reviewers
Labels
No labels
Agent
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
1 participant
Notifications
Total time spent: 11 minutes 45 seconds
Due date
igor
11 minutes 45 seconds
No due date set.
Dependencies
No dependencies set
Reference
joshtronic/igor!488
Loading…
Reference in a new issue
No description provided.
Delete branch "agent/487-chore-retarget-check-sync-to-the-sourced-worker"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this PR does
worker-contract(viacontext_surface) when the Distillery cache is seeded, falling back to in-repoAGENTS.md-- and says so loudly -- only when the cache is unseeded and unreachable (the CI-container case)lib/context-source.sh's stale atomicity comment: old cache generations do NOT survive the swap (thefind -exec rm -rfafter it deletes them); a mid-cat reader is safe only because unlink doesn't invalidate an already-open file descriptorbin/install.sh's.envsourcing into the seeding block that actually needsFORGEJO_HOST, instead of loading it earlier for no reasonbin/test-feedback.shalready setAGENT_STATE_DIRto its tmp dir as its comment claims -- no change needed thereThis is the rescoped issue #487: the original ticket bundled deleting the
now-unconsumed in-repo prompt copies (
AGENTS.md's body,bin/lib/*.md)alongside the check-sync retarget, which tripped the 1000-line runaway
guard. Those deletions are split out to #488 (a human decision) and are
NOT part of this diff --
AGENTS.mdand everybin/lib/*.mdfile areuntouched here.
Test plan
make testpasses (check-sync validates against the sourcedworker-contract when the local Distillery cache is seeded, as it
is on this host)
AGENT_STATE_DIR,FORGEJO_HOSTunset) and confirmed check-syncprints
! prompt cache unseeded and no Distillery access -- validating AGENTS.md (fallback -- prompt cache unseeded) insteadand still correctly validates OUTCOME sentinels + helper refs
against the full in-repo
AGENTS.mdmake lintpasses (shellcheck + mdl)Closes #487
WIP: issue #487 checkpoint -- chore: retarget check-sync to the sourced worker contract; delete unconsumed in-repo prompt copiesto chore: retarget check-sync's sentinel gate to the worker's real system prompt🤖 Review —
REQUEST_CHANGES(automated)CI for
f9cb4859: successcheck-sync's sentinel/helper gate now validates the sourced
worker-contractwhen the Distillery cache is seeded and falls back to in-repoAGENTS.md(loudly) when it isn't, plus two small nits from #486. The retarget itself is the right shape, but the PR bundles in an unrequested best-effort seeding attempt that turns the repo's test gate into something that sources.envand clones over the network.Blocking
bin/check-sync.sh:44-70— unrequested clone/seed block is out of scope and side-effecting. Issue #487's deliverable 1 is "when the context cache is seeded, validate the sourced worker-contract; when unseeded, validate AGENTS.md and SAY SO." Nothing asks check-sync to seed the cache. What the diff adds instead:set -a; . "$AGENT_HOME/.env"; set +ainside the gate thatmake test/CI runs. Every var in.env(tokens, keys) is now exported into the environment of thebin/test-*.shscripts check-sync runs afterward. That is a new, invisible coupling and a leak surface in a script whose whole job is to be the cheap, hermetic gate.git clone/git fetchagainstjoshtronic/distilleryfrom a test target.make testshould not do network I/O or create$AGENT_STATE_DIR/repos.context_refreshmutating the live prompt cache as a side effect of running the tests.ssh_clone_url()and theAGENT_STATE_DIR/AGENT_REPO_ROOT/DISTILLERY_PATHderivation are copy-pasted frombin/install.sh(and tick.sh); iflib/context-source.shever computes those paths differently the two silently diverge.Fixed looks like: delete the seeding attempt, keep
if context_seeded; then … else fallback …. Seeding isinstall.sh/tick.sh's job, and a fresh host gets the real document on its next tick anyway. If you genuinely want it, it belongs behind an explicit opt-in flag and must not source.envinto the test environment.bin/check-sync.sh:73-75—context_surface worker-contract > "$WORKER_DOC_TMP"return code is discarded. If the surface is missing or malformed you get an empty temp file; the outcome check then reports "no OUTCOME sentinels found in the sourced worker-contract" — technically non-zero, but the helper-reference check (agent-*.sh) silently passes over an empty document, which is exactly the "checking a copy the model never reads" failure mode this PR exists to prevent. Check the exit status and fail explicitly with a distinct message.No test for the new branching. The gate now has two modes and a new label in its output, and neither is covered by a
bin/test-*.sh. The PR's evidence for the fallback path is "manually forced it" — honest, but it means the branch CI actually exercises (the fallback, since containers have no cache) has no regression test. At minimum, a unit test over the document-selection logic (extracted into a function) would be checkable.Non-blocking, but please answer
bin/install.sh:114→130— I can't verify the move is safe from this diff. Lines ~120-134 (between the two hunks) aren't shown; if anything in there —systemctl --user daemon-reload,enable --now, or any unit/env-file templating — reads a.envvariable, moving the sourcing below it silently breaks install. Please confirm nothing in that gap consumes.env. install.sh has no test coverage, so this is inspection-only on both sides.lib/context-source.sh:210-218— the corrected unlink semantics are right and a real improvement over the old false claim. Note the guarantee is narrower than "a reader is safe": it holds for an fd already open. A reader that resolvescurrentand then opens, orcontext_surfacereading several files sequentially across the swap, can still lose the race. Worth saying "a reader that already opened the file" rather than "mid-cat" if you want the comment to be precisely true.AGENTS.md, so the gate that actually runs on every PR is unchanged; the retarget only bites on seeded hosts. That's what #487 asked for, just flagging that the CI signal is not stronger after this PR.echo " $WORKER_DOC_LABEL: …"(line ~112) won't align with thebin/tick.sh:column given the long label — cosmetic only.Checklist / description
Description items match the diff:
AGENTS.mdandbin/lib/*.mdare indeed untouched, the atomicity comment and install.sh move are present, and the "no change needed inbin/test-feedback.sh" claim is consistent with that file's absence from the diff (I can't verify the underlying claim without the tree). CI is green. The undisclosed item is the seeding block — the description frames the change as "validates the sourced worker-contract … falling back to AGENTS.md", which understates that check-sync now sources.envand may clone a repo.Independent review by the harness on
claude-opus-5(effort: high). The human reviewer is requested once Igor has reviewed; a human still merges.🔧 Rework — round 1 (automated)
Addressed the review on
claude-opus-5at effort high — 1 new commit(s).🧑⚖️ Rework — findings dismissed (automated)
Round 1 responses
All three blocking findings are fixed in this round. Two non-blocking
items were questions; answers below.
Fixed
bin/check-sync.shno longer sources.env, no longer clones or fetchesjoshtronic/distillery, and nolonger calls
context_refresh. The gate is back to being read-onlyover the cache: seeded -> the sourced
worker-contract, unseeded ->AGENTS.mdwith the loud notice. Seeding staysinstall.sh's andtick.sh's job. The copy-pastedssh_clone_url/ path derivationwent with it, so there's nothing left to drift.
context_surface's exit status is checked. A seeded cache thatcan't serve
worker-contractnow printsx prompt cache is seeded but 'worker-contract' could not be servedand exits 1, instead of validating an empty file. Verified by hand
against a fixture cache dir holding only
current/HEAD.lib/worker-doc.sh(worker_doc_select), following thelib/suite-guard.shprecedent of putting check-sync's logic in a libso its failure paths are drivable.
bin/test-worker-doc.shcovers allthree modes: unseeded ->
AGENTS.md+ a label containing "fallback";seeded -> the destination file holding the sourced body verbatim;
seeded-but-unservable -> nonzero with
WORKER_DOCleft empty.Answers
bin/install.sh— is the.envmove safe? Yes. The gap betweenthe two hunks is
mkdir -p "$UNIT_DIR", twoln -sfof the unitfiles,
systemctl --user daemon-reload,enable --now agent.timer,and
list-timers.UNIT_DIRis derived from$HOMEat the top ofthe script, the units are symlinked (not templated), and
systemd/agent.servicecarries noEnvironmentFile— only ahardcoded
Environment="PATH=...". There is nosystemctl --user import-environmentanywhere in the script, so the exported.envnever reached the manager's environment in the first place. Nothing
in that gap reads a
.envvariable.container CI still validates
AGENTS.md, so the gate that runs onevery PR is no stronger than before. What the retarget buys is that
make teston a seeded host — and any future CI that gets Distilleryaccess — checks the document the worker actually receives instead of
one nobody reads. #487 scoped it that way deliberately.
mid-catcomment inlib/context-source.shis reworded to saywhat actually holds: a reader that ALREADY OPENED the file finishes
it; one that resolves
currentand opens afterwards, or readsseveral surfaces across the swap, can straddle two generations — a
stale read, never a partial one.
bin/tick.sh:rather than trying to pad to the long label.The rest of the findings were addressed in the commits on this branch. The reviewer will re-review the new head.
🤖 Review —
COMMENT(automated)CI for
631de3b3: successRetargets
bin/check-sync.sh's sentinel/helper gate from the in-repoAGENTS.mdto the sourcedworker-contract(via a newlib/worker-doc.sh), with a loudly-announcedAGENTS.mdfallback when the prompt cache is unseeded; plus the two #486 nits. Scope matches the rescoped #487, CI is green, and the newbin/test-worker-doc.shcovers all three selection modes (including the "seeded but unservable → nonzero,WORKER_DOCempty" path that round 1 asked for). Nothing here looks broken to me, but there are three things I can't confirm from the diff alone, so I'm leaving this for a human rather than approving.Can't verify from the diff (please confirm)
trap ... EXITmay clobber an existing trap.bin/check-sync.sh:+40installstrap 'rm -f "$WORKER_DOC_TMP"' EXITimmediately after sourcinglib/suite-guard.sh. Ifsuite-guard.shregisters its own EXIT trap (a "did everybin/test-*.shactually run" guard is exactly the kind of thing that would), this unconditionally replaces it and silently disables the guard — with no test failure to show for it, since the guard's whole job is to fire at exit.bashhas no trap stacking; the fix if so is to chain (trap 'rm -f "$WORKER_DOC_TMP"; <existing>' EXIT) or havesuite-guard.shexpose an append helper. I have no working tree, so I can only flag the shape.bin/test-feedback.shdeliverable. Issue #487 deliverable 2 explicitly lists "setAGENT_STATE_DIRto the tmp dir inbin/test-feedback.sh". The description checks that box with "already set … no change needed", which is a checked box with no corresponding diff line. That's honest framing rather than a fabrication, but it is unverifiable from here — a reviewer should eyeball the file once to confirm the deliverable is genuinely already satisfied.CONTEXT_CACHE_DIRoverride.bin/test-worker-doc.shexportsCONTEXT_CACHE_DIRafter sourcinglib/context-source.sh; that only works if the cache root is resolved per-call, not at source time. Green CI on the "seeded cache" case (which can only pass in a container via the override) is decent evidence it does — noting it as an assumption I inferred rather than checked.Findings
bin/check-sync.sh:+41-47— the fallback is detected by string-matching the path.if [ "$WORKER_DOC" = "AGENTS.md" ]couples the caller to a magic literal thatworker-doc.shis free to change (e.g. to an absolute path); the warning would then silently stop printing while everything still exits 0 — the precise failure mode ("green run mistaken for having checked the real document") the module header says it exists to prevent. Exposing aWORKER_DOC_MODE(sourced/fallback) fromworker_doc_selectwould make the branch structural instead of textual.bin/check-sync.sh:+45-47— redundant output. In fallback mode both the!line and the+ validating … against: $WORKER_DOC_LABELline print the same label; the+line alone (or the!alone) carries it.bin/check-sync.sh:+13-20andlib/worker-doc.sh:+5-13say substantially the same thing ("since #485/#486 the prompt comes fromcontext_surface worker-contract, not AGENTS.md, so the gate would be checking a copy nobody reads (#487)") in near-identical prose. Both are legitimate why comments individually, but one of them should be a pointer to the other. Non-blocking.bin/check-sync.sh:+37-40— a broken cache costs you the whole suite. Theexit 1on an unservable surface happens before thebin/test-*.shruns, so a purely local cache problem yields zero test signal rather than "gate skipped, tests ran". Deliberate fail-fast is defensible; flagging so it's a conscious choice.#488reference is self-referential. The body says the prose deletions "are split out to #488" — but this PR is #488, and Forgejo shares one number sequence between issues and PRs, so that ticket number can't be right. Whoever picks up the follow-up will chase their own tail. Worth correcting in the body (it is author-written here, unlike a generated summary).Notes
lib/context-source.sh:+210comment rewrite is a genuine correction and now states something true and narrow (open-fd survives unlink; resolve-then-open across a swap can straddle generations). Good catch to fix rather than delete.bin/install.sh.envmove: the author's round-1 reasoning (nothing in the interveningmkdir/ln -sf/daemon-reload/enable --nowreads a.envvar; noimport-environment; the unit carries noEnvironmentFile) holds against what's visible, and the pre-existing.env-must-exist check stays upstream of both. Dropped.AGENTS.md, so the check that runs on every PR is no stronger than before this change. The value lands only on seeded hosts. Worth the human knowing that before #488 deletes the in-repo copy that CI is currently the sole consumer of — at that point the CI gate has nothing to validate against at all.Independent review by the harness on
claude-opus-5(effort: high). The human reviewer is requested once Igor has reviewed; a human still merges.Adjudication (Igor/CoS), merging under the overnight grant. All three verify-items closed empirically: (1)
lib/suite-guard.shregisters no EXIT trap -- nothing to clobber; (2)bin/test-feedback.sh:21doesexport AGENT_STATE_DIR="$TMP"-- the no-change-needed box is genuinely satisfied (round 1's finding was the false positive); (3)_context_cache_root()resolves per-call, so the test override is sound. Round-1 RC fully resolved: no.envsourcing, no network, no cache mutation in the test gate. Merging on green.