Skip to content

feat(skill): author the marketplace skill where its code lives - #45

Merged
github-actions[bot] merged 1 commit into
mainfrom
feat/skill-home-marketplace
Oct 23, 2026
Merged

github-actions[bot] merged 1 commit into
mainfrom
feat/skill-home-marketplace

Conversation

@aitrawog

@aitrawog aitrawog commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Agent: charly-six-add

Summary

The marketplace skill is authored HERE now — the repo that holds the thing it documents — instead of only in the layer-charly-internals prose carrier, which holds no code. The destination is MEASURED, never chosen (opencharly/opencharly#611): corpus generation, the refs list, the drift gate and the daily refresh PRs are this plugin's own surface.

$ gh api "search/code?q=filename:SKILL.md+org:opencharly+path:.agents/skills/marketplace" --jq .total_count
1        # one hit — the carrier — so this body existed in no other repository

Per-file counts, parsed from git show --numstat --format='' 40b8e7e (additions, deletions):

103     0      .agents/skills/marketplace/SKILL.md
6       1      AGENTS.md
23      0      candy/plugin-marketplace/charly.yml
2       1      charly.yml

What the diff carries:

  • .agents/skills/marketplace/SKILL.md (+103) — the body, copied byte-identically from the carrier at its main. One sha256, three trees:
    7d4d26763498cd228a1ad8d5825c821b794aa34e4cda0ca542ad011a572aa94b
    (carrier origin/main · carrier checkout · this tree — all equal, re-measured after the commit).
    It sits at the REPO ROOT because a skill body resolves against the OWNING CANDY's repo root (sdk/deploykit's candyRepoRoot) — the same reason plugin-agent's and distro-arch/candy/arch-skills' bodies read that way.
  • candy/plugin-marketplace/charly.yml (+23) — marketplace-skill:, a ROUTING-ONLY skill: node: name / family / owner / triggers, and NO inline description: / content: (an inline body that disagrees with its file is a hard error in the marketplace generator). owner: plugin-marketplace names a candy of THIS project. family: internals is carried over UNCHANGED, so every /charly-internals:marketplace address survives the move.
  • AGENTS.md (+6/−1) — the canonical-files list names the routing node and the body.
  • charly.yml (+2/−1) — an R1 finding FIXED in this change: the root manifest's header claimed "This file declares no entities of its own - it only tells charly where to look", which is false since the marketplace-app box and the check-marketplace bed moved here (the repo's own AGENTS.md says so). The sentence now names them.

