feat(lesson-capture): correction→bake-in loop v1 — lesson-capture fragment + mechanik bake-in doctrine (tk-7druqk)#88
feat(lesson-capture): correction→bake-in loop v1 — lesson-capture fragment + mechanik bake-in doctrine (tk-7druqk)#88zook-bot wants to merge 2 commits into
Conversation
…k doctrine (tk-7druqk) Adds template-fragments/lesson-capture.template.md: a lean (~39 rendered lines) append_fragments fragment instructing any agent to capture explicit operator corrections — agent-local feedback memory when the agent has auto-memory, plus an HQ lesson bead (-l lesson, assigned to mechanik) when the lesson should change shared process. Covers the dedup check (--status open,in_progress) and the bar (corrections only; approvals are not lessons). Adds a 'Lesson Bake-in' section to the mechanik prompt: triage lesson beads on hook, pick the durable home, dispatch edits via the bead→polecat path (Principle 6), close with a pointer to the shipped change, surface week-old lessons to the operator, and the anti-patterns (no approval statistics, no batch-holding, no overriding operator decisions). Activation (adding "lesson-capture" to agent_defaults.append_fragments in the consuming city.toml) is documented in the fragment header comment but deliberately NOT applied: city.toml edits drift session CoreFingerprints and drain detached manual sessions. Provenance: operator greenlight 2026-06-03, thread lo-d5by.
zook-bot
left a comment
There was a problem hiding this comment.
Blocking finding:
template-fragments/lesson-capture.template.md:32/:41: the fragment says to file and dedup lesson beads in HQ, but both commands run in the caller's current bead store. From a gc-toolkit rig worktree,gc bd listloads/home/zook/loomington/rigs/gc-toolkit/.beads/config.yaml, whilegc bd list -C "$GC_CITY"loads HQ at/home/zook/loomington/.beads/config.yaml. Since this fragment is intended for any agent prompt, rig agents would create and dedup-l lessonbeads in their rig DB, not HQ; city-scoped mechanik's hook would not reliably see or triage them. Please force the HQ store in both commands, for example withgc bd list -C "$GC_CITY" ...andgc bd create -C "$GC_CITY" ...or the equivalent documented HQ selector.
Checks performed:
- Reviewed PR diff against
origin/main. git diff --check origin/main...HEADpasses.- Probed
gc bd list --verbosevsgc bd list -C "$GC_CITY" --verboseto verify the store mismatch.
Note: I attempted to submit this as REQUEST_CHANGES, but GitHub rejected it because the authenticated account is treated as the PR author. This is a blocking review finding despite the GitHub review event being a comment.
…ds (tk-gst80h) Codex review on PR#88 found that the fragment's gc bd create/list commands run in the caller's current bead store: from a rig worktree they load the rig's .beads config, not HQ, so rig agents would file lesson beads where the city-scoped mechanik never sees them. Add -C "$GC_CITY" to both the create and dedup-list commands (probe confirmed it loads /home/zook/loomington/.beads/config.yaml even with BEADS_DIR pinning the rig store), plus a two-line comment in the code block explaining why. Rendered fragment is 40 lines, within the ~45 budget; all 13 fragments + mechanik prompt still parse and render.
zook-bot
left a comment
There was a problem hiding this comment.
No blocking findings on the updated head.
Reviewed after the follow-up fix commit 9207893, which forces the lesson bead create and dedup commands through the HQ bead store with -C "$GC_CITY". The earlier HQ-store blocking finding is addressed.
Checks performed:
- Reviewed the PR diff against
origin/main. git diff --check origin/main...HEAD- All
doctor/*/run.shchecks withGC_PACK_DIR=$PWD - Targeted Go
text/templateparse/render probe for all top-level template fragments, the mechanik prompt, and the newlesson-capturefragment
|
Back to draft (operator, 2026-06-05): a feature that isn't wired in just sits and confuses. #88 is half-wired by construction — the mechanik "Lesson Bake-in" section goes live on merge (mechanik told to triage a lesson-bead queue), but the lesson-capture fragment that fills that queue stays dormant until To make it useful = the city.toml activation, scoped to operator-facing agents (mayor/mechanik/deacon — the rest never receive corrections). That edit drifts session CoreFingerprints and can drain detached sessions; the fix (gascity f96fe8dc / PR#25) merged 06-03 and gc was rebuilt 06-05 17:46, so it's likely deployed — confirm behavior before the edit. Plan: land #88 + the append_fragments activation together at a safe window (wire-and-land), not #88 alone. |
…one (tk-vpx62) Second arm of tk-vpx62 (mayor scope extension, 2026-07-21). The first arm handled a PR whose anchor is stranded; this one handles a PR whose anchor is GONE. Every close-on-land path — merge-skill.sh, this reconciler, the refinery patrol — enumerates from the BEAD and reads its pr_number. Sound while the bead outlives the PR, which close-on-land guarantees. But a PR whose bead is CLOSED is not merely unhandled, it is unseen: no scan starts anywhere that reaches it, so it never lands, never escalates, never times out. It does not read as broken, it reads as absent. The pre-#163 close-on-publish model created that state by design, and the 7 PRs it stranded (#171 #170 #166 #108 #88 #80 #77) sat untouched for weeks — found only by a human cross-checking `gh pr list` against the ledger by hand. So reconcile from the other side too: enumerate open PRs, subtract every PR number any LIVE bead references, report the remainder. Verified against the live ledger: flags exactly those 7 and correctly excludes in-flight PR#195. Detection and surfacing ONLY, per the mayor's scope note — it never merges, closes, or reopens an anchorless PR. Disposition stays an operator call. Convergence, since a patrol pass runs on every idle wake: - Escalate once, bounded by an anchorless_flagged marker written to the closed bead BEFORE the mail (stamp-first, mirroring the merged path's close-first). A failed stamp means no bound, so it does not mail — a delayed escalation is recoverable, a mail storm is not. - A PR with NO bead in any state is logged but never mailed: nothing durable exists to record that we already said it. - A failed ledger read is empty, not "[]", and the scan fails CLOSED on it — treating "could not read" as "nothing is tracked" would flag every open PR at once. - Anchor resolution picks the OLDEST bead carrying merge_result, so the operator is pointed at the bead that OPENED the PR rather than a review bead or a later "address findings" child (several closed beads routinely name one PR); the mail lists the whole set regardless. Zero gating anchors is no longer an early exit — that was precisely the state where this scan matters most (no live anchors WITH open PRs is the stranded shape). Tests: 24 new hermetic assertions (62 total, all pass); verified 13 of them FAIL against the pre-arm script while all 38 pre-existing ones still pass. Sibling suites green (merge-skill 36, one-anchor-per-pr 13, pre-open-resolve 16, signoff-anchor-resolution 14, signoff-anchor-failclosed 14, reconcile-graduated-convoys 14, reconcile-rig-checkouts 8, husk-guard 16). bash -n + shellcheck clean at warning severity.
…astownhall (tk-c07sq)
Addresses the pre-open signoff finding on tk-dmqdq (P2, line 31).
The provenance row credited `fa487632b` to `gastownhall/gascity` as a
2026-07-11 merge. Verified against the local gascity checkout:
- `fa487632b` is NOT an ancestor of `upstream/main` (gastownhall);
it IS an ancestor of `origin/main` (zookanalytics fork).
- `clearStaleOpenAssigneeForPoolRoute` appears nowhere in
`upstream/main` — the change is fork-local, not upstream at all.
- `(#88)` in the subject is the fork PR, not a gastownhall PR.
- 2026-07-11 is the AUTHOR date; committer date is 2026-07-22. The
fork rebases `main`, so the SHA churns (the same subject appears on
a dozen rebased commits) — no durable "merged on <date>" claim.
- `engdocs/architecture/dispatch.md:180` was cited as "upstream's own
prose", but upstream's copy of that file carries no such passage.
Rewrites the row to name the fork as producer, state plainly that the
change is absent from canonical gascity, and pin verification to
`zookanalytics/gascity` `origin/main` `7bba3de3b`. Line-number citations
re-verified at that commit and left as-is.
Also scopes the two body claims that inherited the same misattribution
(Lane 1 "Also clears", Lane 3 "no longer the only way to clear") so the
doc's field contract does not read as canonical-gascity behavior.
…he durable record, not the coordination state (tk-4jz9s) The belief said documentation is the system's memory and that "what's written survives", but never said where "written" lands. An agent could satisfy it completely by writing a long analysis into the transient state that coordinates the work — durable-looking, but not part of the record anyone inherits with the work. That ambiguity stalled four docs-only PRs (#171, #170, #108, #88) for 4-7 weeks: the open question was not review, it was whether those documents belonged in the durable record at all. Stated as a principle, not a substrate: memory lives in the durable record, not in the state that coordinates the work. Supersedes PR #212, which encoded the same rule by naming the Gas City substrate (repo vs bead-store, committed-file vs bead-comment) inside an engine-agnostic Core Belief — the wrong altitude for a belief a beadless engine must also be able to satisfy. Distinct from the earlier PR #203 (tk-zdkfe) attempt in docs/file-structure.md, which governs the documentation surface, not whether a work product joins the durable record at all. Sharpened in place on the existing belief; one line, two sentences, matching neighbouring belief density. docs/file-structure.md, other beliefs, agent prompts, and template-fragments untouched; lesson-capture (tk-63qgj) left out of scope.
Summary
Correction→bake-in loop v1:
lesson-capturefragment + mechanik bake-in doctrineWhy (self-contained context — do not assume any other context is injected)
Operator decision (2026-06-03, mechanik thread lo-d5by "ship correction-bake-in loop v1"):
the city should continuously reinforce what works and stop repeating what doesn't.
Analysis converged on building the correction→bake-in loop first: when the operator
gives corrective feedback ("this isn't right", "don't do X", "always do Y first"), that
correction must become a durable process change — not evaporate when the conversation ends.
This is foundation.md's first belief ("Agents improve… every lesson compounds into the pack
so attention is never spent twice") made operational. Deliberately NO statistics, NO
approval-rate tracking, NO new agents/formulas — one instance of a correction is enough
signal. (An adversarial review killed the statistics-based alternative; corrections carry
the signal, approvals don't.)
Today NOTHING instructs agents to capture operator corrections. Some agents (mechanik,
mayor) have auto-memory and do it ad hoc; pool agents (polecats, dogs) have no memory and
lose corrections entirely. This change closes that gap with a convention fragment + a
mechanik triage doctrine.
Optional deeper context (readable on this host, NOT required):
/home/zook/loomington/.gc/agents/mechanik-thread/gc-toolkit.mechanik-thread-adhoc-7d34f10c5d/fill-the-queue-design.mdDeliverable 1:
template-fragments/lesson-capture.template.md(NEW)A gc-toolkit core template-fragment, written for injection into ANY agent prompt via
agent_defaults.append_fragments. Studytemplate-fragments/siblings (e.g. the existingfragments referenced by city.toml's
append_fragments = ["command-glossary", "operational-awareness"]) and match their{{ define "<name>" }}structure exactly —the define-name must be
lesson-captureto match the append_fragments key convention.Content the fragment must convey (write it in the pack's voice; concise — this lands in
every agent's prompt, so budget ~30-45 lines):
Trigger: the operator (human) gives EXPLICIT corrective feedback on how you worked —
"this is wrong", "don't do X", "you should have done Y", "stop doing Z", a redirect after
a mistake. NOT routine instructions, NOT preferences you already honored, NOT agent-to-agent
feedback. v1 is explicit corrections only.
Action A — agent-local (only if you have auto-memory): write a
feedback-type memorynow, per your memory conventions (include the why and how-to-apply; quote the operator
where short). This makes the lesson durable for YOUR future sessions.
Action B — city-level (always, when the lesson should change SHARED process): if the
correction implies a change to shared machinery — an agent prompt, a formula step, a
convention doc, a review check — file a lesson bead in HQ:
Bar and dedup: real corrections only — a lesson bead is a claim that the process
should change. Before filing, check
gc bd list -l lesson --status open,in_progress(open AND in_progress — claim flips status) and extend an existing bead's notes instead of
duplicating. Do not file statistics, scores, or "the operator approved this" — approvals
are not lessons.
What happens next (one line, so filers know the loop closes): the mechanik triages
lesson beads, picks the durable home, dispatches the change, and closes the bead with a
pointer to the shipped change.
Deliverable 2: mechanik prompt amendment (
agents/mechanik/prompt.template.md)Add a compact "Lesson bake-in" section to the mechanik prompt (place it near the existing
inputs/outputs doctrine; match surrounding voice and heading style). Content:
-l lesson, HQ, assigned to you) are corrections other agents capturedfrom the operator. Triage them on hook like routed work.
convention doc, review-leg check, or (if it's genuinely agent-local) the filer's memory
with no pack change. Then dispatch the gc-toolkit edit through the normal bead→polecat
path (Principle 6 — you scope, polecats edit), and close the lesson bead with a pointer
to the shipped change (PR/commit/bead).
operator conversation, not silently backlogged.
corrections waiting for a pattern — ONE clear correction is sufficient signal; do not
bake in a "lesson" that contradicts an operator decision without asking.
Deliverable 3: activation note (DOCUMENT ONLY — do NOT apply)
Activation = adding
"lesson-capture"toagent_defaults.append_fragmentsin theconsuming city's
city.toml. Do NOT touch any city.toml in this PR. Document the wiringline wherever the pack documents fragment adoption (follow the existing pattern — e.g. how
other append_fragments fragments are documented; a short note in the fragment's header
comment or the pack docs is enough). Reason it's deferred: city.toml edits drift session
CoreFingerprints and drain detached manual sessions (known issue, fix not yet deployed);
the operator/mechanik applies the wiring at a safe moment after merge.
Acceptance criteria
template-fragments/lesson-capture.template.mdexists,{{ define "lesson-capture" }},covers: trigger (explicit operator corrections only), Action A (memory, if agent has
it), Action B (HQ lesson bead with the exact create command), dedup
(
--status open,in_progress), the bar (no approvals/statistics), loop-closure line.Principle-6 dispatch, close-with-pointer, no-rot rule, anti-patterns).
Provenance
Operator greenlight 2026-06-03 (thread lo-d5by). Design record: thread working note path
above. Foundation:
docs/foundation.md("Agents improve", "attention is the budget").Implementation notes
Implemented: lesson-capture fragment (39 rendered lines; trigger/Action A/Action B/dedup/bar/loop-closure, activation line in header comment, NOT wired) + mechanik 'Lesson Bake-in' doctrine (durable-home menu, Principle-6 dispatch, close-with-pointer, no-rot, anti-patterns). Validated: fragment+prompt parse and render via text/template mimicking gascity loadSharedTemplates/renderPrompt. No city.toml touched, no gastown files touched.
Refinery handoff
tk-7druqk(task, P2)polecat/tk-7druqkmainmainvia Gastown Refinery.