Skip to content

v2.10.0: memory across runs and learning PRs - #14

Merged
Param-Harrison merged 6 commits into
mainfrom
release/v2.10.0
Sep 27, 2026
Merged

Param-Harrison merged 6 commits into
mainfrom
release/v2.10.0

Conversation

@Param-Harrison

Copy link
Copy Markdown
Contributor

Summary

  • Repo-local memory (.factory/memory/lessons.md, capped, injected via buildContextPack) since headless Claude's own auto-memory is operator-machine-local state the factory can't rely on (research/agents/claude/memory.md).
  • A read-only retro stage runs after an issue's final outcome (merged, rejected, or given up after the third verify rejection) and proposes at most one lesson or skill edit, or none.
  • factory learn batches pending proposals into one PR on a daily factory/learning-YYYYMMDD branch, exempt from protectedPaths only for .factory/memory/** and .claude/skills/**. Never auto-merges; shows in the dashboard inbox as its own read-only kind.
  • Structural fix, found during this release's own verification: touchesProtectedPath now bakes ALWAYS_PROTECTED_PATHS (.claude/**, .factory/**) into itself rather than at each call site, closing the same class of gap at a second call site (merge-policy.ts's autoEligible) that a caller-side-only fix would have missed.

See CHANGELOG.md for the full v2.10.0 entry, including what's deliberately deferred.

Test plan

  • make check (typecheck + full test suite + skills-ref validation) green — see commit history for output.
  • Genuine revert-and-fail proof for both structural fixes (protected-path build-stage check, and the touchesProtectedPath single-resolver fix), each confirmed to fail on revert and pass on restore.
  • Verifier agent independently exercised factory learn's ordering (rows marked learned only after push+PR succeed), runRetro's spend-cap accounting and non-mutation of run status, and the disjointness of touchesProtectedPath/outsideAllowedPaths — verdict: works as described.
  • Scoped prose check (check-prose.py) clean on every line this release added.
  • Live run against learnwithparam/splitbill-demo: deferred pending your reset OK (same precedent as v2.7.0's live-run deferral) — the installed production factory predates this branch, so a genuine run needs a clean baseline reset first.

🤖 Generated with Claude Code

Param-Harrison and others added 6 commits September 27, 2026 20:19
…sions

v2.10.0 item 1. Probed the factory's exact claudeArgs flags against a fresh
throwaway repo: the CLI's system/init event still reports an active
memory_paths.auto path, and the model saw the invoking user's global
CLAUDE.md, even with --setting-sources project,local (user excluded) and
--no-session-persistence. The path is keyed by a hash of cwd under the
operator's own ~/.claude/projects/, so it's per-worktree, machine-local, and
invisible to CI or a VPS runner. Confirms the roadmap's design: the factory's
own lessons memory must live in the repo (.factory/memory/lessons.md, item 2),
never depend on this mechanism.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
v2.10.0 item 2. buildContextPack (src/context.ts) now reads
.factory/memory/lessons.md as a "lessons learned" section, right after
AGENTS.md. Capped independently at 8 KiB (MAX_LESSONS_BYTES), separate from
the pack's own 64 KiB budget, keeping the most recent lines when it grows
past that since a newer lesson is more likely to still apply. install.sh
scaffolds a starter file and treats it as repo-owned, like charter.md and
config.example.json: --update never overwrites accumulated lessons. Works
identically on the Mac, a VPS, or in CI, since it is only a file read off the
worktree, unlike ~/.claude's operator-local auto-memory (research/agents/claude/memory.md).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Plan v2.10.0 items 3-4. A read-only retro stage (Haiku by default) runs after
an issue's final outcome (merged, rejected, or given up on after verify
rejections) and proposes at most one lesson or skill edit, or none. `factory
learn` batches every pending proposal into one PR on a daily
factory/learning-YYYYMMDD branch, exempt from protectedPaths only for
.factory/memory/** and .claude/skills/**, checked by diffing the branch
before any push. It never auto-merges, and shows in the inbox as its own
read-only kind since it has no linked issue to chatops against.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… config

Plan v2.10.0 structural test. touchesProtectedPath's build-stage call
(src/watch.ts) relied entirely on the repo's own protectedPaths, which
defaults to []: with no config, a Bash-made edit to .claude/** or .factory/**
would reach a push, even though guard-paths.sh already hardcodes both as
unconditionally protected for interactive Edit/Write tool calls. This adds
the same ALWAYS_PROTECTED_PATHS to the build-stage diff check so the two
enforcement paths agree. `factory learn`'s branch never calls
touchesProtectedPath (it uses outsideAllowedPaths instead), so its exemption
never weakens this for a normal build. Reverting the merge at the call site
reproduces the gap and fails the new scenario test (confirmed manually).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Verification on the prior commit (a874ca0) found a second call site,
src/merge-policy.ts's autoEligible, that also uses touchesProtectedPath but
was never merged with ALWAYS_PROTECTED_PATHS: a low-risk PR touching
.claude/** or .factory/** could still be judged auto-eligible on its own,
even though this is currently unreachable in practice (the build-stage push
check already blocks it earlier). Rather than patch that one call site too
and leave a third future caller exposed to the same mistake, the merge now
lives inside touchesProtectedPath itself, so every caller gets it for free.
watch.ts's build-stage call drops its now-redundant explicit spread.

Reverting the merge back out of touchesProtectedPath reproduces the gap and
fails three tests: the two ALWAYS_PROTECTED_PATHS tests in boundary.test.ts
and scenario test 12b (confirmed manually, then restored).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Retro stage plus factory learn (plan v2.10.0 items 1-4), and a merge-time
follow-up: touchesProtectedPath now bakes ALWAYS_PROTECTED_PATHS in itself
rather than at each caller, closing the same gap at a second call site
(merge-policy.ts's autoEligible) the first fix missed. The live splitbill-demo
run is deferred pending your reset OK, same as v2.7.0's precedent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Param-Harrison
Param-Harrison merged commit 55464cc into main Sep 27, 2026
2 checks passed
@Param-Harrison
Param-Harrison deleted the release/v2.10.0 branch September 27, 2026 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant