Repository navigation
refactor(marketplace): the corpus reads authored bodies through candywalk's ONE authority (sdk#456) - #43
Conversation
…walk's ONE authority The generator carried its own copy of "where does a `skill:` node's body live": a `type: agent` branch in skillfile.go's read path, the same branch in extract.go's write path, and the same classifier again in four emission decisions. candywalk now owns that rule (opencharly/sdk#463 — ShapeOf / ReadNodeBody / NodeBodyLocation), and this repo consumes it, so the generator and deploykit's validator resolve ONE rule instead of two copies (opencharly/sdk#456). - `fillSkillFromFile` reads through `candywalk.ReadNodeBody` and reconciles the node against the file. `fillAgentFromFile` is DELETED: the agent shape needs no branch, because AuthoredBody carries it and its References are empty by construction, so one reconciliation serves both. - `extract`'s destination and the four emission decisions ask `candywalk.ShapeOf` instead of comparing the raw `type:` string. No `Type == "agent"` comparison remains in the module. - The "no body" message names the shape's own file (`candywalk.NodeBodyLocation`), so an agent node can no longer be told to look under `.agents/skills` — the misdirection that made opencharly/sdk#456's red gate unfixable for the author reading it. - Pin: `github.com/opencharly/sdk` v0.2026289.157 -> v0.2026296.1141, the tag carrying the authority. Proven at the emitted-artifact boundary: the same fixture project (a file-sourced skill, a file-sourced agent definition, a hook entity) emits a BYTE-IDENTICAL corpus under the pre-change and post-change generator — `diff -rq` reports no difference, agent artifact included. Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)
Review — PASSWhat I verified against the current stateCorrectness / claim-vs-diff.
Tests. Security / scope. No secrets, no new input surface, no privilege change. Dependency movement is a pin of the org's own Comments. There are zero comments, so there is nothing to disposition and no maintainer sign-off to weigh; the change stands on its own evidence. Non-blocking observations (do not gate)
None of these affect the correctness, safety, or test coverage of the change. Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
Summary
The corpus generator now reads authored bodies through
candywalk's ONE authority instead ofcarrying its own copy of "where does a
skill:node's body live" — the second caller of theresolution opencharly/sdk#463 put in the shared kit.
opencharly/sdk#456 was a drift between three encodings of one rule:
deploykit's collectorresolved
.agents/skillsfor every node (wrong), while this generator held the correct ruletwice — a
type: agentbranch inskillfile.go's read path and the same branch inextract.go's write path — and used the classifier again in four emission decisions. sdk#463 madecandywalkthe authority (ShapeOf/ReadNodeBody/NodeBodyLocation); this PR makes thecorpus consume it, which is what "one authority, both callers" means. Nothing is left in this repo
that decides where a body lives.
fillSkillFromFilereads throughcandywalk.ReadNodeBodyand reconciles the node againstthe file.
fillAgentFromFileis DELETED — the agent shape needs no branch:AuthoredBodycarries it, its
Referencesare empty by construction, and the one reconciliation serves bothclasses.
extractaskscandywalk.ShapeOffor its destination, and the four emission decisions(kimi manifest, R0 dispatcher ×2, opencode index, the skill/agent synthesis) ask the same
function instead of comparing the raw
type:string.candywalk.NodeBodyLocation), so anagentnode can no longer be told to look under.agents/skills— the misdirection that madesdk#456's red gate unfixable for the author reading it.
github.com/opencharly/sdkv0.2026289.157 → v0.2026296.1141, the tag sdk#463'smerge minted.
go mod tidyalso advances the grpc/protobuf/genproto transitives that pinrequires.
The change is a consolidation, and the invariant is that the corpus does not move: proven at the
emitted-artifact boundary below, byte for byte.
How tested
The head this body describes:
The repo's declared checks (its
AGENTS.md"Build / validate / test":go build,go test,and
charly box validateat the root), run on the committed tree, against the real pin:GOTOOLCHAIN=go1.26.8because this host's Go is 1.27.3 and the pinned linter build cannot read1.27 export data; the module declares
go 1.26.8.The artifact-boundary proof — the same project emitted by the OLD and the NEW generator, diffed.
The repo has no per-repo CI workflow (only
tag-on-merge.yml), and its R10 witness bed(
check-marketplace) gates the PUBLISHED corpus's shape — an artifact this diff cannot change, asthe following proves directly. A throwaway harness (never committed) writes the standard
writeFixtureproject plus a file-sourced skill node, a file-sourcedagent-type node and a hookentity, runs
generate, and copies the emitted tree out:Sixteen emitted files on each side — the agent artifact, both skills, both per-plugin manifests in
each family,
marketplace.json(both shapes),DISPATCHER.md,.well-known/skills/index.json,kimi.plugin.json,package.json,profiles.json— and zero differing bytes. The corpusdoes not move.
The control that FAILS without the change. The one behavioural delta this consolidation carries
is the message a missing body produces; under the pre-change generator the skill branch named its
trees as a Go slice and the agent branch had a separate message, neither derived from the shape
mapping:
restored, tree clean at the head:
The claim that this repo no longer decides the rule — pasted, not asserted:
The only remaining occurrence of the string is the comment recording that the copy is gone. Every
decision now asks the kit:
Test arms on this head: 54 passing entries across the module's suite.
Rulebook compliance
/charly-internals:marketplace(this repo'sAGENTS.mdnames it firstfor an emitter change),
:plugin,:skills,:git-workflow,:go, plus this repo's ownAGENTS.md(Part II fix: advance MARKETPLACE_REF to the marketplace's current main head #4).nothing comparing them. No failure surfaced in this leg; both controls above are green, and the
sdk leg's two findings (the label wire shape; the carrier whose gate fails for an unrelated
owner reason) are disposed of on their own threads — the ai.opencharly.skill wire entry cannot express a sub-agent definition:
type/model/toolsare dropped, so anagentnode rides the skill label as a plain skill spec#276 andPolicy: a skill lives with the code it describes — retire the skills-only repo class (22 repos / 94 skills measured) opencharly#600.
fillAgentFromFileis deleted, thefour classifier copies become calls, and the path rule now exists only in
candywalk.skillsskill and
AGENTS.mdPart II fix(marketplace.json): put description and version at top level per the spec #5 all state the two shapes, and the code now agrees with them.type:comparisons are gone, notdeprecated; the grep above is the claim-keyed sweep.
origin/main; no force-push, no amendafter push, no push to
main.diff -rqrc=0) is the boundaryproof for a generator change; the message control fails on the pre-change generator and passes
here.
boundary.
go.sumare the source-of-record, and the consumer that builds a binary ischarly.(
go build/go test/gofmt/vet/lint/charly box validate) ran on the committed tree, andthe artifact the change could affect is proven byte-identical. This repo declares no per-repo CI
workflow (
tag-on-merge.ymlonly); itscheck-marketplacebed gates the published corpus'sshape, which the A/B shows this diff cannot move.
AGENTS.md— candy entity + Go source together — the candy entity isuntouched: its
description:still describes the same generator, andplugin.providersisunchanged. Only the Go source and the module pin move.
AGENTS.md— generate and drift stay in step — both run the sameemission pipeline, which is why the A/B was run through
generateitself and not a helper.AGENTS.md— landing — PR-only, one commit; the tag is minted at merge.complete on its own: the pin bump and every in-repo caller of the rule. The
charlymodule-pinbump is a separate repo and a separate PR.
CLAIM; sdk#463 (the producer) is merged and taggedv0.2026296.1141, which is what this pin names.STATUSon Policy: a skill lives with the code it describes — retire the skills-only repo class (22 repos / 94 skills measured) opencharly#600 followsthe
charlyleg, when the two held carriers' drainability is measured rather than promised.A3 — attribution evidence, as delivered in this session
The runtime's own system message reads, verbatim:
Harness
DeepSeek Harness, modeldeepseek-v4.1-flash— the pair the footer names. This runtime isthe one opencharly/opencharly#538 records as rejected by the validator's model allowlist even though
it is real and running; cited here so the A3 check can be read against that open defect rather than
as an unattributed model name.
Change classification
Code change (Go generator + module pin), not documentation. Nine files: six Go sources, two
Go tests,
go.mod/go.sum. The change-class gate is this repo's declared checks, pasted above,run on the committed tree; the attribution tier the evidence supports is
fully tested and validated— the module's full suite passes and the changed path (emission)executed for real, with its output diffed byte-for-byte against the pre-change generator's.
Filed issues
None. Both findings this work surfaced are disposed of outside this diff and named under R1:
opencharly/spec#276 (the label wire entry cannot express a sub-agent definition) and the
layer-charly-internals-extraowner mismatch reported on opencharly/opencharly#600.Agent: charly
Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)