diff --git a/plugins/gitea/.apm/skills/gitea-files/references/sources.md b/plugins/gitea/.apm/skills/gitea-files/references/sources.md index 756778d..9c94072 100644 --- a/plugins/gitea/.apm/skills/gitea-files/references/sources.md +++ b/plugins/gitea/.apm/skills/gitea-files/references/sources.md @@ -2,13 +2,13 @@ ## gitea-mcp-repo -**Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags. +**Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags. Tool parameters and SHA/concurrency behavior were cross-checked live against the deployed MCP tool schemas via `ToolSearch`, per this repo's process for resolving schema-vs-docs drift, rather than copied from the derived research doc. **Source:** https://gitea.com/gitea/gitea-mcp - **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md -**Contributing files:** (tool parameters and SHA/concurrency behavior cross-checked live against the deployed MCP tool schemas via ToolSearch) +**Contributing files:** - SKILL.md (Gotchas — cross-flow parameter and encoding traps; Dispatch) - references/reading.md (read-tool parameters, `ref`/`tree_sha` selection, tree pagination) - references/writing.md (write-tool parameters, SHA/concurrency behavior, canonical call sequences, failed-write triage) @@ -45,4 +45,4 @@ - **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md -**Contributing files:** (none) +- **Contributing files:** (none) diff --git a/plugins/gitea/skills/gitea-files/references/sources.md b/plugins/gitea/skills/gitea-files/references/sources.md index 756778d..9c94072 100644 --- a/plugins/gitea/skills/gitea-files/references/sources.md +++ b/plugins/gitea/skills/gitea-files/references/sources.md @@ -2,13 +2,13 @@ ## gitea-mcp-repo -**Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags. +**Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags. Tool parameters and SHA/concurrency behavior were cross-checked live against the deployed MCP tool schemas via `ToolSearch`, per this repo's process for resolving schema-vs-docs drift, rather than copied from the derived research doc. **Source:** https://gitea.com/gitea/gitea-mcp - **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md -**Contributing files:** (tool parameters and SHA/concurrency behavior cross-checked live against the deployed MCP tool schemas via ToolSearch) +**Contributing files:** - SKILL.md (Gotchas — cross-flow parameter and encoding traps; Dispatch) - references/reading.md (read-tool parameters, `ref`/`tree_sha` selection, tree pagination) - references/writing.md (write-tool parameters, SHA/concurrency behavior, canonical call sequences, failed-write triage) @@ -45,4 +45,4 @@ - **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md -**Contributing files:** (none) +- **Contributing files:** (none) diff --git a/plugins/kyberforge/.apm/skills/agent-audit/scripts/validate-provenance.sh b/plugins/kyberforge/.apm/skills/agent-audit/scripts/validate-provenance.sh index a5525d1..4b07ae3 100755 --- a/plugins/kyberforge/.apm/skills/agent-audit/scripts/validate-provenance.sh +++ b/plugins/kyberforge/.apm/skills/agent-audit/scripts/validate-provenance.sh @@ -22,7 +22,10 @@ Checks performed: 0 source_keys present in agent pair but sources.md absent 1 FILL IN: placeholders in sources.md 2 source_keys in agent files → slug exists in sources.md - 3 Contributing files listed in sources.md exist on disk (plugin-root relative) + 3 Contributing files listed in sources.md exist on disk (plugin-root + relative). An explicit '(none)' skips silently; a Contributing files block + this parser cannot read is reported as an INFO saying checks 3 and 4 did + not run, never skipped silently. 4 Contributing files back-reference the parent slug in their source_keys 5 Research doc field present and not placeholder EOF @@ -244,14 +247,31 @@ has_fail = False def emit_fail(desc, fpath, why, fix): global has_fail has_fail = True - findings.append(("FAIL", desc, fpath, why, fix)) + findings.append(("FAIL", desc, fpath, why, fix, None)) + +# INFO does not set has_fail and does not change the exit code. It is for a +# check that could not RUN — an unverified entry, not a broken one — and it +# exists so that "did not run" is never spelled the same way as "passed". +def emit_info(desc, fpath, note): + findings.append(("INFO", desc, fpath, None, None, note)) def print_findings(): - for kind, desc, fpath, why, fix in findings: - print(f"FAIL {desc} — {fpath}") - print(f" Why: {why}") - print(f" Fix: {fix}") - print() + for entry in findings: + kind = entry[0] + desc = entry[1] + fpath = entry[2] + why = entry[3] + fix = entry[4] + note = entry[5] + if kind == "FAIL": + print(f"FAIL {desc} — {fpath}") + print(f" Why: {why}") + print(f" Fix: {fix}") + print() + else: + print(f"INFO {desc} — {fpath}") + print(f" Note: {note}") + print() # --- Collect source_keys from agent pair --- def get_source_keys_from_file(fpath): @@ -321,9 +341,24 @@ for fpath, keys in [(agent_file, given_keys)]: # --- Checks 3, 4, 5: Per-slug checks in sources.md --- for slug in parse_h2_slugs(sources_content): - # Check 3: Contributing files exist (paths relative to plugin root) + # Checks 3 and 4: Contributing files exist (paths relative to plugin root), + # and back-reference the slug. `[]` and None are NOT the same answer here. + # `[]` is the author writing "(none)" — there is nothing to check and the + # skip is correct. None is a Contributing-files block this parser cannot + # read, and skipping THAT silently disables both checks on the one entry + # least likely to be right, which is the failure mode + # parse_contributing_files' own docstring warns about. Say so out loud. cf_files = parse_contributing_files(sources_content, slug) - if cf_files: + if cf_files is None: + emit_info( + f"Contributing-file checks skipped for '{slug}' — the Contributing files block could not be parsed", + f"sources.md (## {slug})", + f"The '## {slug}' entry has no Contributing files list this parser can read — a missing field, a bare heading, '*' bullets, a numbered list, or prose all read as unparsable rather than as an empty declaration. " + f"Checks 3 and 4 did not run for this slug, so nothing verified that its contributing files exist or name it back. " + f"Write the value as '- **Contributing files:** ', or as a '**Contributing files:**' heading followed by '- ' bullets — " + f"or record '(none)' if this source contributed no files." + ) + elif cf_files: for cf_rel in cf_files: cf_abs = os.path.join(plugin_root, cf_rel) if not os.path.isfile(cf_abs): diff --git a/plugins/kyberforge/.apm/skills/agent-audit/tests/validate-provenance.bats b/plugins/kyberforge/.apm/skills/agent-audit/tests/validate-provenance.bats index d14635c..186d484 100644 --- a/plugins/kyberforge/.apm/skills/agent-audit/tests/validate-provenance.bats +++ b/plugins/kyberforge/.apm/skills/agent-audit/tests/validate-provenance.bats @@ -433,3 +433,140 @@ EOF run bash "$SCRIPT" "$root/.apm/agents/my-agent.agent.md" assert_success } + +# --------------------------------------------------------------------------- +# Checks 3 and 4: None ("could not parse") is NOT [] ("explicitly (none)") +# +# parse_contributing_files returns three distinguishable answers and checks 3 +# and 4 have to honour all three. `[]` is the author writing "(none)" — the +# skip is correct and silent. None is a Contributing files block the parser +# cannot read, and skipping THAT silently disables both checks on the one entry +# least likely to be right, which is the failure mode the parser's own +# docstring warns about. The assertions below are therefore about the INFO +# appearing; a silent exit 0 is exactly the bug. +# --------------------------------------------------------------------------- + +@test "INFO: an unparsable Contributing files block names the slug instead of skipping checks 3 and 4 silently" { + local root="$TMPDIR/package" + make_package "$root" + make_agent_with_source_keys "$root" + cat > "$root/sources.md" < "$root/sources.md" < "$root/sources.md" < "$root/sources.md" <', or as a '**Contributing files:**' heading followed by '- ' bullets — " + f"or record '(none)' if this source contributed no files." + ) + elif cf_files: for cf_rel in cf_files: cf_abs = os.path.join(skill_dir, cf_rel) if not os.path.isfile(cf_abs): diff --git a/plugins/kyberforge/.apm/skills/skill-audit/tests/validate-provenance.bats b/plugins/kyberforge/.apm/skills/skill-audit/tests/validate-provenance.bats index 7b0df0c..aef8d83 100644 --- a/plugins/kyberforge/.apm/skills/skill-audit/tests/validate-provenance.bats +++ b/plugins/kyberforge/.apm/skills/skill-audit/tests/validate-provenance.bats @@ -985,3 +985,132 @@ EOF assert_output --partial "INFO" assert_output --partial "Upstream checks skipped for 'my-source' — no repo root above the skill directory" } + +# --------------------------------------------------------------------------- +# Cycle 16 — Checks 4 and 5: None ("could not parse") is NOT [] ("explicitly +# (none)"), on the sources.md side this time +# +# Cycle 13 pinned the distinction for check 8, which reads the parser's output +# against a RESEARCH doc. Checks 4 and 5 read it against the skill's own +# sources.md and honoured neither half: a truthiness test collapsed None into +# [], so an unreadable Contributing files block disabled both checks and the +# script still exited 0 with no output — the failure mode +# parse_contributing_files' docstring names in as many words. The assertions +# below are therefore about the INFO appearing; a silent exit 0 is exactly the +# bug. +# --------------------------------------------------------------------------- + +@test "INFO: an unparsable Contributing files block names the slug instead of skipping checks 4 and 5 silently" { + local skill="$TMPDIR/my-skill" + make_skill_with_source_keys "$skill" + mkdir -p "$skill/references" + cat > "$skill/references/sources.md" < "$skill/references/sources.md" < "$skill/references/extra.md" < "$skill/references/extra.md" <', or as a '**Contributing files:**' heading followed by '- ' bullets — " + f"or record '(none)' if this source contributed no files." + ) + elif cf_files: for cf_rel in cf_files: cf_abs = os.path.join(plugin_root, cf_rel) if not os.path.isfile(cf_abs): diff --git a/plugins/kyberforge/skills/skill-audit/scripts/validate-provenance.sh b/plugins/kyberforge/skills/skill-audit/scripts/validate-provenance.sh index 5524605..2e8cca9 100755 --- a/plugins/kyberforge/skills/skill-audit/scripts/validate-provenance.sh +++ b/plugins/kyberforge/skills/skill-audit/scripts/validate-provenance.sh @@ -21,7 +21,10 @@ Checks performed: 3 source_keys in references/*.md → slug exists in sources.md (INFO if no source_keys; an explicit 'source_keys: []' declares the file house-authored and passes silently) - 4 Contributing files listed in sources.md exist on disk + 4 Contributing files listed in sources.md exist on disk. An explicit + '(none)' skips silently; a Contributing files block this parser cannot + read is reported as an INFO saying checks 4 and 5 did not run, never + skipped silently. 5 Contributing files back-reference the parent slug in their source_keys 6 Research doc field present and not placeholder 7 Slug in sources.md present in upstream research doc (INFO only). A section @@ -104,7 +107,13 @@ def parse_source_keys(fm): # claims that then have to be maintained in sources.md as well. A bare # `source_keys:` with nothing after it is NOT accepted here — that reads as a # truncated or half-written entry, not a decision. -EMPTY_SOURCE_KEYS_RE = re.compile(r'^\s*source_keys:\s*\[\s*\]\s*$') +# +# The indent is pinned to the two positions parse_source_keys() actually reads +# — column 0, or two spaces under `metadata:`. A permissive `^\s*` matched a +# `source_keys: []` nested at ANY depth under an unrelated key, which +# parse_source_keys() never reads, so a stray nested key silenced the check-3 +# INFO for a file that had declared nothing. +EMPTY_SOURCE_KEYS_RE = re.compile(r'^(?: )?source_keys:\s*\[\s*\]\s*$') def declares_empty_source_keys(fm): """True when frontmatter carries an explicit, empty `source_keys: []`.""" @@ -436,9 +445,25 @@ repo_root = find_repo_root(skill_dir) research_docs_seen = {} # abs_path → set of slugs in sources.md that reference it for slug in parse_h2_slugs(sources_content): - # Check 4: Contributing files exist + # Checks 4 and 5: Contributing files exist, and back-reference the slug. + # `[]` and None are NOT the same answer here. `[]` is the author writing + # "(none)" — there is nothing to check and the skip is correct. None is a + # Contributing-files block this parser cannot read, and skipping THAT + # silently disables both checks on the one entry least likely to be right, + # which is the failure mode parse_contributing_files' own docstring warns + # about. Say so out loud instead, the same way an unresolvable Research doc + # value does. cf_files = parse_contributing_files(sources_content, slug) - if cf_files: + if cf_files is None: + emit_info( + f"Contributing-file checks skipped for '{slug}' — the Contributing files block could not be parsed", + f"references/sources.md (## {slug})", + f"The '## {slug}' entry has no Contributing files list this parser can read — a missing field, a bare heading, '*' bullets, a numbered list, or prose all read as unparsable rather than as an empty declaration. " + f"Checks 4 and 5 did not run for this slug, so nothing verified that its contributing files exist or name it back. " + f"Write the value as '- **Contributing files:** ', or as a '**Contributing files:**' heading followed by '- ' bullets — " + f"or record '(none)' if this source contributed no files." + ) + elif cf_files: for cf_rel in cf_files: cf_abs = os.path.join(skill_dir, cf_rel) if not os.path.isfile(cf_abs):