No structural change was needed, and no shelf candy was added: this repo is already a charly project (discover: candy, charly#459) and its own candy/plugin-marketplace candy can own a skill: node.

How tested

Run on the committed tree 40b8e7e26125dad2d2fe4a7912f67d498d35429e. The WARNING: charly is a dev/worktree build … stderr line appears on every invocation of this worktree-local binary; it is binary provenance, not a validation warning, and the gate's own count is 0 warnings.

Arm 1 — the green one.

$ charly box validate
charly box validate: OK — checked 1 candy, 1 box, 1 deploy, 7 distros, 7 builders; 0 warnings, 0 errors
rc=0

Arm 2 — the NEGATIVE control: the gate that actually gates. The body removed:

$ mv .agents/skills/marketplace/SKILL.md /tmp/mkt2.bak && charly box validate
charly: error: command "validate": validation error: skills: skill "marketplace": no body — the node carries no in-line `content:` and no SKILL.md exists under .agents/skills at the repo root of the owning candy "plugin-marketplace"
rc=1

It names the NODE and its OWNING CANDY, so the green arm above cannot be vacuous: removing the prose reds the gate. (The body was restored immediately; git status --short is empty at the pushed head.)

Arm 3 — the corpus-generation probe. A routing/entity change's proof is the emitted artifact, not the parse. Minimal local root carrying exactly this candy + its body + the internals family registry, run through THIS plugin:

$ charly marketplace generate --root /tmp/six-add/gen-plugin-marketplace --out /tmp/six-add/gen-plugin-marketplace-out
rc=0
$ grep -n marketplace /tmp/six-add/gen-plugin-marketplace-out/DISPATCHER.md
4:| Marketplace / skill-corpus generation — … | `/charly-internals:marketplace` |
$ find … -name SKILL.md
…/internals/skills/marketplace/SKILL.md

The /charly-internals:marketplace row proves the family address survives end to end (entity → corpus).

The emitted body is the authored body plus one normalized EOF byte (5800 authored → 5801 emitted; identical for the first 5800 chars) — the convention violation filed as #44, deliberately not fixed in this commit so the body stays byte-identical to the carrier.

Round 1 RCA — three body claims contradicted by the diff, and one content finding

The validator BLOCKed this head. The change itself was found coherent (routing-only node, byte-identical body, genuine negative control); the blocks were in the body's claims plus one contradiction inside the moved prose. All four are dispositioned above and below; the RCA and the missed control:

  • Two per-file line counts were wrong (AGENTS.md (+7/−1) vs the real +6/−1; charly.yml (+3/−1) vs the real +2/−1). Mechanism: git show --stat prints the number of CHANGED lines per file — AGENTS.md | 7 ++- is 6 insertions + 1 deletion, charly.yml | 3 +- is 2 + 1 — and I transcribed that column as insertions. Missed control: the pre-push self-audit's parse, do not transcribe rule was applied to the sha256s and the pasted gate outputs but NOT to the per-file counts. Root fix: every count now comes from git show --numstat, pasted as the machine's own columns at the top of this body.
  • The moved body's internals ownership row contradicts the move. SKILL.md says internals → layer-charly-internals (+ layer-charly-internals-extra …), and this PR re-homes one internals skill here. The row has in fact been stale since the #139 drain (nine internals skills already live at sdk/spec/the umbrella), so its correction is ONE sweep across the whole family — not a per-PR edit. It is deferred to the marketplace skill's internals ownership row still names layer-charly-internals as the one owner #46, the named tracking issue that carries the full measured map and the replacement row. It is deferred rather than fixed here because this PR's acceptance test is that the body is byte-identical to the carrier's main: editing the row inside the ADD would break the invariant that proves the move transported prose rather than editing it, and the row can only be written correctly once the drain has landed.

Rulebook compliance

  • R0 — loaded before the first tool action: /charly-internals:skills, /charly-internals:git-workflow, /charly-internals:cutover-policy, /charly-build:validate, /charly-internals:marketplace, plus this repo's AGENTS.md (Part II fix: advance MARKETPLACE_REF to the marketplace's current main head #4).
  • R1 — two findings. The false "declares no entities of its own" header is FIXED here (this PR's own body would otherwise contradict the repo it lands in). The EOF-convention violation and the stale internals ownership row are NON-BLOCKING and separable (the projection is already correct; the row spans a family-wide sweep), so they are FILED as the marketplace skill body ends without a trailing newline, so its authored file differs from its own corpus projection by one byte #44 and the marketplace skill's internals ownership row still names layer-charly-internals as the one owner #46 with their RCAs.
  • R2 — one home for one behaviour, reached in two ordered steps: this PR ADDS the body in its owning repo, and the layer-charly-internals drain PR (which names this one) DELETES the carrier's copy once all six ADDs have merged. The copy that exists between the two PRs is the content-existence invariant doing its job — the prose must exist in SOME repository at every commit.
  • R3 — no workaround, no sleep, no bypass; git commit -F <file> was used because the pre-commit hook's shell parser rejects a heredoc (its own documented remedy).
  • R4 — the skill documents the generator's real surface; nothing was routed around.
  • R5 — no legacy skill BODY is deleted here (this PR only adds one); the legacy HOME is deleted by the carrier's drain PR. What this PR does delete, and says so, is the false "declares no entities of its own" header sentence.
  • R6 — git status read first; no force-push, no hook bypass, no direct push to main.
  • R7 — the changed path is proven by a gate that FAILS without the change (arm 2), and the emitted corpus artifact is validated at its own boundary (arm 3), including the byte-level round-trip.
  • R8 — no live service boundary is involved.
  • R9 — no Go source and no binary changed.
  • R10 — the change-class gate for a docs + routing-config change in a repo with no live bed is charly box validate + the negative arm + the generation probe: all three ran on the committed tree above.
  • HC — one cutover, one commit; the carrier drain is a separate repo's unit, sequenced after this merges.
  • Coordination — claimed on the build carrier's 15 skills are a plugin repo's, not charly's — and the internals map re-derives to 33 of 35 with 2 unroutable opencharly#611 before this push (slug charly-six-add).

Change classification

Docs + routing config (a skill: entity, its body, the rulebook's file list, and one corrected header comment). No Go, no schema, no image, no bed. The attribution tier is fully tested and validated because the change-class gate above passed on the final tree and the emitted artifact was produced from the changed source.

A3. This session's delivered system message reads, verbatim: You are a coding agent powered by the deepseek-v4.1-flash model. — harness DeepSeek Harness, model deepseek-v4.1-flash; cited with opencharly/opencharly#538, the open record of this runtime being real while a validator's model allowlist rejected it.

Filed issues

Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)

marketplace documented corpus generation, the refs list, the drift gate and the
refresh PRs, but its body lived only in the layer-charly-internals carrier, which
holds no code. The destination is measured (opencharly/opencharly#611): that
surface IS this plugin.

- .agents/skills/marketplace/SKILL.md — the body, copied byte-identically
  (sha256 7d4d26763498cd228a1ad8d5825c821b794aa34e4cda0ca542ad011a572aa94b) from
  the carrier at its main.
- marketplace-skill: — the routing-only skill: node in the candy's own charly.yml
  (name/family/owner/triggers, no inline description:/content:).
  owner: plugin-marketplace names a candy of THIS project; family: internals is
  unchanged, so /charly-internals:marketplace survives.
- AGENTS.md + charly.yml — the file list names the node and the body, and the root
  manifest's false "declares no entities of its own" header is corrected.

Gate: charly box validate rc=0 / 0 warnings; the negative control (body removed)
rc=1 naming the node and its owning candy; and a corpus-generation probe emitting
internals/skills/marketplace/SKILL.md + its DISPATCHER row.

One filed finding: the carrier's body has no trailing newline, so the copy is
byte-identical by instruction and its projection gains that one EOF byte.

Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)
@github-actions

Copy link
Copy Markdown

Review — BLOCK

I re-derived every claim in the body against the current diff and the commit list, and dispositioned the (empty) comment thread. The change itself is coherent — the skill: node is routing-only (no inline description:/content:), family: internals and owner: plugin-marketplace are plausible, the body file is byte-identical-with-no-trailing-newline as described, and the negative control (arm 2) is genuine evidence that the gate fails without the body. No security concerns (docs + routing config only; no secrets, no code, no schema). But the body's own "measured, re-measured" claims do not survive line-by-line verification.

Blocks

  • AGENTS.md — body line-count contradicts the diff. The body states AGENTS.md (+7/−1). The actual hunk is @@ -10,7 +10,12 @@ with 6 added lines and 1 removed line (+6/−1, net +5). The four-line new bullet plus the two-line modified bullet continuation total 6 additions, not 7. Fix: correct the body to +6/−1.

  • charly.yml (root) — body line-count contradicts the diff. The body states charly.yml (+3/−1). The actual hunk is @@ -7,7 +7,8 @@ with exactly 2 added comment lines and 1 removed line (+2/−1, net +1). Fix: correct the body to +2/−1.

    These two discrepancies matter specifically because the body's entire thesis is precision ("measured, never chosen", "re-measured after the commit", byte-identical sha256). An off-by-one in two of four stated counts is a direct, verifiable contradiction of the diff and undercuts that claim. (For the record, SKILL.md +103 and candy/plugin-marketplace/charly.yml +23 do match their headers, so only these two are wrong — but they are wrong.)

  • .agents/skills/marketplace/SKILL.md — content now contradicts the move it documents. The copied body's ownership table says internals → layer-charly-internals (+ layer-charly-internals-extra …). This PR places the internals-family marketplace skill in plugin-marketplace, so the sole authoritative copy (the carrier copy is to be drained per R2/R5) now tells a future editor to look in the wrong repo for this very skill. The body acknowledges the EOF-byte staleness (the marketplace skill body ends without a trailing newline, so its authored file differs from its own corpus projection by one byte #44) but not this ownership-table staleness. Fix: update the table to record the plugin-marketplace exception (and accept the resulting byte difference), or explicitly state in the body that the table correction is deferred to a named follow-up with a tracking reference — rather than leaving an unacknowledged contradiction.

Non-blocking observations

  • The comment thread is empty (0 comments), so there is no maintainer/operator sign-off to import and no comment claim to disposition; the change must stand on its own evidence, which it mostly does.
  • The arm 1/arm 2/arm 3 evidence is internally consistent and the negative control is the right kind of proof. The #44 EOF finding is correctly classified as separable.

Verdict: BLOCK


ollama-cloud/deepseek-v4.1-flash — action-review.

View action run

@aitrawog

Copy link
Copy Markdown
Contributor Author

RCA — round 1 BLOCK was in the PR body, not the diff.

Findings (all three dispositioned before this re-run): two per-file counts were wrong (AGENTS.md (+7/−1) vs the real +6/−1; charly.yml (+3/−1) vs the real +2/−1); and the moved body's internals ownership row contradicts the move — it names layer-charly-internals as the family's one owner while this PR re-homes one of its skills here.

Mechanism. git show --stat prints, per file, the number of CHANGED lines (AGENTS.md | 7 ++- = 6 insertions + 1 deletion; charly.yml | 3 +- = 2 + 1), and the body transcribed that column as the insertion count.

Missed control. The pre-push self-audit's parse, do not transcribe rule — quote a machine's field BY KEY, never retype a rendered column — was applied to the sha256s and to every pasted gate output, and NOT to the per-file counts. For the third finding the missed control is different and worth naming separately: I verified the body's BYTES (sha256 identical, EOF byte disclosed) but never read the moved prose for claims about the MOVE ITSELF. A byte-identical relocation can still land a false claim, because the claim is about where the skill lives, and only the destination PR changes that.

Root fix (applied). Every per-file count now comes from git show --numstat, pasted as the machine's own columns at the top of the body. The ownership row is NOT edited here — this PR's acceptance test is a byte-identical body, and the row is stale across the whole family (nine internals skills already live at sdk/spec/the umbrella, so it has been wrong since the #139 drain), which makes its correction ONE sweep. That sweep is filed as #46, carrying the full measured map, the replacement row and the reason it cannot be a per-PR edit; the body now names it where it discusses the row.

Blast radius. Body prose plus one deferred prose finding; the diff, the routing node, the byte-identical body, the negative arm and the generation probe are unchanged at this head.

Agent: charly-six-add

Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)

@github-actions

Copy link
Copy Markdown

Review — PASS

I re-derived every claim against the current diff and commit list, and dispositioned both comments.

Per-file counts (round-1 block) — resolved

The body now pastes git show --numstat columns, and all four match the diffs:

  • .agents/skills/marketplace/SKILL.md — hunk @@ -0,0 +1,103 @@ → 103/0 ✓
  • AGENTS.md — hunk @@ -10,7 +10,12 @@ with 6 added (2-line modified bullet + 4-line new bullet) and 1 removed → 6/1 ✓ (round 1 said +7/−1; now correct)
  • candy/plugin-marketplace/charly.yml — 23 added lines counted line-by-line, 0 removed → 23/0 ✓
  • charly.yml (root) — hunk @@ -7,7 +7,8 @@, 2 added comment lines, 1 removed → 2/1 ✓ (round 1 said +3/−1; now correct)

The two off-by-one contradictions that drove the round-1 BLOCK are gone.

Ownership-row contradiction (round-1 block) — dispositioned as permitted

The moved body's table still says internals → layer-charly-internals (+ layer-charly-internals-extra …), while this PR re-homes the internals-family marketplace skill into plugin-marketplace. The round-1 reviewer's stated remedy was either to correct the table (accepting a byte difference) or to explicitly defer the correction to a named follow-up with a tracking reference. The body now does the latter: it names #46, explains the row has been stale across the whole family since the #139 drain (nine internals skills already live elsewhere), and justifies why a byte-identical relocation cannot edit it in-place. This satisfies the offered remedy, and the residual defect is disclosed rather than silently carried.

Correctness of the change

  • The node marketplace-skill: carries only name/family/owner/triggers — no inline description:/content:, matching the claim and the generator's hard-error rule.
  • owner: plugin-marketplace names the candy this repo declares (plugin-marketplace:), and family: internals is preserved, so /charly-internals:marketplace survives the move.
  • The body file at .agents/skills/marketplace/SKILL.md has no trailing newline, consistent with the disclosed the marketplace skill body ends without a trailing newline, so its authored file differs from its own corpus projection by one byte #44 EOF finding and the byte-identity invariant.
  • The root charly.yml header correction ("declares no entities of its own" → names the marketplace-app box + check-marketplace bed) is accurate per AGENTS.md and is a comment-only edit.
  • The AGENTS.md bullet accurately describes the node and the repo-root body placement.

Evidence / tests

Arm 1 (box validate green), arm 2 (negative control: removing the body reds the gate, naming the node and owning candy), and arm 3 (generation probe emitting the /charly-internals:marketplace row and the projected body) are internally consistent and are the right class of proof for a docs + routing-config change. No Go/schema/image changed; no security surface (no secrets, no input handling).

Comments

Residual (non-blocking)

The stale ownership row remains in the shipped prose until #46 lands; this is explicitly disclosed and tracked, and the temporary carrier copy is sequenced for deletion by the drain PR (R2). Neither warrants a block.

Verdict: PASS


ollama-cloud/deepseek-v4.1-flash — action-review.

View action run

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.

2 participants