From 09505a0f78fc00219578656e3e59b151ef93fe95 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Sat, 14 Nov 2026 13:19:00 +0900 Subject: [PATCH] docs(spec-loop): sync specs with contributed functionality Back-fills the specs for what landed since bfc99bb6 without a spec change: #2005, #2040, #2055, #2056, #2057, #2063, #2068, #2069, #2070 and #2071, and moves .last-sync to 4d491b09. Generated-by: Claude Opus 5 --- tools/spec-loop/.last-sync | 2 +- .../specs/marketplace-distribution.md | 11 +++++++- .../specs/meta-and-quality-tooling.md | 3 ++ .../spec-loop/specs/organization-adapters.md | 19 +++++++++++++ tools/spec-loop/specs/pr-management-family.md | 28 +++++++++++++++++-- .../specs/security-issue-lifecycle.md | 13 +++++++++ 6 files changed, 72 insertions(+), 4 deletions(-) diff --git a/tools/spec-loop/.last-sync b/tools/spec-loop/.last-sync index b6a848934..b987a3f36 100644 --- a/tools/spec-loop/.last-sync +++ b/tools/spec-loop/.last-sync @@ -1 +1 @@ -bfc99bb6f47be727b124adf939e5c010fe33ba5f +4d491b09b31b0d692d3fe91cf11d0b16c7f4720d diff --git a/tools/spec-loop/specs/marketplace-distribution.md b/tools/spec-loop/specs/marketplace-distribution.md index 12b41d148..ee77130ac 100644 --- a/tools/spec-loop/specs/marketplace-distribution.md +++ b/tools/spec-loop/specs/marketplace-distribution.md @@ -134,7 +134,11 @@ which Claude Code would load twice. `tools/dev/check-family-plugins.py` is both the generator (`--fix`) and the CI gate — the prek hook runs it in `--fix` mode, so the gate corrects drift -rather than only reporting it. `docs/setup/marketplace.md` is the +rather than only reporting it. +It also copies `assets/plugin-icon.png` to `.claude-plugin/icon.png` in every +plugin and fails when a copy is missing or differs, because +`claude plugin validate --strict` reports a plugin without an icon (#2069). +`docs/setup/marketplace.md` is the adopter-facing page. ## Behaviour & contract @@ -208,6 +212,11 @@ adopter-facing page. once per plugin version and points the `current` symlink at it; that is `` on a marketplace install, writable so `uv run --project` works, and the hook only ever replaces a symlink at `current`. + The plugin also ships `organizations/*/organization.md`, which the hook + copies into that tree, and `release_config` looks for organization manifests + under `~/.cache/apache-magpie/framework/current` too, so a project + inheriting a key from its organization does not fall back to the framework + default on a marketplace install (#2068). `magpie-agent-guard` is the exception to the symlink (#1516): it carries a byte-identical copy of `tools/agent-guard/src/agent_guard` as real files, because a marketplace client may drop a link whose target leaves diff --git a/tools/spec-loop/specs/meta-and-quality-tooling.md b/tools/spec-loop/specs/meta-and-quality-tooling.md index ef6e7da03..4787ab8f3 100644 --- a/tools/spec-loop/specs/meta-and-quality-tooling.md +++ b/tools/spec-loop/specs/meta-and-quality-tooling.md @@ -268,6 +268,9 @@ trustworthy as it grows. test` on every plugin whose `hooks/hooks.json` declares `modules`, with Claude Code pinned in the hook environment, because Claude Code silently skips a hooks module that fails its static analysis. + That validation type-checks the hooks module, so the mods import their + siblings as `./.js` and fix strict-null findings with guards rather + than suppressions (#2070). Its `check-claude-mods-local` twin runs on ordinary commits with the contributor's own Claude Code and skips when it is absent or older than the pin; CI skips the twin. diff --git a/tools/spec-loop/specs/organization-adapters.md b/tools/spec-loop/specs/organization-adapters.md index 566375e39..c45f531c8 100644 --- a/tools/spec-loop/specs/organization-adapters.md +++ b/tools/spec-loop/specs/organization-adapters.md @@ -54,6 +54,9 @@ identical "ASF default" values in its own `project.md`. GitHub Releases, no list/forwarder/metadata backends); inherited by `projects/non-asf-example/`. - `organizations/_template/` — authoring skeleton. +- `tools/dev/check-skill-source-drift.py` and + `.github/workflows/skill-source-drift.yml` — the weekly check of every + curated `organizations/*/skill-sources.md` against its source (#2040). - Resolution contract: `AGENTS.md` §"Configuration resolution order". - The project-manifest template that names the organization, `plugins/magpie-setup/templates/project.md` (`projects/_template/` links to @@ -107,6 +110,22 @@ identical "ASF default" values in its own `project.md`. [security@apache.org]`, the organization-wide CVE bookkeeping sender. A project list replaces, never merges with, an organization list, so a project override repeats the inherited entries. +- **Curated skill sources are checked against their source weekly (#2040).** + An organization's `skill-sources.md` pins each source to a tag and may + carry a catalogue between `BEGIN` / `END SKILL-SOURCE CATALOGUE` markers + listing every skill the source ships, its install status (`pinned`, + `untagged`, `single-file`, `draft`) and the agent marketplaces that list + it. + The ASF adapter catalogues every skill under `apache/incubator`'s + `tools/skills/`, and since the Incubator tags each skill on its own, each + pinned skill is its own descriptor pinned to its own `-` tag. + `tools/dev/check-skill-source-drift.py` reads each GitHub source through + the REST API and reports added, removed or re-laid-out skills, a pin + whose tag no longer resolves to the recorded commit, a newer or first tag, + and a marketplace column that disagrees with the source's catalogs; it is + read-only and exits `0` in sync, `1` on drift and `2` when it could not run. + The weekly `skill-source-drift` workflow runs it and keeps one issue open + while there is drift, closing it once a run finds everything in sync. - An organization declares only org-wide values. Per-project values (security-list address, scope labels, product name, roster, tracker label/body-field vocabulary) stay in `project.md`. diff --git a/tools/spec-loop/specs/pr-management-family.md b/tools/spec-loop/specs/pr-management-family.md index c0ab6d40d..d6c2fc1ef 100644 --- a/tools/spec-loop/specs/pr-management-family.md +++ b/tools/spec-loop/specs/pr-management-family.md @@ -83,6 +83,9 @@ same directory; the behaviour is unchanged. It also ships agent-guard guards under `guards/` (`mark_ready.py`, `mention.py`) and the opt-in shadow pre-filter `scripts/typed_decision_prefilter.py` with its tests under `tests/`. + The skill runs its bundled scripts (`pr_link.py` and the pre-filter) as + `/scripts/…`, because `` on a marketplace install + holds no `skills/` directory (#2063). - Skill: `pr-management-stats` — read-only dashboard of the open PR backlog, grouped by area label, age bucket, and triage state. No tracker state is mutated. Ships `mode: Triage` + `capability: capability:stats` @@ -101,6 +104,16 @@ same directory; the behaviour is unchanged. Selection, scans, the slop threshold, disposition, inline anchoring and the review payload run as code in `pr_management.code_review`; the agent judges H1/H5/S2, writes the findings and assigns severity. + The `pr:` selector names one PR or several (#2055): `pr:N,M`, inclusive + ranges `pr:N-M`, optional `#` prefixes and repeated `pr:` tokens, with + duplicates dropped and at most 50 PRs; the queue keeps the order the + maintainer named, and a named PR missing from the open-PR sweep is listed + under `not_open`. + The selector output keeps `pr_number` (set when exactly one PR is named) + beside `pr_numbers`. + `code-review session record --outcome` accepts `FIXUP` beside the three + review events and the `skipped` / `slop-comment` / `slop-close` / + `dry-run` outcomes, and the session summary counts it as a review (#2056). An inline comment carries the finding as the review body does (its `quoted_rule` and `suggestion`), minus the excerpt it is anchored on, and a folded finding falls back to its suggestion before its rule, never the @@ -401,8 +414,19 @@ same directory; the behaviour is unchanged. disposition --findings ` Bash call hydrates the mod's interactive pane above the prompt, and the zero-token `/magpie-findings` command (`status`, `all`, `none`, `keep`, `drop`, `edit`) tracks per-finding actions. - Neither changes what is posted: only the answer typed at the picker reaches - `render`. + Once the maintainer curates, the mod writes the findings to + `.curated.json` (an envelope carrying the PR number and the source + file's SHA-256) and the keep answer to `.curated.keep` beside the + findings file; the first `disposition` run writes neither, and a write + failure, empty findings or a PR mismatch writes an invalidation marker + instead, since the mod API cannot delete files (#2005). + It refuses to write through a symlink or a non-regular file. + `render` uses `.curated.json` only when its PR and source hash + match, else the original findings; a curated envelope passed directly + must pass every check or the run stops. + An answer typed at the picker still wins; an empty answer is passed as + `--keep curated`, which uses `.curated.keep` only when the curated + findings were used, and `A` otherwise. Runtimes without mods keep the text picker alone, and Codex reads the clean `hooks/codex-hooks.json` instead (#1992). - **Third-party licence scan reads only real copyright notices.** diff --git a/tools/spec-loop/specs/security-issue-lifecycle.md b/tools/spec-loop/specs/security-issue-lifecycle.md index fba2d73e8..bdcc93116 100644 --- a/tools/spec-loop/specs/security-issue-lifecycle.md +++ b/tools/spec-loop/specs/security-issue-lifecycle.md @@ -438,6 +438,19 @@ publication, with a human gate and an audit-log entry at every step. `MAGPIE_ALLOW_EMBARGO_TERMS=1` is the maintainer's escape hatch after disclosure, and the block message does not tell the agent how to bypass it. + It fails closed (#2071): a throw while evaluating a command blocks it + unless that escape hatch is set, and a blocked evaluation with no reason + still blocks, under a fallback reason. + When a blocked `gh api` write has a vetted route, the reason names the + exact operation (#2057): a POST to an advisory's comments endpoint maps to + `advisory-comment`, a PATCH to `issues/comments/` to `comment-update` + and a POST to `issues//comments` to `issue-comment`. + The reason adds that the calling skill needs the operation in its + `[callers]` list in the adopter's vetted-ops config, which is a + maintainer's change. + Advisory record field edits and advisory comment edits have no vetted + operation, and the reason points at the advisory web UI. + The block decision itself is unchanged. - **Adversarial review before a PR, on public content only.** `security-issue-fix`, `security-issue-import-from-pr` (over the patch it verifies) and `security-issue-import-from-scan` carry the shared