Skip to content

feat(f4): marketplace.json + release.yml + bump 0.1.0 (cierre Fase F)#28

Merged
javiAI merged 4 commits into
mainfrom
feat/f4-marketplace-public-repo
Apr 27, 2026
Merged

feat(f4): marketplace.json + release.yml + bump 0.1.0 (cierre Fase F)#28
javiAI merged 4 commits into
mainfrom
feat/f4-marketplace-public-repo

Conversation

@javiAI
Copy link
Copy Markdown
Owner

@javiAI javiAI commented Apr 27, 2026

Summary

Última rama de Fase F. Aterriza la infra local del marketplace + release flow del plugin pos. Cierra Fase F con el plugin distribuible: manifest oficial, workflow de release reproducible, runbook ejecutable, bump al primer release público (0.1.0). Repo público javiAI/pos-marketplace deliberadamente diferido — F4 deja la infra lista; la creación manual del repo público es decisión separada.

  • .claude-plugin/marketplace.json (NEW): schema oficial {name, owner, plugins, metadata} + plugins[0].source.{source: "github", repo: "javiAI/project-operating-system", ref: "v0.1.0"}. Single source of cómo /plugin install pos resolverá el repo + ref.
  • .claude-plugin/plugin.json: bump 0.0.1 → 0.1.0 (pre-1.0, primer release público). version es source of truth: tag git = v\${version} y marketplace.json.source.ref lo espejan.
  • .github/workflows/release.yml (NEW): trigger push.tags ['v*']. 5 jobs encadenados:
    • version-match → asserta plugin.json.version == \${tag#v} (primer gate).
    • selftest → reusa contrato F3 (pytest bin/tests -q) sobre el ref del tag.
    • build-bundle → empaqueta pos-v\${version}.tar.gz plugin-only curated.
    • publish-releaseneeds: [version-match, selftest, build-bundle] + gh release create --generate-notes.
    • mirror-marketplace → condicional if: vars.POS_MARKETPLACE_REPO != '' (skippea silenciosamente si la variable está vacía; no falla el release).
    • Actions pinneadas por SHA (regla ci-cd.md#2).
  • docs/RELEASE.md (NEW): runbook de versionado + bundle + flujo en 5 pasos + recovery + activación del mirror cuando exista repo público.
  • Tests RED-first (3 archivos nuevos, 21 tests):
    • bin/tests/test_marketplace_json_schema.py (12 tests).
    • bin/tests/test_release_workflow_smoke.py (6 tests).
    • bin/tests/test_plugin_json_version_bump.py (3 tests, EXPECTED_VERSION = "0.1.0" pin literal).

Decisiones cerradas en Fase -1 (8 ajustes ratificados):

  • A1.b Repo público diferido: F4 entrega solo infra local. Mirror gated por vars.POS_MARKETPLACE_REPO.
  • A2 marketplace.json schema oficial Claude Code: top-level {name, owner, plugins}; owner.name requerido.
  • A3 Versionado: bump 0.0.1 → 0.1.0 (no 1.0.0; pre-1.0 explícito). plugin.json.version source of truth.
  • A4 Bundle curated plugin-only (8 paths); excluye generator/, templates/, questionnaire/, tools/, bin/tests/, .github/.
  • A5 5 jobs en orden estricto. Test asserta publish-release.needs ⊇ {version-match, selftest, build-bundle}.
  • A6 Diferidos NO en F4: audit.yml nightly, /pos:pr-description + /pos:release skills, CHANGELOG.md enforced, refactor/template-policy-d5b-migration, Fase G.
  • A7 Tests RED-first: 21 tests en 3 archivos.
  • A8 Docs scope estricto. NO tocar: policy.yaml, hooks/**, .claude/skills/**, agents/**, generator/**, templates/**, .claude/rules/skills-map.md.

Ajuste durante GREEN (gotcha persistente): PyYAML 1.1 parsea on: (clave canónica de triggers) como Python bool True. El test acepta ambos (data.get("on") or data.get(True)) — patrón aplicable a cualquier test futuro de workflow YAML.

Suite global: 665 passed + 1 skipped (vs baseline F3 644 + 1 skip = +21 nuevos tests F4). Sin regresión D1..D6 / E1a..E3b / F1..F3.

Carry-overs post-F4 (cierre Fase F):

Test plan

  • pytest bin/tests -q local — 21 nuevos F4 verdes (12 marketplace + 6 release workflow + 3 plugin version pin).
  • Suite full local — 665 passed + 1 skipped (skip D5 intencional F3).
  • Sin regresión D1..D6 / E1a..E3b / F1..F3.
  • Docs-sync dentro del PR: ROADMAP.md (F4 ✅ + § Progreso), HANDOFF.md (§1 + §9 + §22 nuevo), MASTER_PLAN.md § Rama F4 expandida, .claude/rules/ci-cd.md (release.yml Aterrizado + H3 nuevo), docs/ARCHITECTURE.md § 13 reescrita, docs/RELEASE.md (NEW).
  • pre-pr-gate.py requeridos ROADMAP.md + HANDOFF.md satisfechos.
  • CI verde tras push.

🤖 Generated with Claude Code

Javier and others added 3 commits April 27, 2026 09:39
Fase 0 (kickoff) + Fase 1 (RED tests) for feat/f4-marketplace-public-repo.

Scope (per Fase -1 ratificada con 8 ajustes del usuario):
- Aterrizar infra local del marketplace + release flow sin depender de
  que javiAI/pos-marketplace exista todavía (A1.b).
- .claude-plugin/marketplace.json con schema oficial Claude Code:
  top-level {name, owner, plugins}; owner.name; plugin {name, source}
  con source.{source=github, repo, ref="v"+version}.
- .github/workflows/release.yml trigger tag:v*, jobs version-match /
  selftest / build-bundle / publish-release / mirror-marketplace
  (mirror condicional/skippable hasta repo público).
- Bump plugin.json.version 0.0.1 → 0.1.0 (primer release público).

Archivos en este commit (RED tests, expected failures):
- bin/tests/test_marketplace_json_schema.py (12 tests)
- bin/tests/test_release_workflow_smoke.py (6 tests)
- bin/tests/test_plugin_json_version_bump.py (3 tests)

Tests verifican:
- marketplace.json schema oficial mínimo (top-level + owner + plugin)
- plugin name/version/ref sync entre marketplace ↔ plugin.json
- release.yml trigger v*, jobs esperados, publish-release.needs ⊇
  {version-match, selftest, build-bundle}, mirror-marketplace
  conditional/skippable
- plugin.json.version pin = "0.1.0"

Estado RED actual: 19 failed + 12 passed (12 = F3 baseline 9 + 3
plugin.json existe/parses). Sin regresión en F3.

Diferidos en F4 (regla #7 CLAUDE.md):
- audit.yml nightly (sin consumer hoy; rama propia post-F4).
- /pos:pr-description, /pos:release skills (sin repetición demostrada).
- CHANGELOG.md enforced (auto-generated from git log entre tags).
- refactor/template-policy-d5b-migration (drift independiente).
- Fase G (Knowledge Plane).

GREEN impl + docs (RELEASE.md/ARCHITECTURE/ci-cd/MASTER_PLAN/ROADMAP/
HANDOFF) entran en commits siguientes dentro de esta rama.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fase 2 (GREEN) — flippea los 19 RED del commit previo.

.claude-plugin/marketplace.json (NEW):
- Schema oficial Claude Code marketplace.
- top-level: name="pos-marketplace", owner.name="javiAI", plugins[].
- plugins[0]: name=pos, source={source:github, repo:javiAI/
  project-operating-system, ref:v0.1.0}, version=0.1.0.
- metadata.{description, version} para humans.

.claude-plugin/plugin.json:
- version 0.0.1 → 0.1.0 (primer release público; pre-1.0).
- Single source of truth; tag git debe ser v${version}.

.github/workflows/release.yml (NEW):
- Trigger: push tags v*.
- Jobs:
  - version-match: assert plugin.json.version == ${tag#v}.
  - selftest: pytest bin/tests -q (reusa contrato F3).
  - build-bundle: tar.gz curated plugin-only (.claude-plugin/,
    .claude/skills/, .claude/rules/, hooks/, agents/, policy.yaml,
    bin/pos-selftest.sh, bin/_selftest.py, docs/RELEASE.md). Excluye
    generator/, tools/, templates/, questionnaire/.
  - publish-release: needs [version-match, selftest, build-bundle];
    gh release create con bundle como asset.
  - mirror-marketplace: condicional vía vars.POS_MARKETPLACE_REPO;
    si vacío skippea sin fallar release. Abre PR contra repo público
    cuando esté configurado.
- Actions pinneadas por SHA (ci-cd.md regla #2).
- permissions.contents=write para gh release create.

Tests post-GREEN: 21 passed (12 marketplace + 6 release.yml + 3 plugin
version), suite total 644 passed + 1 skipped (skip D5 intencional F3).
Sin regresión.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…/MASTER_PLAN

Fase N+3 — docs-sync dentro de la rama (CLAUDE.md regla #2,
docs.md § Docs-sync en cada rama).

docs/RELEASE.md (NEW):
- Runbook user-facing de versionado + bundle + flujo + recovery.
- Contrato de versionado: plugin.json.version source of truth;
  tag = v${version}; marketplace.json.source.ref espeja.
- Bundle scope plugin-only curated (incluye/excluye explícitos).
- Flujo en 5 pasos: bump → tag → workflow → verify → recovery.
- Activación del mirror cuando exista repo público (3 pasos:
  crear repo + gh variable set POS_MARKETPLACE_REPO + gh secret
  set POS_MARKETPLACE_TOKEN).
- Instalación user-facing (/plugin marketplace add + /plugin
  install pos).
- Diferidos enumerados.

docs/ARCHITECTURE.md § 13 (Marketplace + Release flow):
- Reescrita de placeholder de 6 líneas a sub-sección completa.
- Manifest, source of truth de versión, jobs del workflow,
  bundle scope curated, deferral del repo público,
  determinismo del flujo, instalación user-facing, deferrals.

.claude/rules/ci-cd.md:
- Bullet release.yml promovido de "Diferidos" a "Aterrizado"
  (entregado en F4).
- Nuevo H3 "### Job release (entregado en F4)" con scope
  completo (5 jobs + bundle curated + source of truth).

ROADMAP.md:
- Tabla: F4 marcada ✅ (PR pendiente).
- Nueva sección § feat/f4-marketplace-public-repo en Progreso
  Fase F: scope, entregables, decisiones Fase -1 (A1.b..A8),
  contrato fijado, carry-overs, criterio de salida (665 passed
  + 1 skipped).

HANDOFF.md:
- §1 Snapshot: rama actual F4 (entrega + suite update).
- §9 Próxima rama: Fase F cerrada; carry-overs (template-policy
  d5b migration, marketplace activación, skills diferidas,
  audit.yml).
- §22 nuevo: Estado F4 con entregables + contrato + decisiones
  + carry-overs (paralelo a §19 F1, §20 F2, §21 F3).

MASTER_PLAN.md § Rama F4:
- Expandida de 3 líneas a sección completa: scope realizado,
  archivos entregados con detalle por path, decisiones Fase -1
  (A1.b..A8), contexto leído, criterio de salida, carry-overs.

Simplify pre-commit:
- Recortados 3 bullets de "Ajustes durante implementación"
  (heredoc syntax glitch + rtk wrapper output filter) —
  debug ephemera, pertenecen a commit history.
- Mantenido el único gotcha persistente: PyYAML 1.1 parsea
  `on:` como Python bool True (patrón reutilizable para tests
  futuros de workflow YAML).

Sin tocar (per A8 ratificado en Fase -1): policy.yaml, hooks/**,
.claude/skills/**, agents/**, generator/**, templates/**,
.claude/rules/skills-map.md.

Tests: sin cambios (GREEN ya verde con 665 passed + 1 skipped).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 27, 2026 17:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the local marketplace manifest + automated GitHub release workflow needed to publish the pos plugin as a reproducible bundle (v0.1.0), along with a runbook and contract tests to lock down the workflow/manifest shape.

Changes:

  • Introduces .claude-plugin/marketplace.json and bumps .claude-plugin/plugin.json to 0.1.0 (tag/ref coupling).
  • Adds .github/workflows/release.yml to build/upload the curated plugin bundle, create a GitHub Release, and optionally mirror marketplace.json into a separate public marketplace repo.
  • Adds docs (docs/RELEASE.md) + contract tests for marketplace/release workflow shape and updates roadmap/handoff/architecture/CI-CD rule docs accordingly.

Reviewed changes

Copilot reviewed 9 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
docs/RELEASE.md New release runbook covering versioning, bundle scope, workflow jobs, and recovery/mirroring steps.
docs/ARCHITECTURE.md Expands architecture docs for marketplace + release flow and its determinism guarantees.
bin/tests/test_release_workflow_smoke.py Adds workflow contract tests (trigger, required jobs, needs, conditional mirror).
bin/tests/test_plugin_json_version_bump.py Pins plugin.json.version to 0.1.0 as a milestone contract.
bin/tests/test_marketplace_json_schema.py Adds schema/consistency checks for marketplace.json vs plugin.json.
ROADMAP.md Marks F4 as delivered and documents the scope/decisions.
MASTER_PLAN.md Updates F4 plan section to reflect delivered artifacts and constraints.
HANDOFF.md Updates current snapshot and next steps after F4.
.github/workflows/release.yml New tag-triggered release workflow building curated bundle + publishing release + optional marketplace mirroring.
.claude/rules/ci-cd.md Documents the new release workflow as delivered and its job responsibilities.
.claude-plugin/plugin.json Bumps plugin version to 0.1.0.
.claude-plugin/marketplace.json New local marketplace manifest pointing to javiAI/project-operating-system at v0.1.0.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +64 to +67
build-bundle:
name: build-bundle (curated plugin-only)
runs-on: ubuntu-latest
outputs:
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build-bundle is also meant to be behind the version-match gate, but it currently has no needs and will run even when the tag/version mismatch. Add needs: [version-match] (or otherwise enforce the ordering) so the bundle build is skipped when version-match fails and the job graph matches the documented "orden estricto".

Copilot uses AI. Check for mistakes.
dst['plugins'] = plugins
dst_path.write_text(json.dumps(dst, indent=2) + '\n')
PY
git add marketplace.json
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mirror-marketplace will fail on workflow re-runs (or any no-op update) because git commit -m ... exits non-zero when there are no changes. Make the job idempotent by checking for a clean working tree before committing (and exiting 0 if nothing changed) or by handling the empty-commit case explicitly.

Suggested change
git add marketplace.json
git add marketplace.json
if git diff --cached --quiet --exit-code; then
echo "No marketplace changes detected; skip mirror"
exit 0
fi

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/release.yml Outdated
Comment on lines +173 to +177
gh pr create \
--repo "$MARKETPLACE_REPO" \
--title "bump pos to ${tag}" \
--body "Automated bump of pos plugin to ${tag}." \
--head "$branch"
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After pushing the branch, gh pr create will exit non-zero if a PR for the same branch already exists (common when re-running the workflow for a tag). Consider making this step idempotent (e.g., detect an existing open PR for bump/pos-${version} and skip, or use gh pr view/gh pr list before creating).

Suggested change
gh pr create \
--repo "$MARKETPLACE_REPO" \
--title "bump pos to ${tag}" \
--body "Automated bump of pos plugin to ${tag}." \
--head "$branch"
existing_pr="$(gh pr list \
--repo "$MARKETPLACE_REPO" \
--head "$branch" \
--state open \
--json number \
--jq '.[0].number')"
if [ -n "$existing_pr" ]; then
echo "Open PR #$existing_pr already exists for branch $branch; skipping creation."
else
gh pr create \
--repo "$MARKETPLACE_REPO" \
--title "bump pos to ${tag}" \
--body "Automated bump of pos plugin to ${tag}." \
--head "$branch"
fi

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +38
selftest:
name: selftest (ubuntu, py 3.11)
runs-on: ubuntu-latest
steps:
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selftest is described as being gated by version-match ("primer gate; sin esto el resto no corre"), but the workflow currently runs selftest in parallel with version-match (no needs). This can waste CI time on mismatched tags and contradicts the documented job ordering; add needs: [version-match] to selftest to make version-match a true gate.

Copilot uses AI. Check for mistakes.
…(PR #28 review)

Aplica las 4 findings de Copilot review de PR #28. Las 4 son real
correctness/idempotency bugs, no estilo. Triage value/effort: todas
high/trivial-low → FIX.

Gating de version-match (findings 1 + 4):
- selftest: needs [version-match].
- build-bundle: needs [version-match].

Antes corrían en paralelo con version-match → CI gastaba tiempo en
tags mismatched y contradecía el "orden estricto" documentado.
Ahora: version-match → (selftest + build-bundle) → publish-release
→ mirror-marketplace.

Idempotencia mirror-marketplace (findings 2 + 3):
- Tras `git add marketplace.json`, si `git diff --cached --quiet`
  no hay cambios → exit 0. Antes `git commit` no-op fallaba la
  re-run del workflow.
- Antes de `gh pr create`, `gh pr list --head $branch --state open`.
  Si ya existe un PR abierto → skip create con mensaje. Antes
  `gh pr create` con PR existente fallaba la re-run.

Tests: bin/tests 31/31 verde; full explicit run 850 passed + 1
skipped (skip D5 intencional F3). Sin regresión.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@javiAI
Copy link
Copy Markdown
Owner Author

javiAI commented Apr 27, 2026

Fix push: applied all 4 Copilot findings (commit 0bc8392).

  • Gating findings (release.yml:38, :67): added needs: [version-match] to selftest and build-bundle. Before they ran in parallel with the gate; now version-match → (selftest + build-bundle) → publish-release → mirror-marketplace strictly.
  • Idempotency findings (release.yml:169, :173): mirror-marketplace now (a) checks git diff --cached --quiet after git add and exits 0 if no changes, and (b) checks gh pr list --head \$branch --state open before gh pr create and skips with a log line if a PR already exists. Workflow re-runs no longer fail on no-op commits or pre-existing PRs.

Tests: bin/tests 31/31 green; full explicit run 850 passed + 1 skipped (intentional F3 D5 skip). No regression.

@javiAI javiAI merged commit d5afa8b into main Apr 27, 2026
7 checks passed
@javiAI javiAI deleted the feat/f4-marketplace-public-repo branch April 27, 2026 17:39
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