Repository navigation
Port Stele promotion to the current ledger API; install promoted skills; clean-clone tests (#1, #2, #8) - #10
Closed
Deep-Sixed wants to merge 3 commits into
Closed
Deep-Sixed wants to merge 3 commits into
Deep-Sixed wants to merge 3 commits into
Conversation
Fixes #1: EvecorStelePort targeted a Stele LedgerStore API removed in the ledger redesign (commit/DuplicateArtifactError/duplicate_policy), so the MCP server failed at import. It now records the candidate with create_pending(parser=agentsync-kanon, ...) and seal(), against a LedgerStore bound to a BlobStore evidence archive. SEALED is reported as PromotionState.COMMITTED. A retry for the same run_id reuses its record (sealed + same content -> committed; pending -> re-sealed; otherwise failed) instead of recording a second artifact. The stele extra is now pinned to a Deep-Sixed/Stele commit, and a missing/incompatible stele surfaces its real ImportError. Fixes #2: promotion never reached the approved catalog. After Stele seals, Kanon installs the candidate at approved/<dir_name>/SKILL.md (atomic write; a different existing skill is rejected before Stele is called), reloads the Skill Server, and records redeemed_skill_id on the obligation. The Enforcer shares the server's SkillServer index and looks up a task's redeemed skill by id, so re-enforcing the task is covered instead of minting a new obligation. Storage scripts, env example and README cover the new storage/stele/archive directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VnaMtsgmbeB8QWCrqdpSWc
Deep-Sixed
marked this pull request as ready for review
September 25, 2026 22:23
mcp 2.x renamed FastMCP to MCPServer, so with `mcp[cli]>=1.0` a fresh install resolves to 2.x and agentsync.mcp.server fails at startup (ModuleNotFoundError: mcp.server.fastmcp). Cap the mcp and dev extras at <2 until the server is ported to the 2.x API. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VnaMtsgmbeB8QWCrqdpSWc
Tests read seed skills from storage/skills/approved/, which .gitignore
excludes, so a fresh clone failed 12 tests; and four modules imported
stele at module load, so without the [stele] extra they errored during
collection.
- Add committed seed skills under tests/fixtures/approved/
(sailpoint-joiner-provisioning, jamf-ade-enrollment, a frontmatter-less
broken-skill, and a directory without SKILL.md) and point the skill
server, enforcer, local-service and MCP-service tests at them.
- Skip the Stele port, local-service and MCP-service tests, and the
server-import storage test, with importorskip("stele") when the
[stele] extra is not installed.
- README: describe the clean-clone behaviour.
Clean clone, no stele: 83 passed, 14 skipped. With the pinned stele:
102 passed, 10 skipped (ContextForge suites only).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VnaMtsgmbeB8QWCrqdpSWc
Deep-Sixed
force-pushed
the
claude/friendly-curie-7inb1h
branch
from
September 26, 2026 07:43
7e4903c to
6563e58
Compare
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.
Fixes #1, fixes #2, fixes #8. Also pins
mcpbelow 2 so the server starts on a fresh install.#1: EvecorStelePort against the current Stele ledger API
The port called
create_pending(..., duplicate_policy=...),store.commit()andDuplicateArtifactError. Stele's ledger redesign (Deep-Sixed/Stele#12) removed all three, soagentsync.mcp.serverfailed at import.LedgerStore(db, BlobStore(archive_root))and records the candidate withcreate_pending(parser=ParserIdentity("agentsync-kanon", <version>), parser_config={validation_level, dir_name, file_name}), thenseal(). There is no input snapshot, because Kanon parsed no input document.SEALEDrecord is reported asPromotionState.COMMITTED, so the MCP tool output (state: "committed") is unchanged.run_id, and the obligation'srun_idis that key. A second attempt with the samerun_idreuses the existing record:committed(idempotent);failed, and the existing artifact is not overwritten.get_by_run_id(obl.run_id).steleis missing or incompatible, the server now raises the realImportErrorwith its cause, instead of a generic message.[stele]is pinned togit+https://github.com/Deep-Sixed/Stele@10bbf3f, replacing the unpinnedfile:///mnt/...path. The README says how to use a local checkout instead.storage/stele/archive/(env varAGENTSYNC_STELE_ARCHIVE_ROOT). It is covered by the bootstrap, backup and restore scripts,.gitignore, and the env example. The ledger's records point into it, so the two are backed up together.#2: promoted skills land in the approved catalog
PromotionAdapterinstalls the candidate atapproved/<dir_name>/SKILL.md. It writes a temp file and renames it into place, rejects anydir_namethat isn't a single directory name, then callson_installed(the server passesSkillServer.reload).approved/<dir_name>already holds different content, the promotion is rejected as a validation error before Stele is called. Installing identical content again is allowed.redeemed_skill_id. When enforcing a task, the Enforcer looks up the skill that task already produced by its ID, so re-enforcing a redeemed task returnscoveredand no second obligation is minted. If that skill has since been removed, the task is obligated again.SkillServerbetween the skill tools and the Enforcer's lookup; before this change they were two indexes that were never reloaded.PromotionAdapterwithoutapproved_rootbehaves as before, so existing callers and tests are unaffected.#8: the test suite passes on a clean clone
tests/fixtures/approved/:sailpoint-joiner-provisioning,jamf-ade-enrollment, abroken-skillwith no frontmatter, and a directory with noSKILL.md. The skill server, enforcer, local-service and MCP-service tests read from there, never from the git-ignoredstorage/skills/approved/.pytest.importorskip("stele"). Without the[stele]extra they skip; before, they errored during collection.mcp pinned below 2
mcp[cli]>=1.0resolved to mcp 2.x. That version renamedFastMCPtoMCPServer, so the server failed at startup withModuleNotFoundError: mcp.server.fastmcp. Themcpanddevextras are nowmcp[cli]>=1.0,<2, which resolves to 1.30.0 and importsFastMCP. Porting to the 2.x API can be done separately.Tests
Run on a fresh clone of this branch, in a new venv, under Python 3.12:
mcp<2+ pytest, no Stele[stele]extra)master, for comparison (with Stele10bbf3fandmcp<2)storage/unchanged.New or changed tests:
tests/test_evecor_stele_port.py: ported to the current API. Adds tests for one record per run, idempotent retry, different content on retry → failed, resuming a pending record, and the recorded producer identity.tests/test_promotion_catalog.py(new, runs without Stele): install plus reload closes the loop, removing the skill brings the obligation back, a conflictingdir_nameis rejected before Stele, a failed commit installs nothing, and paths outsideapproved/are rejected.tests/test_mcp_service_smoke.py: the full MCP loop now also checks that the promoted skill is listed and that re-enforcing the task returnscovered. It copies the fixture catalog intotmp_path, so promotion never writes into the repo.tests/test_operational_hardening.py: covers the archive directory in bootstrap, backup/restore and_ensure_storage_dirs.Not in this PR
run_idis used up. A later retry of the same obligation getsfaileduntil the obligation is cancelled and a new one minted. Minting a newrun_idfor each attempt would fix this, but it changes the obligation model.record_external_artifactAPI for this kind of caller. Once it merges, the port can switch to it and move the Stele pin.requires-python = ">=3.14"is unchanged. These results are from 3.12, which is what this environment has.🤖 Generated with Claude Code
https://claude.ai/code/session_01VnaMtsgmbeB8QWCrqdpSWc