fix: materialize bundle agent identity (SOUL.md) on upgrade (#2818)#2819
fix: materialize bundle agent identity (SOUL.md) on upgrade (#2818)#2819chubes4 wants to merge 2 commits into
Conversation
Agent-level memory carried by a committed bundle (manifest included.memory=["agent/SOUL.md"]) was never applied to the live agent store on `agent upgrade`. The upgrade planner's projection (AgentBundleLifecycleProjection) emitted agent_config, pipeline, flow, and file artifacts (prompts/rubrics/etc.) but skipped the bundle's agent-layer memory entirely, so SOUL.md was absent from the plan and the live identity stayed stale. Add a focused AgentBundleMemoryArtifact unit that owns the authored-identity-vs-learned-memory rule in one place: - target_artifacts(): surface authored identity (SOUL.md, authority tier agent_identity) as a `memory` artifact in the plan. - current_artifacts(): project the live store content for installed memory artifacts so diffs classify as no-op / needs-approval cleanly. - apply(): write only bundle-declared authored identity to the live store via AgentMemory::replace_all(), and hard-refuse learned runtime memory. Wire it into the planner projection and the core artifact applier, and make AgentBundler::import() materialize SOUL through a ledger-aware, local-modification-protected path on upgrade while skipping learned runtime memory (MEMORY.md, WAKE.md, daily/*) so a deploy never clobbers what the live agent accumulated. Fresh installs still seed every bundle-carried file. Closes #2818
Homeboy Results —
|
The fresh-install path materialized agent identity via write_agent_files' direct file_put_contents, which bypasses the WP_Agent_Memory_Store seam. Against a non-disk store (the wp_agent_memory_store fake that CI registers) the installed SOUL never landed in the store, so reading it back reported not-found — failing the new test's "Fresh install writes SOUL.md to the live store" assertion. Materialize authored identity through AgentBundleMemoryArtifact::apply() (the store seam) on BOTH fresh install and upgrade, and skip authored identity in write_agent_files so it is never double-written and non-disk stores stay authoritative. Learned runtime memory (MEMORY.md, WAKE.md, daily/*) is still seeded on fresh install and preserved on upgrade.
CI fix — fresh-install SOUL now materializes through the store seamThe failing test ( Root cause: the fresh-install path wrote agent identity via Fix (commit
Verification:
|
Summary
wp datamachine agent upgrade <bundle> --slug=<agent>did not materialize a committed bundle's agent-level memory (agent/SOUL.md) into the live agent store. A flow-less, memory-bearing bundle (manifest.included.memory=["agent/SOUL.md"],flows:[],pipelines:[]) shipped canonical identity in git but the live agent kept running its stale SOUL.Closes #2818.
Root cause — where agent-level memory was dropped
agent upgradeplans throughAgentBundleAbilityService::plan_for_bundle()→AgentBundleLifecycleProjection::target_artifacts(). That projection emittedagent_config,pipeline,flow, and file artifacts (prompts/rubrics/tool-policies/auth-refs/seed-queues) but never iterated the bundle's agent-layer memory files. Somemory:agent/SOUL.mdwas absent from the plan entirely (not auto-apply, not needs-approval, not no-op).AgentBundleUpgradePlanner::artifacts_from_bundle()does buildmemoryartifacts (line 51) — but that method is a separate path not used byplan_for_bundle(). The package planner itself bucketsmemoryartifacts correctly when given them (seetests/agent-bundle-upgrade-planner-smoke.php[1]); the artifacts simply never reached it. The apply side (AgentBundleCoreArtifactApply) likewise had nomemorybranch, andAgentBundler::import()'swrite_agent_files()wrote all$bundle['files']unconditionally — which would clobber learned memory if a bundle ever carried it.Confirmed live before the fix (
--dry-runagainstextrachill-roadie/bundles/roadie, agentroadie): plan showedagent_config+ 4 prompts as no-ops,memory:agent/SOUL.mdabsent; liveuploads/.../agents/roadie/SOUL.md(Mar 20) differed from the committed bundle SOUL.The fix
New
AgentBundleMemoryArtifactunit owns the authored-identity-vs-learned-memory rule in exactly one place:target_artifacts()— surfaces authored identity (SOUL.md, authority tieragent_identity) as amemoryartifact in the plan, with the same hash/diff/approval semantics as every other artifact.current_artifacts()— projects the live store content for installed memory artifacts (ledger-gated) so diffs classify as no-op / needs-approval cleanly and an unmanaged live SOUL is never reported as drift.apply()— writes only bundle-declared authored identity to the live store viaAgentMemory::replace_all(), and hard-refuses learned runtime memory with aWP_Error.Wiring:
AgentBundleLifecycleProjection::target_artifacts()/current_artifacts()now include memory artifacts.AgentBundleCoreArtifactApply::apply()gains amemorybranch (needs-approval / PendingAction path).AgentBundler::import()materializes SOUL through a ledger-aware, local-modification-protected block on upgrade, andwrite_agent_files()is skipped for identity files on upgrade (fresh installs still seed every bundle-carried file).Authored-identity vs learned-memory safeguard
The whole point of committing SOUL is versioned, deployable identity — so authored identity (
SOUL.md) is upgradeable. Learned runtime memory (MEMORY.md,WAKE.md,daily/*) must not be clobbered by a deploy. The gate keys on the memory file registry'sauthority_tier: onlyagent_identityis materializable; everything else is refused (with a'SOUL.md'fallback when the registry isn't loaded). On upgrade, learned-memory files are skipped entirely in both the importer and the artifact applier, and apply is local-modification-aware (parity with the existing prompt/rubric/--rebase-localconflict handling) so local SOUL edits surface asneeds_approvalinstead of being blown away.Verification
--dry-run):memory:agent/SOUL.mdabsent from plan; live SOUL ≠ bundle SOUL.tests/agent-bundle-memory-artifact-smoke.php(15 assertions, all pass): SOUL surfaces as a target; learnedMEMORY.md/daily/*do not; the upgrade guard andapply()refuse learned memory; the unregistered-SOUL.mdfallback holds.test_upgrade_materializes_authored_soul_without_clobbering_learned_memoryinAgentBundlerImportTest(fullwp_agent_memory_storefake): fresh install writes SOUL + tracks it in the ledger; upgrade materializes the new SOUL into the live store; a learnedMEMORY.mdwritten post-install survives the upgrade.agent-bundle-upgrade-planner37,agent-bundler-directory-adapter55,agent-bundle-template-upgrade-tracking9). The 4 pre-existing standalone-smoke failures (extension-artifacts,package-portability,portable-update,runtime-drift) reproduce identically onorigin/mainand are unrelated to this change.php -l+phpcsclean on all changed files.homeboy test data-machinecould not bootstrap the WP unit suite — the host wp-codebox runner is currently broken (wp-codebox --versionprobe regression), as flagged in the task. The new integration test is well-formed and will run once that runner is restored.