From 9f644fe26dc8f8bd91aa33eb8440b60fee99e317 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 21:09:16 +0200 Subject: [PATCH 01/23] feat: update skill and agent documentation, refine task execution logic, and enhance test coverage --- .github/agents/README.md | 2 +- .github/scripts/run.sh | 10 ++-- .../SKILL.md | 3 - .../internal-agent-support-next-step/SKILL.md | 4 +- .github/skills/internal-excel/SKILL.md | 25 +------- .github/skills/internal-gateway-idea/SKILL.md | 3 +- .../references/workflow.md | 2 +- .../internal-gateway-simple-task/SKILL.md | 2 +- .../scripts/resolve_simple_task.py | 5 +- INTERNAL_CONTRACT.md | 2 +- Makefile | 33 ++--------- .../test_validation_entrypoints.py | 29 ---------- .../test_fast_check_contract.py | 17 ------ .../test_workflow_contract.py | 14 ++--- .../test_simple_task_contract.py | 57 +++++++++++++++++++ .../test_makefile_skill_script_references.py | 23 ++++++++ tests/test_repository_test_layout_contract.py | 16 ++++++ 17 files changed, 121 insertions(+), 126 deletions(-) delete mode 100644 tests/github/skills/internal-gateway-idea/test_fast_check_contract.py create mode 100644 tests/test_makefile_skill_script_references.py diff --git a/.github/agents/README.md b/.github/agents/README.md index 81ad20ba..e78487cf 100644 --- a/.github/agents/README.md +++ b/.github/agents/README.md @@ -12,7 +12,7 @@ repo-only sync workflows. - `internal-gateway-review-code`: owns dedicated code-focused review for source, tests, scripts, build metadata, dependency metadata, and code diffs. - `internal-gateway-critical-master`: owns pressure testing. -- `internal-gateway-simple-task`: owns concrete execution and approved retained-plan consumption. +- `internal-gateway-simple-task`: owns concrete execution through one focused lane. ## Active Gateway Agents diff --git a/.github/scripts/run.sh b/.github/scripts/run.sh index 1c122019..44c31f00 100755 --- a/.github/scripts/run.sh +++ b/.github/scripts/run.sh @@ -34,12 +34,12 @@ Tools: github_catalog_validation analyze_copilot_debug_log benchmark_skill_tokens - build_inventory - check_catalog_consistency - audit_copilot_catalog - detect_token_risks + build_inventory + check_catalog_consistency + audit_copilot_catalog + detect_token_risks sync_home_ai_resources - validate_critical_output + validate_critical_output validate_internal_skills EOF } diff --git a/.github/skills/internal-agent-support-lane-change-engine/SKILL.md b/.github/skills/internal-agent-support-lane-change-engine/SKILL.md index ef339910..790fe1fd 100644 --- a/.github/skills/internal-agent-support-lane-change-engine/SKILL.md +++ b/.github/skills/internal-agent-support-lane-change-engine/SKILL.md @@ -7,7 +7,6 @@ description: Use when a repository-owned internal agent needs a consistent user- ## Referenced skills -- `internal-gateway-simple-task`: source or target lane for concrete local follow-up work. - `internal-gateway-idea`: source lane when planning or scope definition is needed; target lane when planning or scope definition dominates. - `internal-gateway-critical-master`: source lane when assumption pressure-testing dominates; target lane when assumption pressure-testing dominates. - `internal-gateway-execute-plans`: target lane when approved retained-plan execution is the next step. @@ -31,7 +30,5 @@ agents. | Current agent | When the boundary breaks | Recommend | | --- | --- | --- | -| `internal-gateway-simple-task` | Planning or governance becomes dominant | `internal-gateway-idea` | -| `internal-gateway-simple-task` | Assumption pressure-testing becomes dominant | `internal-gateway-critical-master` | | `internal-gateway-critical-master` | The next step is planning | `internal-gateway-idea` | | `internal-gateway-idea` | An approved retained plan is ready for execution | `internal-gateway-execute-plans` | diff --git a/.github/skills/internal-agent-support-next-step/SKILL.md b/.github/skills/internal-agent-support-next-step/SKILL.md index f7847541..dcbb35f9 100644 --- a/.github/skills/internal-agent-support-next-step/SKILL.md +++ b/.github/skills/internal-agent-support-next-step/SKILL.md @@ -8,7 +8,6 @@ description: Use when a repository-owned agent or prompt needs to package an alr ## Referenced skills - `internal-gateway-idea`: source lane that may need a visible next-step transition. -- `internal-gateway-simple-task`: source lane that may need a visible next-step transition. - `internal-gateway-execute-plans`: source lane that may need a visible next-step transition. - `internal-gateway-critical-master`: source lane that may need a visible next-step transition. @@ -17,8 +16,7 @@ chosen or confirmed. ## When to use -- `internal-gateway-idea`, `internal-gateway-simple-task`, - `internal-gateway-execute-plans`, or `internal-gateway-critical-master` +- `internal-gateway-idea`, `internal-gateway-execute-plans`, or `internal-gateway-critical-master` stop with a visible transition. ## Package Contract diff --git a/.github/skills/internal-excel/SKILL.md b/.github/skills/internal-excel/SKILL.md index fe7e9064..0a0e38e6 100644 --- a/.github/skills/internal-excel/SKILL.md +++ b/.github/skills/internal-excel/SKILL.md @@ -29,9 +29,8 @@ description: Use when tasks involve CSV, TSV, or Excel tabular data profiling, s - Keep evidence compact for large files: report headers, counts, targeted anomalies, transformation rules, exact validation gaps, and any locale or coercion assumptions that change numeric meaning. - Treat `.xlsx` as a workbook container first. Stay here for tabular extraction, safe value-level transformation, workbook contract inspection, writer parity checks, and formula-column decisions. Route to `anthropic-xlsx` only when rendered fidelity, cached recalculation, charts, or presentation-preserving delivery is the main job. - Preserve identifier fidelity before coercion: keep leading zeros, long numeric IDs, and day-first date text exact until an explicit schema rule says otherwise. -- Flag spreadsheet-bound text that could execute as a formula and minimize sensitive-column exposure in samples or logs. +- Flag spreadsheet-bound text that could execute as a formula and minimize sensitive-column exposure in samples or logs; apply the safeguards in `references/data-integrity-and-safety.md` when those risks are material. - Read `references/tool-selection.md` when choosing between Python `csv`, `pandas`, `openpyxl`, PyArrow, Polars, or DuckDB, or when scale, memory use, file format, or workbook fidelity makes the engine choice non-obvious. -- Read `references/data-integrity-and-safety.md` when delimiter or encoding detection, locale coercion, operation-specific proof, formula injection, or sensitive data exposure are material. - Read `references/large-file-token-discipline.md` when file size, broad profiling, repeated output, sampling strategy, or context pressure could make the tabular workflow expensive. ## Noise Exclusions @@ -40,13 +39,6 @@ description: Use when tasks involve CSV, TSV, or Excel tabular data profiling, s - Ignore workbook lock files such as `~$*` and `.~lock.*`. - Prefer targeted `rg` queries on source files, writer modules, and the named workbook path. Do not start with broad repo scans when the target file or owner path is already known. -## Workbook Token Gate - -- Before broad `.xlsx` reads, collect only bounded metadata: file size, sheet names, target-sheet dimensions, target headers, essential row counts, formula count, and style or style-id counts. -- Do not dump workbook XML, full worksheets, broad profiler output, or whole tables into chat unless they are the missing evidence. -- Read only the target sheets, columns, ranges, or writer blocks needed for the active question. -- Before opening large code modules, use `rg` to find owner functions, workbook writers, style builders, and formula helpers, then read only the needed blocks. - ## Workbook Contracts - When a sample workbook or sample tab defines the expected layout, treat that tab as a contract: column order, widths, header style, body style, money style, alert or error row style, and formula columns. @@ -60,20 +52,6 @@ description: Use when tasks involve CSV, TSV, or Excel tabular data profiling, s - If output validation needs a generated workbook, write it to `tmp/` or another declared controlled path and report that path. - Do not include Excel or LibreOffice lock files in discovery, validation, diffs, or deliverables. -## Runtime And Validation - -- If the local toolchain or bundle exposes a `.venv` or declared runtime, use that runtime for `py_compile`, tests, or `pytest` instead of ambient Python. -- Run the smallest deterministic validation that proves the workbook or tabular change; keep output bounded and artifact-oriented. - -## Token Discipline - -- Run a token budget gate before inspecting large or unknown-size files: capture file size, format, sheet names or delimiter, cheap row and column counts, headers, encoding clues, and the smallest representative sample needed. -- Do not paste full tables, raw workbook XML, full profiling JSON, or broad command output into chat by default. Report bounded summaries, counts, schema, anomalies, transformation rules, artifact paths, and validation gaps. -- Treat row samples as discovery only. Keep samples small and redacted, then prove transformations with full-file aggregate checks such as counts, key scans, coercion failures, or reconciliation queries. -- Prefer streaming reads, column projection, chunked scans, DuckDB, Polars, or PyArrow for large files. Use full `pandas` loads or full workbook traversal only after size and scope show that the token and memory cost is justified. -- For `.xlsx`, inspect workbook metadata first and read only the target sheets or ranges when possible. Do not escalate to broad workbook traversal unless the metadata gate shows it is necessary. -- Pause before expensive expansions such as dumping more rows, profiling every sheet, loading all columns, or running repeated wide joins. If the user explicitly asks for full output, state the context impact and provide the smallest bounded next slice or a local artifact path. - ## Workflow 1. Confirm the artifact type, row scale, token budget risk, whether workbook fidelity matters, and whether locale-specific numeric conventions or spreadsheet reopening are in play. @@ -86,6 +64,7 @@ description: Use when tasks involve CSV, TSV, or Excel tabular data profiling, s ## Validation +- If the local toolchain or bundle exposes a `.venv` or declared runtime, use that runtime for validation instead of ambient Python. - Run the smallest deterministic check that proves the transform: row counts, schema diff, duplicate-key scan, delimiter or encoding confirmation, locale-sensitive numeric confirmation, join cardinality, or a reconciliation sample. - For large files, validation output must stay compact: full-file checks should produce aggregate evidence, anomaly counts, sampled examples only when needed, and paths to generated reports instead of inline dumps. - When data may return to spreadsheet tools, verify formula-injection handling and avoid exposing raw sensitive values in samples or validation output. diff --git a/.github/skills/internal-gateway-idea/SKILL.md b/.github/skills/internal-gateway-idea/SKILL.md index 79be54f0..ac69dcc1 100644 --- a/.github/skills/internal-gateway-idea/SKILL.md +++ b/.github/skills/internal-gateway-idea/SKILL.md @@ -1,7 +1,6 @@ --- name: internal-gateway-idea description: Use when a repository-owned idea needs brainstorming, assumption challenge, alternative discovery, and a spec-vs-plan recommendation before implementation planning. -disable-model-invocation: true --- # Internal Gateway Idea @@ -16,7 +15,7 @@ disable-model-invocation: true - `references/workflow.md`: authoritative state machine, Mermaid workflow, approval rules, routing stability, and scoped local validation lane for this bundle. -- `scripts/audit_workflow.py`: marker-consistency validator; run via `python3 .github/skills/internal-gateway-idea/scripts/audit_workflow.py` or `make internal-gateway-idea-fast-check`. +- `scripts/audit_workflow.py`: marker-consistency validator; run via `python3 .github/skills/internal-gateway-idea/scripts/audit_workflow.py`. - Script output contract: `text` for short operator summaries (default), `json` for nested or machine-consumed output, `tsv`/`csv` only for large flat tables; data on stdout, diagnostics on stderr; keep output bounded. Lightweight repository-owned wrapper for idea shaping. Use `/superpowers-brainstorming` as the core workflow and add the local gates below. Loading `/superpowers-brainstorming` is an intentional, globally-resolvable exception to the bundle self-containment rule. This skill does not replace the core brainstorming process; it constrains it for repository-owned idea work. diff --git a/.github/skills/internal-gateway-idea/references/workflow.md b/.github/skills/internal-gateway-idea/references/workflow.md index 209e1a38..1e39e7c4 100644 --- a/.github/skills/internal-gateway-idea/references/workflow.md +++ b/.github/skills/internal-gateway-idea/references/workflow.md @@ -84,6 +84,6 @@ and user decisions remain visible. ## Local validation lane -Run `python3 .github/skills/internal-gateway-idea/scripts/audit_workflow.py` or `make internal-gateway-idea-fast-check` before widening to catalog-wide checks. This scoped lane must cover the bundle audit and marker consistency. +Run `python3 .github/skills/internal-gateway-idea/scripts/audit_workflow.py` before widening to catalog-wide checks. This scoped lane must cover the bundle audit and marker consistency. The checkpoint must use one bounded research question; do not start a second research pass automatically. diff --git a/.github/skills/internal-gateway-simple-task/SKILL.md b/.github/skills/internal-gateway-simple-task/SKILL.md index 5dc071eb..134fc9e4 100644 --- a/.github/skills/internal-gateway-simple-task/SKILL.md +++ b/.github/skills/internal-gateway-simple-task/SKILL.md @@ -74,7 +74,7 @@ For `full-gate`, complete the gates in this order: 1. Inspect the nearest local evidence. 2. Confirm the task still fits one bounded run. 3. Complete Initial Idea Ordering. -4. Ask one compact `/grill-me` block only when a missing bounded fact blocks the active lane. Use `/grill-me` only when a missing bounded fact blocks the active lane. +4. Ask one compact `/grill-me` block only when a missing bounded fact blocks the active lane. 5. Run `/internal-gateway-critical-master` before non-trivial action. 6. Write a short Readiness Brief. 7. If executable or evaluable behavior changes, load `/internal-tdd` before implementation and follow its routed posture. diff --git a/.github/skills/internal-gateway-simple-task/scripts/resolve_simple_task.py b/.github/skills/internal-gateway-simple-task/scripts/resolve_simple_task.py index 4347b7e8..908bc8e7 100644 --- a/.github/skills/internal-gateway-simple-task/scripts/resolve_simple_task.py +++ b/.github/skills/internal-gateway-simple-task/scripts/resolve_simple_task.py @@ -192,7 +192,8 @@ def detect_depth_keywords(prompt: str, explicit_keywords: list[str]) -> list[str found = set(explicit_keywords) lowered_prompt = prompt.lower() for keyword in DEPTH_KEYWORDS: - if re.search(rf"\b{re.escape(keyword)}\b", lowered_prompt): + explicit_prompt = rf"(?:/{re.escape(keyword)}\b|\b(?:depth|mode|gate)\s*[:=]\s*{re.escape(keyword)}\b|\b{re.escape(keyword)}\s+(?:gate|mode|workflow)\b)" + if re.search(explicit_prompt, lowered_prompt): found.add(keyword) return sorted(found) @@ -337,8 +338,6 @@ def build_gate_decision( if missing_validation_evidence: reason_codes.append("validation-path-missing") blocking_reasons.append("validation-path-missing") - if validation_obvious and missing_validation_evidence: - reason_codes.append("validation-path-missing") if blocking_reasons: gate_outcome = "stop-with-reason" diff --git a/INTERNAL_CONTRACT.md b/INTERNAL_CONTRACT.md index d557d74c..d03655fb 100644 --- a/INTERNAL_CONTRACT.md +++ b/INTERNAL_CONTRACT.md @@ -275,7 +275,7 @@ Treat the current skill-first architecture as the source of truth. Do not infer - `internal-gateway-idea`, `internal-gateway-review`, `internal-gateway-simple-task`, and `internal-gateway-critical-master` remain the canonical repository-owned skill-first gateway core - `internal-gateway-idea`, `internal-gateway-review-generic`, `internal-gateway-simple-task`, and `internal-gateway-critical-master` remain the current Copilot wrapper entrypoints for that core - the default operational model uses direct owner selection or user-selected gateway skills with visible phases instead of a hidden repository-owned front-door router - - retained execution stays separate: `internal-gateway-simple-task` consumes approved `compact` plans and `internal-gateway-execute-plans` consumes approved `extended` plans + - retained execution stays separate: approved retained plans are executed by `internal-gateway-execute-plans` - ambiguous or mixed-shape entry fails safe to `internal-gateway-idea` - unclear target state and multiple credible paths are explicit planning triggers - `internal-gateway-codebase-improvement` is a manual-only specialist gateway outside the canonical gateway core; it must not become an implicit fallback, peer-dispatch target, or replacement for an existing gateway owner diff --git a/Makefile b/Makefile index 6472991d..654a2d40 100644 --- a/Makefile +++ b/Makefile @@ -3,19 +3,19 @@ PYTHON_VERSION := $(strip $(shell head -n 1 $(PYTHON_VERSION_FILE) 2>/dev/null)) PYTHON_MAJOR_MINOR := $(strip $(shell printf '%s' "$(PYTHON_VERSION)" | awk -F. 'NF >= 2 { print $$1 "." $$2 }')) PYTHON ?= $(if $(PYTHON_MAJOR_MINOR),python$(PYTHON_MAJOR_MINOR),python3) SHELL_SCRIPTS := $(wildcard .github/scripts/*.sh) -PYTHON_PATHS := .github/scripts/*.py .github/scripts/lib tests .github/skills +PYTHON_PATHS := .github/scripts/*.py .github/scripts/lib tests SCRIPTS_RUNNER := ./.github/scripts/run.sh SCRIPTS_VENV := .github/scripts/.venv RUFF := $(if $(wildcard $(SCRIPTS_VENV)/bin/ruff),$(SCRIPTS_VENV)/bin/ruff,ruff) -CATALOG_FAST_TESTS := tests/test_inventory_and_consistency.py tests/test_validation_entrypoints_contract.py tests/test_retained_plan_artifact_contract.py tests/github/scripts/test_cli_entrypoints.py +CATALOG_FAST_TESTS := tests/github/scripts/lib/test_inventory.py tests/github/scripts/lib/test_repo_paths.py tests/github/scripts/test_install_graphify_hooks.py tests/github/scripts/test_run_sh_dispatch.py tests/test_repository_test_layout_contract.py CATALOG_FAST_INCLUDE_TOKEN_RISKS ?= 0 MARKDOWNLINT_VERSION := 0.18.1 MARKDOWNLINT_PATTERNS := "**/*.md" "\#tmp/**" "\#graphify-out/**" "\#.graphify_*" "\#.claude/commands/agent-os/**" -.PHONY: help python-version-check lint catalog-lint catalog-fast-check github-catalog-validation test scripts-bootstrap catalog-check catalog-audit inventory-build token-risks skill-lint docs-lint critical-validate internal-gateway-idea-fast-check all +.PHONY: help python-version-check lint catalog-lint catalog-fast-check github-catalog-validation test scripts-bootstrap catalog-check catalog-audit inventory-build token-risks skill-lint docs-lint all help: - @printf '%s\n' 'Targets: lint catalog-lint catalog-fast-check github-catalog-validation test scripts-bootstrap catalog-check catalog-audit inventory-build token-risks skill-lint docs-lint critical-validate all' + @printf '%s\n' 'Targets: lint catalog-lint catalog-fast-check github-catalog-validation test scripts-bootstrap catalog-check catalog-audit inventory-build token-risks skill-lint docs-lint all' python-version-check: @test -s "$(PYTHON_VERSION_FILE)" || { printf '%s\n' 'Missing or empty .python-version.' >&2; exit 1; } @@ -67,14 +67,6 @@ token-risks: scripts-bootstrap skill-lint: scripts-bootstrap @$(SCRIPTS_RUNNER) validate_internal_skills --root . --strict -critical-validate: scripts-bootstrap - @$(SCRIPTS_RUNNER) validate_critical_output --strict --file .github/skills/internal-gateway-critical-master/fixtures/critical_output_valid.md - -internal-gateway-idea-fast-check: scripts-bootstrap - @$(PYTHON) .github/skills/internal-gateway-idea/scripts/audit_workflow.py - @$(SCRIPTS_RUNNER) validate_internal_skills --skill internal-gateway-idea --strict - @$(SCRIPTS_VENV)/bin/python -m pytest -q tests/github/skills/internal-gateway-idea - docs-lint: @if command -v markdownlint-cli2 >/dev/null 2>&1; then \ markdownlint-cli2 $(MARKDOWNLINT_PATTERNS); \ @@ -90,21 +82,4 @@ docs-lint: printf '%s\n' 'npx not installed; skipping markdown lint.'; \ fi -PLAN_FOLDER ?= -PLAN_STAGE ?= handoff - -PLAN_AUTHORING_CLI := .github/skills/internal-gateway-writing-plans/scripts/plan_authoring.py -PLAN_EXECUTING_CLI := .github/skills/internal-gateway-execute-plans/scripts/plan_execution.py - -retained-plan-check: python-version-check - @case "$(PLAN_STAGE)" in \ - handoff) \ - if [ -z "$(PLAN_FOLDER)" ]; then printf '%s\n' 'PLAN_FOLDER is required for handoff stage (e.g. make retained-plan-check PLAN_STAGE=handoff PLAN_FOLDER=tmp/superpowers/plans/my-plan)' >&2; exit 1; fi; \ - $(PYTHON) $(PLAN_AUTHORING_CLI) handoff-check "$(PLAN_FOLDER)" ;; \ - completion) \ - if [ -z "$(PLAN_FILE)" ] || [ -z "$(STATUS_FILE)" ]; then printf '%s\n' 'PLAN_FILE and STATUS_FILE are required for completion stage (e.g. make retained-plan-check PLAN_STAGE=completion PLAN_FILE=tmp/superpowers/plans/my-plan.md STATUS_FILE=tmp/superpowers/plans/my-plan.DONE.md)' >&2; exit 1; fi; \ - $(PYTHON) $(PLAN_EXECUTING_CLI) completion-check "$(PLAN_FILE)" "$(STATUS_FILE)" --repo-root . ;; \ - *) printf '%s\n' 'PLAN_STAGE must be handoff or completion.' >&2; exit 1 ;; \ - esac - all: lint test catalog-check diff --git a/tests/github/skills/internal-gateway-execute-plans/test_validation_entrypoints.py b/tests/github/skills/internal-gateway-execute-plans/test_validation_entrypoints.py index 865edb9d..e35e93d5 100644 --- a/tests/github/skills/internal-gateway-execute-plans/test_validation_entrypoints.py +++ b/tests/github/skills/internal-gateway-execute-plans/test_validation_entrypoints.py @@ -1,4 +1,3 @@ -import subprocess from pathlib import Path REPO_ROOT = next( @@ -8,13 +7,6 @@ ) -def test_make_completion_cli_exists() -> None: - makefile = (REPO_ROOT / "Makefile").read_text() - expected = ".github/skills/internal-gateway-execute-plans/scripts/plan_execution.py" - assert expected in makefile - assert (REPO_ROOT / expected).is_file() - - def test_no_live_legacy_execute_plan_references() -> None: forbidden = ( "done-*", @@ -39,24 +31,3 @@ def test_no_live_legacy_execute_plan_references() -> None: text_parts.append(item.read_text(errors="replace")) text = "\n".join(text_parts) assert not any(marker in text for marker in forbidden) - - -def test_completion_make_target_reaches_bundle_cli(tmp_path: Path) -> None: - plan_file = tmp_path / "plan.md" - plan_file.write_text("# Plan\n") - status_file = tmp_path / "plan.DONE.md" - status_file.write_text("## Status\n`DONE`\n") - result = subprocess.run( - [ - "make", - "retained-plan-check", - f"PLAN_FILE={plan_file}", - f"STATUS_FILE={status_file}", - "PLAN_STAGE=completion", - ], - cwd=REPO_ROOT, - text=True, - capture_output=True, - ) - assert "can't open file" not in result.stderr - assert "No such file or directory" not in result.stderr diff --git a/tests/github/skills/internal-gateway-idea/test_fast_check_contract.py b/tests/github/skills/internal-gateway-idea/test_fast_check_contract.py deleted file mode 100644 index 42dc1ff5..00000000 --- a/tests/github/skills/internal-gateway-idea/test_fast_check_contract.py +++ /dev/null @@ -1,17 +0,0 @@ -from pathlib import Path - -REPO_ROOT = next( - parent - for parent in Path(__file__).resolve().parents - if (parent / "AGENTS.md").exists() and (parent / ".github").exists() -) -MAKEFILE_PATH = REPO_ROOT / "Makefile" - - -def test_makefile_exposes_internal_gateway_idea_fast_check() -> None: - text = MAKEFILE_PATH.read_text() - - assert "internal-gateway-idea-fast-check: scripts-bootstrap" in text - assert ".github/skills/internal-gateway-idea/scripts/audit_workflow.py" in text - assert "validate_internal_skills --skill internal-gateway-idea --strict" in text - assert "tests/github/skills/internal-gateway-idea" in text diff --git a/tests/github/skills/internal-gateway-idea/test_workflow_contract.py b/tests/github/skills/internal-gateway-idea/test_workflow_contract.py index 871170e3..b519cdd7 100644 --- a/tests/github/skills/internal-gateway-idea/test_workflow_contract.py +++ b/tests/github/skills/internal-gateway-idea/test_workflow_contract.py @@ -42,11 +42,6 @@ def test_skill_and_workflow_keep_the_same_gate_order() -> None: _assert_in_order(WORKFLOW_PATH.read_text(), MANDATORY_SEQUENCE) -def test_bundle_docs_reference_the_scoped_fast_lane() -> None: - assert "make internal-gateway-idea-fast-check" in SKILL_PATH.read_text() - assert "make internal-gateway-idea-fast-check" in WORKFLOW_PATH.read_text() - - def test_runtime_prompt_keeps_the_full_mandatory_gate_sequence() -> None: _assert_in_order(AGENT_PATH.read_text(), MANDATORY_SEQUENCE) @@ -63,9 +58,12 @@ def test_idea_runtime_surfaces_delegate_to_the_expected_owners() -> None: assert "/internal-gateway-writing-plans" in text -def test_idea_agent_allows_model_invocation() -> None: - frontmatter = yaml.safe_load(ROOT_AGENT_PATH.read_text().split("---", 2)[1]) - assert frontmatter.get("disable-model-invocation") is not True +def test_idea_skill_and_agent_allow_model_invocation() -> None: + skill_frontmatter = yaml.safe_load(SKILL_PATH.read_text().split("---", 2)[1]) + agent_frontmatter = yaml.safe_load(ROOT_AGENT_PATH.read_text().split("---", 2)[1]) + + assert skill_frontmatter.get("disable-model-invocation") is not True + assert agent_frontmatter.get("disable-model-invocation") is not True def test_bundle_docs_use_repository_root_validation_commands() -> None: diff --git a/tests/github/skills/internal-gateway-simple-task/test_simple_task_contract.py b/tests/github/skills/internal-gateway-simple-task/test_simple_task_contract.py index 9019939a..43fd5595 100644 --- a/tests/github/skills/internal-gateway-simple-task/test_simple_task_contract.py +++ b/tests/github/skills/internal-gateway-simple-task/test_simple_task_contract.py @@ -576,6 +576,45 @@ def test_clarification_reference_has_no_broken_stop_rules_pointer() -> None: assert "Stop Conditions above" in clarification_text +def test_depth_keywords_require_explicit_depth_language() -> None: + assert resolve_simple_task.detect_depth_keywords("fix the full path", []) == [] + assert resolve_simple_task.detect_depth_keywords("run a full gate", []) == [ + "full" + ] + assert resolve_simple_task.detect_depth_keywords("complete the TODO", []) == [] + + +def test_missing_validation_reason_is_emitted_once() -> None: + decision = resolve_simple_task.build_gate_decision( + task="A task with unnamed validation", + lane="edit", + trivial_kind=None, + prompt="", + depth_keywords=[], + risks=[], + needs_plan=False, + needs_review=False, + needs_critical=False, + owner_ambiguous=False, + clarification_overflow=False, + validation_obvious=True, + validation_path="", + validation_gap="", + ) + + assert decision["reason_codes"].count("validation-path-missing") == 1 + + +def test_simple_task_does_not_own_retained_plan_consumption() -> None: + contract_text = (REPO_ROOT / "INTERNAL_CONTRACT.md").read_text() + agents_text = (REPO_ROOT / ".github/agents/README.md").read_text() + + assert "internal-gateway-simple-task` consumes approved `compact` plans" not in contract_text + assert "approved retained-plan consumption" not in agents_text + assert "retained execution stays separate: approved retained plans are executed by `internal-gateway-execute-plans`" in contract_text + + + @pytest.mark.parametrize( ("overrides", "expected_outcome"), [ @@ -667,3 +706,21 @@ def test_skill_and_agent_allow_model_invocation() -> None: assert skill_frontmatter.get("disable-model-invocation") is not True assert agent_frontmatter.get("disable-model-invocation") is not True + + +def test_simple_task_support_references_match_its_no_delegation_boundary() -> None: + skill_text = SKILL_PATH.read_text() + next_step_text = ( + REPO_ROOT + / ".github/skills/internal-agent-support-next-step/SKILL.md" + ).read_text() + lane_change_text = ( + REPO_ROOT + / ".github/skills/internal-agent-support-lane-change-engine/SKILL.md" + ).read_text() + + assert skill_text.count( + "only when a missing bounded fact blocks the active lane." + ) == 1 + assert "internal-gateway-simple-task" not in next_step_text + assert "internal-gateway-simple-task" not in lane_change_text diff --git a/tests/test_makefile_skill_script_references.py b/tests/test_makefile_skill_script_references.py new file mode 100644 index 00000000..f90a33e7 --- /dev/null +++ b/tests/test_makefile_skill_script_references.py @@ -0,0 +1,23 @@ +from pathlib import Path + + +REPO_ROOT = next( + parent + for parent in Path(__file__).resolve().parents + if (parent / "AGENTS.md").exists() and (parent / ".github").exists() +) + + +def test_makefile_does_not_reference_skill_scripts() -> None: + makefile = (REPO_ROOT / "Makefile").read_text() + + forbidden = ( + ".github/skills/", + "critical-validate", + "internal-gateway-idea-fast-check", + "retained-plan-check", + "audit_internal_gateway_idea", + "plan_authoring", + "plan_execution", + ) + assert not any(marker in makefile for marker in forbidden) diff --git a/tests/test_repository_test_layout_contract.py b/tests/test_repository_test_layout_contract.py index 7c35ddce..b4851a95 100644 --- a/tests/test_repository_test_layout_contract.py +++ b/tests/test_repository_test_layout_contract.py @@ -1,4 +1,5 @@ import re +import shlex from pathlib import Path REPO_ROOT = next( @@ -7,6 +8,7 @@ if (parent / "AGENTS.md").exists() and (parent / ".github").exists() ) TESTS_ROOT = REPO_ROOT / "tests" +MAKEFILE = REPO_ROOT / "Makefile" AGENTS = REPO_ROOT / "AGENTS.md" INTERNAL_TDD = REPO_ROOT / ".github/skills/internal-tdd/SKILL.md" INTERNAL_CONTRACT = REPO_ROOT / "INTERNAL_CONTRACT.md" @@ -73,3 +75,17 @@ def test_github_owned_python_tests_make_owner_obvious() -> None: ) assert not violations, "\n".join(violations) + + +def test_catalog_fast_check_lists_existing_test_files() -> None: + makefile_text = MAKEFILE.read_text(encoding="utf-8") + line = next( + line + for line in makefile_text.splitlines() + if line.startswith("CATALOG_FAST_TESTS :=") + ) + test_paths = shlex.split(line.split(":=", 1)[1].strip()) + missing_paths = [path for path in test_paths if not (REPO_ROOT / path).is_file()] + + missing_summary = ", ".join(missing_paths) + assert not missing_paths, f"catalog-fast-check lists missing tests: {missing_summary}" From db2986702431d65e6d13dd5bbfc1d68d9acdf03a Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 21:14:41 +0200 Subject: [PATCH 02/23] feat: remove deprecated internal-agent-support skills and update related documentation --- .github/CHANGELOG.md | 2 +- .github/INVENTORY.md | 2 - .github/scripts/benchmark_skill_tokens.py | 4 +- .github/scripts/lib/token_risks.py | 35 ---------------- .../SKILL.md | 34 --------------- .../agents/openai.yaml | 4 -- .../internal-agent-support-next-step/SKILL.md | 30 ------------- .../agents/openai.yaml | 4 -- .../references/decision-brief.md | 42 ------------------- .../test_repository_routing_contract.py | 9 ---- .../test_simple_task_contract.py | 17 -------- 11 files changed, 3 insertions(+), 180 deletions(-) delete mode 100644 .github/skills/internal-agent-support-lane-change-engine/SKILL.md delete mode 100644 .github/skills/internal-agent-support-lane-change-engine/agents/openai.yaml delete mode 100644 .github/skills/internal-agent-support-next-step/SKILL.md delete mode 100644 .github/skills/internal-agent-support-next-step/agents/openai.yaml delete mode 100644 .github/skills/internal-agent-support-next-step/references/decision-brief.md diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index c14ff587..93b279b5 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -26,7 +26,7 @@ Use this format for new updates: - Narrowed `internal-gateway-operational-flow` to delegate unresolved idea work visibly to the new gateway and consume validated Definition Brief handoffs for `plan` without repeating ideation or its critical pass. - Added guided decision interview semantics: evidence-first discovery, iterative numbered question blocks through `grill-me`, visible defaults, compact decision ledger, proportional depth, and checkpoint states. - Retired the standalone `idea-refine` skill immediately after extracting its useful shaping frameworks and evaluation criteria into `internal-gateway-idea` references, preserving its upstream license and removing the competing runtime entrypoint. -- Updated adjacent routing owners (`internal-agent-support-next-step`, `internal-agent-support-lane-change-engine`, `internal-gateway-simple-task`, `internal-gateway-critical-master`) to recognize the new gateway in handoffs and lane-change recommendations. +- Updated adjacent gateway routing owners to recognize the new gateway in handoffs and lane-change recommendations. - Updated `.github/agents/README.md`, `.github/README.md`, `INTERNAL_CONTRACT.md`, `docs`, wrapper-alignment, mode-contracts, subagent-patterns, home-sync catalog, token benchmarks, and regression tests for the four-gateway model. ## 2026-05-19 diff --git a/.github/INVENTORY.md b/.github/INVENTORY.md index 5831aae4..321bce3d 100644 --- a/.github/INVENTORY.md +++ b/.github/INVENTORY.md @@ -62,8 +62,6 @@ This file is the exact path inventory for the live GitHub Copilot catalog in thi - `.github/skills/awesome-copilot-security-review/SKILL.md` - `.github/skills/grill-me/SKILL.md` - `.github/skills/internal-agent-creator/SKILL.md` -- `.github/skills/internal-agent-support-lane-change-engine/SKILL.md` -- `.github/skills/internal-agent-support-next-step/SKILL.md` - `.github/skills/internal-aws-governance/SKILL.md` - `.github/skills/internal-aws-lambda/SKILL.md` - `.github/skills/internal-aws-mcp-research/SKILL.md` diff --git a/.github/scripts/benchmark_skill_tokens.py b/.github/scripts/benchmark_skill_tokens.py index cc203524..aab2f00a 100644 --- a/.github/scripts/benchmark_skill_tokens.py +++ b/.github/scripts/benchmark_skill_tokens.py @@ -116,7 +116,7 @@ def build_scenario_report(root: Path) -> list[dict[str, Any]]: "Define idea and critical": [ GATEWAY_SKILL, "grill-me", "internal-gateway-critical-master", ], - "Plan handoff": [GATEWAY_SKILL, "internal-gateway-writing-plans", "internal-agent-support-next-step"], + "Plan handoff": [GATEWAY_SKILL, "internal-gateway-writing-plans"], "Approved apply-plan": [GATEWAY_SKILL, "internal-gateway-execute-plans"], "Review counter-check": [ REVIEW_COUNTERCHECK_SKILL, @@ -131,7 +131,7 @@ def build_scenario_report(root: Path) -> list[dict[str, Any]]: "Mandatory critical pass": [ IDEA_GATEWAY_SKILL, "internal-gateway-critical-master", ], - "Visible handoff": [IDEA_GATEWAY_SKILL, "internal-agent-support-next-step"], + "Visible handoff": [IDEA_GATEWAY_SKILL], } GATEWAY_OUTPUT_FIELD_SCENARIOS: dict[str, list[str]] = { diff --git a/.github/scripts/lib/token_risks.py b/.github/scripts/lib/token_risks.py index e09c9787..2b0cbff4 100644 --- a/.github/scripts/lib/token_risks.py +++ b/.github/scripts/lib/token_risks.py @@ -54,11 +54,6 @@ GATEWAY_CORE_SKILL_PATH = ".github/skills/internal-gateway-idea/SKILL.md" GATEWAY_CORE_BYTE_BUDGET = 16286 GATEWAY_REQUIRED_CONTEXT_BYTE_BUDGET = 30000 -GATEWAY_UNIVERSAL_PRELOAD_MARKERS = ( - "Always preload only `grill-me` and `internal-agent-support-next-step`.", -) - - def detect_token_risks(root: Path) -> list[Finding]: findings: list[Finding] = [] findings.extend(check_root_policy_overlap(root)) @@ -75,7 +70,6 @@ def detect_token_risks(root: Path) -> list[Finding]: findings.extend(check_internal_root_policy_overlap(root)) findings.extend(check_paired_agent_skill_overlap(root)) findings.extend(check_gateway_core_budget(root)) - findings.extend(check_gateway_universal_preload_regression(root)) return sorted(findings, key=finding_sort_key) @@ -579,35 +573,6 @@ def check_gateway_core_budget(root: Path) -> list[Finding]: ] -def check_gateway_universal_preload_regression(root: Path) -> list[Finding]: - path = root / GATEWAY_CORE_SKILL_PATH - if not path.exists(): - return [] - - text = read_text(path) - found_markers = [ - marker for marker in GATEWAY_UNIVERSAL_PRELOAD_MARKERS if marker in text - ] - if not found_markers: - return [] - - return [ - Finding( - severity="non-blocking", - code="gateway-universal-preload-regression", - path=GATEWAY_CORE_SKILL_PATH, - message=( - "The operational-flow core still contains universal preload instructions " - f"that should be phase-local: {', '.join(repr(m) for m in found_markers)}." - ), - suggestion=( - "Load grill-me when Gate 0 activates and internal-agent-support-next-step " - "when a transition package is needed; do not preload universally." - ), - ) - ] - - def extract_section_bullets(text: str, heading: str) -> list[str]: bullets: list[str] = [] inside_section = False diff --git a/.github/skills/internal-agent-support-lane-change-engine/SKILL.md b/.github/skills/internal-agent-support-lane-change-engine/SKILL.md deleted file mode 100644 index 790fe1fd..00000000 --- a/.github/skills/internal-agent-support-lane-change-engine/SKILL.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: internal-agent-support-lane-change-engine -description: Use when a repository-owned internal agent needs a consistent user-visible lane-change response after the selected lane no longer fits. ---- - -# Internal Agent Support Lane Change Engine - -## Referenced skills - -- `internal-gateway-idea`: source lane when planning or scope definition is needed; target lane when planning or scope definition dominates. -- `internal-gateway-critical-master`: source lane when assumption pressure-testing dominates; target lane when assumption pressure-testing dominates. -- `internal-gateway-execute-plans`: target lane when approved retained-plan execution is the next step. - -Use this skill as the shared lane-mismatch engine for repository-owned internal -agents. - -## When to use - -- A repository-owned internal agent no longer fits the real work. -- The current owner must stop and recommend one better visible owner. - -## Goals - -- Stop before doing off-lane work. -- Explain the concrete mismatch. -- Recommend exactly one better owner when the next lane is clear. -- Fail safe to `internal-gateway-idea` when the next lane is still ambiguous. - -## Recommendation Matrix - -| Current agent | When the boundary breaks | Recommend | -| --- | --- | --- | -| `internal-gateway-critical-master` | The next step is planning | `internal-gateway-idea` | -| `internal-gateway-idea` | An approved retained plan is ready for execution | `internal-gateway-execute-plans` | diff --git a/.github/skills/internal-agent-support-lane-change-engine/agents/openai.yaml b/.github/skills/internal-agent-support-lane-change-engine/agents/openai.yaml deleted file mode 100644 index 58c481d5..00000000 --- a/.github/skills/internal-agent-support-lane-change-engine/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Internal Agent Support Lane Change Engine" - short_description: "Shared user-visible lane-change guidance" - default_prompt: "Use $internal-agent-support-lane-change-engine when a repository-owned internal agent needs the shared stop-and-recommend lane-change workflow." diff --git a/.github/skills/internal-agent-support-next-step/SKILL.md b/.github/skills/internal-agent-support-next-step/SKILL.md deleted file mode 100644 index dcbb35f9..00000000 --- a/.github/skills/internal-agent-support-next-step/SKILL.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: internal-agent-support-next-step -description: Use when a repository-owned agent or prompt needs to package an already-chosen next owner, scope, action, validation path, and risk note for a user-visible transition. ---- - -# Internal Agent Support Next Step - -## Referenced skills - -- `internal-gateway-idea`: source lane that may need a visible next-step transition. -- `internal-gateway-execute-plans`: source lane that may need a visible next-step transition. -- `internal-gateway-critical-master`: source lane that may need a visible next-step transition. - -Use this skill to format the next step after the next owner has already been -chosen or confirmed. - -## When to use - -- `internal-gateway-idea`, `internal-gateway-execute-plans`, or `internal-gateway-critical-master` - stop with a visible transition. - -## Package Contract - -- `Owner` -- `Scope` -- `Action` -- `Validation` -- `Risk` -- `Continuation` -- `User action required` when `Continuation` is `waiting` diff --git a/.github/skills/internal-agent-support-next-step/agents/openai.yaml b/.github/skills/internal-agent-support-next-step/agents/openai.yaml deleted file mode 100644 index 65c63013..00000000 --- a/.github/skills/internal-agent-support-next-step/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Internal Agent Support Next Step" - short_description: "Package user-visible next actions" - default_prompt: "Use $internal-agent-support-next-step to package the selected next owner, scope, action, validation path, and risk note for a user-visible transition." diff --git a/.github/skills/internal-agent-support-next-step/references/decision-brief.md b/.github/skills/internal-agent-support-next-step/references/decision-brief.md deleted file mode 100644 index 62f350c8..00000000 --- a/.github/skills/internal-agent-support-next-step/references/decision-brief.md +++ /dev/null @@ -1,42 +0,0 @@ -# Decision Brief - -Use this template when a plan phase or next-step package needs a compact bridge -to execution, review, or critical challenge. The brief is a projection of the -decision, not a second canonical plan. - -## Source Pattern - -- Comparative source: `tmp/external-comparison/compound-engineering-plugin/plugins/compound-engineering/skills/ce-plan/references/plan-handoff.md`. -- Adopt the handoff shape only. Do not import the external runtime. - -## Required Fields - -| Field | Required content | -| --- | --- | -| Target state | The smallest complete outcome the next owner should deliver. | -| Anti-scope | Work the next owner must not add silently. | -| Suggested owner | Exact skill or agent owner already selected. | -| Evidence source | Plan path, request, diff, validator output, or reference that justifies the step. | -| Validation path | Command, review path, validator, or explicit validation gap. | -| Known risks | Residual risk, tradeoff, rollback note, or missing evidence. | -| Stop conditions | Conditions that must stop execution or trigger lane change. | - -## Template - -```text -Decision Brief -Target state: -Anti-scope: -Suggested owner: -Evidence source: -Validation path: -Known risks: -Stop conditions: -``` - -## Missing Field Handling - -- If a required field is missing before execution, state the gap visibly. -- If the gap is recoverable from repository files, inspect those files first. -- If the gap cannot be recovered safely, stop and ask for the missing decision. -- Do not fill missing owner, validation, or stop-condition fields from memory. diff --git a/tests/github/skills/internal-gateway-execute-plans/test_repository_routing_contract.py b/tests/github/skills/internal-gateway-execute-plans/test_repository_routing_contract.py index b2c74fcb..3207ecf6 100644 --- a/tests/github/skills/internal-gateway-execute-plans/test_repository_routing_contract.py +++ b/tests/github/skills/internal-gateway-execute-plans/test_repository_routing_contract.py @@ -16,15 +16,6 @@ def test_execute_plan_handoff_targets_a_real_agent() -> None: assert "extended" not in idea.lower() -def test_lane_engine_uses_artifact_presence_not_legacy_profiles() -> None: - text = ( - REPO_ROOT / ".github/skills/internal-agent-support-lane-change-engine/SKILL.md" - ).read_text() - assert "approved retained plan" in text - assert "compact" not in text.lower() - assert "extended" not in text.lower() - - def test_agent_loads_gateway_and_allows_model_invocation() -> None: text = ( REPO_ROOT / ".github/agents/internal-gateway-execute-plans.agent.md" diff --git a/tests/github/skills/internal-gateway-simple-task/test_simple_task_contract.py b/tests/github/skills/internal-gateway-simple-task/test_simple_task_contract.py index 43fd5595..b57d5d3c 100644 --- a/tests/github/skills/internal-gateway-simple-task/test_simple_task_contract.py +++ b/tests/github/skills/internal-gateway-simple-task/test_simple_task_contract.py @@ -707,20 +707,3 @@ def test_skill_and_agent_allow_model_invocation() -> None: assert skill_frontmatter.get("disable-model-invocation") is not True assert agent_frontmatter.get("disable-model-invocation") is not True - -def test_simple_task_support_references_match_its_no_delegation_boundary() -> None: - skill_text = SKILL_PATH.read_text() - next_step_text = ( - REPO_ROOT - / ".github/skills/internal-agent-support-next-step/SKILL.md" - ).read_text() - lane_change_text = ( - REPO_ROOT - / ".github/skills/internal-agent-support-lane-change-engine/SKILL.md" - ).read_text() - - assert skill_text.count( - "only when a missing bounded fact blocks the active lane." - ) == 1 - assert "internal-gateway-simple-task" not in next_step_text - assert "internal-gateway-simple-task" not in lane_change_text From 6063daad2e9487ad38ac26571dbce63d6cfb9d61 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 21:29:33 +0200 Subject: [PATCH 03/23] feat: add mattpocock-triage skill and related documentation, update inventory and tests --- .github/INVENTORY.md | 1 + .../references/managed-resources.yaml | 7 +- .../skills/mattpocock-triage/AGENT-BRIEF.md | 207 ++++++++++++++++++ .../skills/mattpocock-triage/OUT-OF-SCOPE.md | 105 +++++++++ .github/skills/mattpocock-triage/SKILL.md | 112 ++++++++++ .../mattpocock-triage/agents/openai.yaml | 5 + .../scripts/test_cli.py | 2 +- .../scripts/test_manifest.py | 12 +- 8 files changed, 443 insertions(+), 8 deletions(-) create mode 100644 .github/skills/mattpocock-triage/AGENT-BRIEF.md create mode 100644 .github/skills/mattpocock-triage/OUT-OF-SCOPE.md create mode 100644 .github/skills/mattpocock-triage/SKILL.md create mode 100644 .github/skills/mattpocock-triage/agents/openai.yaml diff --git a/.github/INVENTORY.md b/.github/INVENTORY.md index 321bce3d..2756a0a3 100644 --- a/.github/INVENTORY.md +++ b/.github/INVENTORY.md @@ -139,6 +139,7 @@ This file is the exact path inventory for the live GitHub Copilot catalog in thi - `.github/skills/mattpocock-setup-matt-pocock-skills/SKILL.md` - `.github/skills/mattpocock-tdd/SKILL.md` - `.github/skills/mattpocock-to-spec/SKILL.md` +- `.github/skills/mattpocock-triage/SKILL.md` - `.github/skills/mattpocock-wayfinder/SKILL.md` - `.github/skills/mattpocock-writing-great-skills/SKILL.md` - `.github/skills/openai-docs/SKILL.md` diff --git a/.github/skills/local-agent-sync-external-resources/references/managed-resources.yaml b/.github/skills/local-agent-sync-external-resources/references/managed-resources.yaml index f3a8adc7..3ed667e2 100644 --- a/.github/skills/local-agent-sync-external-resources/references/managed-resources.yaml +++ b/.github/skills/local-agent-sync-external-resources/references/managed-resources.yaml @@ -120,6 +120,9 @@ sources: - upstream: skills/engineering/setup-matt-pocock-skills local: .github/skills/mattpocock-setup-matt-pocock-skills canonical_name: mattpocock-setup-matt-pocock-skills + - upstream: skills/engineering/triage + local: .github/skills/mattpocock-triage + canonical_name: mattpocock-triage - upstream: skills/engineering/code-review local: .github/skills/mattpocock-code-review canonical_name: mattpocock-code-review @@ -258,10 +261,6 @@ watchlist: upstream_id: prototype local_owner: unmanaged reason: Referenced by wayfinder but outside the user-approved import scope; keep visible until explicitly approved or mapped to a local owner. - - source_family: mattpocock/skills - upstream_id: triage - local_owner: unmanaged - reason: Referenced by setup-matt-pocock-skills but not installed in this repository; keep visible until explicitly approved or mapped to a local owner. - source_family: mattpocock/skills upstream_id: to-tickets local_owner: unmanaged diff --git a/.github/skills/mattpocock-triage/AGENT-BRIEF.md b/.github/skills/mattpocock-triage/AGENT-BRIEF.md new file mode 100644 index 00000000..55123719 --- /dev/null +++ b/.github/skills/mattpocock-triage/AGENT-BRIEF.md @@ -0,0 +1,207 @@ +# Writing Agent Briefs + +An agent brief is a structured comment posted on a GitHub issue or PR when it moves to `ready-for-agent`. It is the authoritative specification that an AFK agent will work from. The original body and discussion are context — the agent brief is the contract. + +The brief states **what the agent should do**, which stretches to both surfaces: for an issue, that's building the change from nothing; for a PR, it's what's left to do *to the existing diff* — finish it, close gaps, address review points. Same principles either way; the PR example below shows the difference. + +## Principles + +### Durability over precision + +The issue may sit in `ready-for-agent` for days or weeks. The codebase will change in the meantime. Write the brief so it stays useful even as files are renamed, moved, or refactored. + +- **Do** describe interfaces, types, and behavioral contracts +- **Do** name specific types, function signatures, or config shapes that the agent should look for or modify +- **Don't** reference file paths — they go stale +- **Don't** reference line numbers +- **Don't** assume the current implementation structure will remain the same + +### Behavioral, not procedural + +Describe **what** the system should do, not **how** to implement it. The agent will explore the codebase fresh and make its own implementation decisions. + +- **Good:** "The `SkillConfig` type should accept an optional `schedule` field of type `CronExpression`" +- **Bad:** "Open src/types/skill.ts and add a schedule field on line 42" +- **Good:** "When a user runs `/mattpocock-triage` with no arguments, they should see a summary of issues needing attention" +- **Bad:** "Add a switch statement in the main handler function" + +### Complete acceptance criteria + +The agent needs to know when it's done. Every agent brief must have concrete, testable acceptance criteria. Each criterion should be independently verifiable. + +- **Good:** "Running `gh issue list --label needs-triage` returns issues that have been through initial classification" +- **Bad:** "Triage should work correctly" + +### Explicit scope boundaries + +State what is out of scope. This prevents the agent from gold-plating or making assumptions about adjacent features. + +## Template + +```markdown +## Agent Brief + +**Category:** bug / enhancement +**Summary:** one-line description of what needs to happen + +**Current behavior:** +Describe what happens now. For bugs, this is the broken behavior. +For enhancements, this is the status quo the feature builds on. + +**Desired behavior:** +Describe what should happen after the agent's work is complete. +Be specific about edge cases and error conditions. + +**Key interfaces:** +- `TypeName` — what needs to change and why +- `functionName()` return type — what it currently returns vs what it should return +- Config shape — any new configuration options needed + +**Acceptance criteria:** +- [ ] Specific, testable criterion 1 +- [ ] Specific, testable criterion 2 +- [ ] Specific, testable criterion 3 + +**Out of scope:** +- Thing that should NOT be changed or addressed in this issue +- Adjacent feature that might seem related but is separate +``` + +## Examples + +### Good agent brief (bug) + +```markdown +## Agent Brief + +**Category:** bug +**Summary:** Skill description truncation drops mid-word, producing broken output + +**Current behavior:** +When a skill description exceeds 1024 characters, it is truncated at exactly +1024 characters regardless of word boundaries. This produces descriptions +that end mid-word (e.g. "Use when the user wants to confi"). + +**Desired behavior:** +Truncation should break at the last word boundary before 1024 characters +and append "..." to indicate truncation. + +**Key interfaces:** +- The `SkillMetadata` type's `description` field — no type change needed, + but the validation/processing logic that populates it needs to respect + word boundaries +- Any function that reads SKILL.md frontmatter and extracts the description + +**Acceptance criteria:** +- [ ] Descriptions under 1024 chars are unchanged +- [ ] Descriptions over 1024 chars are truncated at the last word boundary + before 1024 chars +- [ ] Truncated descriptions end with "..." +- [ ] The total length including "..." does not exceed 1024 chars + +**Out of scope:** +- Changing the 1024 char limit itself +- Multi-line description support +``` + +### Good agent brief (enhancement) + +```markdown +## Agent Brief + +**Category:** enhancement +**Summary:** Add `.out-of-scope/` directory support for tracking rejected feature requests + +**Current behavior:** +When a feature request is rejected, the issue is closed with a `wontfix` label +and a comment. There is no persistent record of the decision or reasoning. +Future similar requests require the maintainer to recall or search for the +prior discussion. + +**Desired behavior:** +Rejected feature requests should be documented in `.out-of-scope/.md` +files that capture the decision, reasoning, and links to all issues that +requested the feature. When triaging new issues, these files should be +checked for matches. + +**Key interfaces:** +- Markdown file format in `.out-of-scope/` — each file should have a + `# Concept Name` heading, a `**Decision:**` line, a `**Reason:**` line, + and a `**Prior requests:**` list with issue links +- The triage workflow should read all `.out-of-scope/*.md` files early + and match incoming issues against them by concept similarity + +**Acceptance criteria:** +- [ ] Closing a feature as wontfix creates/updates a file in `.out-of-scope/` +- [ ] The file includes the decision, reasoning, and link to the closed issue +- [ ] If a matching `.out-of-scope/` file already exists, the new issue is + appended to its "Prior requests" list rather than creating a duplicate +- [ ] During triage, existing `.out-of-scope/` files are checked and surfaced + when a new issue matches a prior rejection + +**Out of scope:** +- Automated matching (human confirms the match) +- Reopening previously rejected features +- Bug reports (only enhancement rejections go to `.out-of-scope/`) +``` + +### Good agent brief (PR) + +For a PR, "Current behavior" describes the state of the diff, and the brief asks the agent to finish or fix it rather than build from scratch. + +```markdown +## Agent Brief + +**Category:** enhancement +**Summary:** Finish the contributor's `--json` output flag for `triage list` + +**Current behavior:** +The PR adds a `--json` flag that serializes the issue list to JSON. The happy +path works and the diff matches the project's command structure. Two gaps +remain: errors are still printed as human text (not JSON), and the new flag has +no test coverage. + +**Desired behavior:** +With `--json`, all output — including errors — is well-formed JSON on stdout, +and the command's exit codes are unchanged. The existing human-readable output +is untouched when the flag is absent. + +**Key interfaces:** +- The command's error path should emit `{ "error": string }` under `--json` + instead of the plain-text error +- Reuse the existing serializer the PR already added; don't introduce a second + +**Acceptance criteria:** +- [ ] `triage list --json` emits valid JSON for both success and error cases +- [ ] Exit codes match the non-JSON command +- [ ] A test covers the `--json` success output and one error case +- [ ] Default (non-JSON) output is byte-for-byte unchanged + +**Out of scope:** +- Adding `--json` to any other command +- Changing the JSON shape of the success payload the PR already defined +``` + +### Bad agent brief + +```markdown +## Agent Brief + +**Summary:** Fix the triage bug + +**What to do:** +The triage thing is broken. Look at the main file and fix it. +The function around line 150 has the issue. + +**Files to change:** +- src/triage/handler.ts (line 150) +- src/types.ts (line 42) +``` + +This is bad because: +- No category +- Vague description ("the triage thing is broken") +- References file paths and line numbers that will go stale +- No acceptance criteria +- No scope boundaries +- No description of current vs desired behavior diff --git a/.github/skills/mattpocock-triage/OUT-OF-SCOPE.md b/.github/skills/mattpocock-triage/OUT-OF-SCOPE.md new file mode 100644 index 00000000..fc0e39f5 --- /dev/null +++ b/.github/skills/mattpocock-triage/OUT-OF-SCOPE.md @@ -0,0 +1,105 @@ +# Out-of-Scope Knowledge Base + +The `.out-of-scope/` directory in a repo stores persistent records of rejected feature requests. It serves two purposes: + +1. **Institutional memory** — why a feature was rejected, so the reasoning isn't lost when the issue is closed +2. **Deduplication** — when a new issue comes in that matches a prior rejection, the skill can surface the previous decision instead of re-litigating it + +## Directory structure + +``` +.out-of-scope/ +├── dark-mode.md +├── plugin-system.md +└── graphql-api.md +``` + +One file per **concept**, not per issue. Multiple issues requesting the same thing are grouped under one file. + +## File format + +The file should be written in a relaxed, readable style — more like a short design document than a database entry. Use paragraphs, code samples, and examples to make the reasoning clear and useful to someone encountering it for the first time. + +```markdown +# Dark Mode + +This project does not support dark mode or user-facing theming. + +## Why this is out of scope + +The rendering pipeline assumes a single color palette defined in +`ThemeConfig`. Supporting multiple themes would require: + +- A theme context provider wrapping the entire component tree +- Per-component theme-aware style resolution +- A persistence layer for user theme preferences + +This is a significant architectural change that doesn't align with the +project's focus on content authoring. Theming is a concern for downstream +consumers who embed or redistribute the output. + +```ts +// The current ThemeConfig interface is not designed for runtime switching: +interface ThemeConfig { + colors: ColorPalette; // single palette, resolved at build time + fonts: FontStack; +} +``` + +## Prior requests + +- #42 — "Add dark mode support" +- #87 — "Night theme for accessibility" +- #134 — "Dark theme option" +``` + +### Naming the file + +Use a short, descriptive kebab-case name for the concept: `dark-mode.md`, `plugin-system.md`, `graphql-api.md`. The name should be recognizable enough that someone browsing the directory understands what was rejected without opening the file. + +### Writing the reason + +The reason should be substantive — not "we don't want this" but why. Good reasons reference: + +- Project scope or philosophy ("This project focuses on X; theming is a downstream concern") +- Technical constraints ("Supporting this would require Y, which conflicts with our Z architecture") +- Strategic decisions ("We chose to use A instead of B because...") + +The reason should be durable. Avoid referencing temporary circumstances ("we're too busy right now") — those aren't real rejections, they're deferrals. + +## When to check `.out-of-scope/` + +During triage (Step 1: Gather context), read all files in `.out-of-scope/`. When evaluating a new issue: + +- Check if the request matches an existing out-of-scope concept +- Matching is by concept similarity, not keyword — "night theme" matches `dark-mode.md` +- If there's a match, surface it to the maintainer: "This is similar to `.out-of-scope/dark-mode.md` — we rejected this before because [reason]. Do you still feel the same way?" + +The maintainer may: + +- **Confirm** — the new issue gets added to the existing file's "Prior requests" list, then closed +- **Reconsider** — the out-of-scope file gets deleted or updated, and the issue proceeds through normal triage +- **Disagree** — the issues are related but distinct, proceed with normal triage + +## When to write to `.out-of-scope/` + +Only when an **enhancement** (not a bug) is *rejected* as `wontfix`. This applies to enhancement PRs exactly as it does to issues — a rejected PR is recorded here so the same request doesn't return as fresh code. + +Do **not** write here when something is closed as `wontfix` because it's **already implemented**. That's a built feature, not a rejected one; recording it would poison the dedup checks with false rejections. Instead, the closing comment points to where the feature already lives. + +The flow: + +1. Maintainer decides a feature request is out of scope +2. Check if a matching `.out-of-scope/` file already exists +3. If yes: append the new issue to the "Prior requests" list +4. If no: create a new file with the concept name, decision, reason, and first prior request +5. Post a comment on the issue explaining the decision and mentioning the `.out-of-scope/` file +6. Close the issue with the `wontfix` label + +## Updating or removing out-of-scope files + +If the maintainer changes their mind about a previously rejected concept: + +- Delete the `.out-of-scope/` file +- The skill does not need to reopen old issues — they're historical records +- The new issue that triggered the reconsideration proceeds through normal triage diff --git a/.github/skills/mattpocock-triage/SKILL.md b/.github/skills/mattpocock-triage/SKILL.md new file mode 100644 index 00000000..760a8842 --- /dev/null +++ b/.github/skills/mattpocock-triage/SKILL.md @@ -0,0 +1,112 @@ +--- +name: mattpocock-triage +description: Move issues and external PRs through a state machine of triage roles — categorise, verify, grill if needed, and write agent-ready briefs. +disable-model-invocation: true +--- + +# Triage + +Move issues on the project issue tracker through a small state machine of triage roles. + +If this repo treats external pull requests as a request surface (see the issue-tracker config), triage covers them too: **a PR is an issue with attached code** — same roles, same states, same machine, with a few deltas marked "for a PR" below. Resolve a bare `#42` to an issue or PR per the tracker config. + +Every comment or issue posted to the issue tracker during triage **must** start with this disclaimer: + +``` +> *This was generated by AI during triage.* +``` + +## Reference docs + +- [AGENT-BRIEF.md](AGENT-BRIEF.md) — how to write durable agent briefs +- [OUT-OF-SCOPE.md](OUT-OF-SCOPE.md) — how the `.out-of-scope/` knowledge base works + +## Roles + +Two **category** roles: + +- `bug` — something is broken +- `enhancement` — new feature or improvement + +Five **state** roles: + +- `needs-triage` — maintainer needs to evaluate +- `needs-info` — waiting on reporter for more information +- `ready-for-agent` — fully specified, ready for an AFK agent +- `ready-for-human` — needs human implementation +- `wontfix` — will not be actioned + +For a PR, the same states read against the attached code: `ready-for-agent` means a brief is attached and an agent should take the next step on the diff; `ready-for-human` means it's ready for a human to merge. + +Every triaged issue should carry exactly one category role and one state role. If state roles conflict, flag it and ask the maintainer before doing anything else. + +These are canonical role names — the actual label strings used in the issue tracker may differ. The mapping should have been provided to you - run `/setup-matt-pocock-skills` if not. + +State transitions: an unlabeled issue normally goes to `needs-triage` first; from there it moves to `needs-info`, `ready-for-agent`, `ready-for-human`, or `wontfix`. `needs-info` returns to `needs-triage` once the reporter replies. The maintainer can override at any time — flag transitions that look unusual and ask before proceeding. + +## Invocation + +The maintainer invokes `/mattpocock-triage` and describes what they want in natural language. Interpret the request and act. Examples: + +- "Show me anything that needs my attention" +- "Let's look at #42" (issue or PR) +- "Move #42 to ready-for-agent" +- "What's ready for agents to pick up?" + +## Show what needs attention + +Query the issue tracker and present three buckets, oldest first: + +1. **Unlabeled** — never triaged. +2. **`needs-triage`** — evaluation in progress. +3. **`needs-info` with reporter activity since the last triage notes** — needs re-evaluation. + +When PRs are in scope, include external PRs in these buckets and tag each line `[PR]` or `[issue]`. Discovery surfaces only *external* PRs (the tracker config defines who counts as external) — a collaborator's in-flight PR is not triage work. This filter is discovery-only; an explicitly named PR is always triaged regardless of author. + +Show counts and a one-line summary per item. Let the maintainer pick. + +## Triage a specific issue or PR + +1. **Gather context.** Read the full issue or PR (body, comments, labels, author, dates; for a PR, the diff too). Parse any prior triage notes so you don't re-ask resolved questions. Explore the codebase using the project's domain glossary, respecting ADRs in the area. Run two checks against the codebase: (a) **redundancy** — search for an existing implementation of the requested behavior by domain concept (not just the request's wording), and report where you looked. If found, it's an already-implemented `wontfix` (step 5). (b) **prior rejection** — read `.out-of-scope/*.md` and surface any that resembles this request. + +2. **Recommend.** Tell the maintainer your category and state recommendation with reasoning, plus a brief codebase summary relevant to the request — including whether it's already implemented. Wait for direction. + +3. **Verify the claim.** Before any grilling, check that the claim holds up. For a bug, reproduce it from the reporter's steps. For a PR, confirm the diff does what it claims — check it out, run the relevant tests or commands. Report what happened: confirmed (with code path), failed, or insufficient detail (a strong `needs-info` signal). A confirmed verification makes a much stronger agent brief. + +4. **Grill (if needed).** If the request needs fleshing out, run the `/grill-me` and `/mattpocock-domain-modeling` skills together — grill it into shape one question at a time, sharpening domain terms and updating `CONTEXT.md`/ADRs inline as decisions land. + +5. **Apply the outcome:** + - `ready-for-agent` — post an agent brief comment ([AGENT-BRIEF.md](AGENT-BRIEF.md)). + - `ready-for-human` — same structure as an agent brief, but note why it can't be delegated (judgment calls, external access, design decisions, manual testing). + - `needs-info` — post triage notes (template below). + - `wontfix` — close, with the comment depending on *why*: + - **Already implemented** — the change already exists in the codebase. Point to where it lives; do **not** write to `.out-of-scope/` (that KB is for *rejected* requests, not built ones). + - **Rejected (bug)** — polite explanation, then close. + - **Rejected (enhancement)** — write to `.out-of-scope/`, link to it from a comment, then close ([OUT-OF-SCOPE.md](OUT-OF-SCOPE.md)). + - `needs-triage` — apply the role. Optional comment if there's partial progress. + +## Quick state override + +If the maintainer says "move #42 to ready-for-agent", trust them and apply the role directly. Confirm what you're about to do (role changes, comment, close), then act. Skip grilling. If moving to `ready-for-agent` without a grilling session, ask whether they want to write an agent brief. + +## Needs-info template + +```markdown +## Triage Notes + +**What we've established so far:** + +- point 1 +- point 2 + +**What we still need from you (@reporter):** + +- question 1 +- question 2 +``` + +Capture everything resolved during grilling under "established so far" so the work isn't lost. Questions must be specific and actionable, not "please provide more info". + +## Resuming a previous session + +If prior triage notes exist on the issue or PR, read them, check whether the reporter has answered any outstanding questions, and present an updated picture before continuing. Don't re-ask resolved questions. diff --git a/.github/skills/mattpocock-triage/agents/openai.yaml b/.github/skills/mattpocock-triage/agents/openai.yaml new file mode 100644 index 00000000..acb366cf --- /dev/null +++ b/.github/skills/mattpocock-triage/agents/openai.yaml @@ -0,0 +1,5 @@ +interface: + display_name: "Triage" + short_description: "Move issues through triage roles" +policy: + allow_implicit_invocation: false diff --git a/tests/github/skills/local-agent-sync-external-resources/scripts/test_cli.py b/tests/github/skills/local-agent-sync-external-resources/scripts/test_cli.py index 3e6e3eb2..689b26ba 100644 --- a/tests/github/skills/local-agent-sync-external-resources/scripts/test_cli.py +++ b/tests/github/skills/local-agent-sync-external-resources/scripts/test_cli.py @@ -69,7 +69,7 @@ def test_audit_does_not_fetch_or_write(repo_root: Path) -> None: payload = json.loads(result.stdout) assert payload["mode"] == "audit" assert payload["repository_changed"] is False - assert payload["managed_assets"] == 56 + assert payload["managed_assets"] == 57 def test_apply_refuses_dirty_target(tmp_path: Path) -> None: diff --git a/tests/github/skills/local-agent-sync-external-resources/scripts/test_manifest.py b/tests/github/skills/local-agent-sync-external-resources/scripts/test_manifest.py index 426c0913..bc07e3b0 100644 --- a/tests/github/skills/local-agent-sync-external-resources/scripts/test_manifest.py +++ b/tests/github/skills/local-agent-sync-external-resources/scripts/test_manifest.py @@ -139,8 +139,8 @@ def test_live_manifest_preserves_declared_scope(repo_root: Path) -> None: / ".github/skills/local-agent-sync-external-resources/references/managed-resources.yaml" ) - assert len(manifest.assets) == 56 - assert len(manifest.watchlist) == 13 + assert len(manifest.assets) == 57 + assert len(manifest.watchlist) == 12 matt_source = next( source for source in manifest.sources if source.source_id == "mattpocock-skills" ) @@ -150,7 +150,12 @@ def test_live_manifest_preserves_declared_scope(repo_root: Path) -> None: item.upstream_id for item in manifest.watchlist if item.source_family == "mattpocock/skills" - } >= {"prototype", "triage", "to-tickets", "qa"} + } >= {"prototype", "to-tickets", "qa"} + assert "triage" not in { + item.upstream_id + for item in manifest.watchlist + if item.source_family == "mattpocock/skills" + } assert {item.canonical_name for item in matt_source.assets} >= { "mattpocock-grill-with-docs", "mattpocock-domain-modeling", @@ -161,6 +166,7 @@ def test_live_manifest_preserves_declared_scope(repo_root: Path) -> None: "mattpocock-to-spec", "mattpocock-setup-matt-pocock-skills", "mattpocock-code-review", + "mattpocock-triage", "mattpocock-wayfinder", "mattpocock-writing-great-skills", } From 6423f653b1eb152c7f5ec34fc4fc071ab4c7bf75 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 21:54:28 +0200 Subject: [PATCH 04/23] feat: add domain documentation, issue tracker guidelines, and triage labels mapping --- AGENTS.md | 14 +++++++++++++ docs/agents/domain.md | 34 +++++++++++++++++++++++++++++++ docs/agents/issue-tracker.md | 39 ++++++++++++++++++++++++++++++++++++ docs/agents/triage-labels.md | 15 ++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 docs/agents/domain.md create mode 100644 docs/agents/issue-tracker.md create mode 100644 docs/agents/triage-labels.md diff --git a/AGENTS.md b/AGENTS.md index 67048607..b2ea85ad 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -99,6 +99,20 @@ nearest owner, avoid duplicated guidance, and require explicit validation. - If this gate is skipped, agents must stop, disclose the violation, establish the recovery path, and must not claim retroactive red-green-refactor work. +## Agent skills + +### Issue tracker + +Issues and PRDs are tracked in GitHub Issues for `pagopa/cloud-strategy.github`. See `docs/agents/issue-tracker.md`. + +### Triage labels + +Use the default canonical triage labels. See `docs/agents/triage-labels.md`. + +### Domain docs + +This repository uses the single-context domain documentation layout. See `docs/agents/domain.md`. + ## graphify For any question about this repo's architecture, structure, components, or how to add/modify/find diff --git a/docs/agents/domain.md b/docs/agents/domain.md new file mode 100644 index 00000000..1759a544 --- /dev/null +++ b/docs/agents/domain.md @@ -0,0 +1,34 @@ +# Domain Docs + +How the engineering skills should consume this repo's domain documentation when exploring the codebase. + +## Before exploring, read these + +- **`CONTEXT.md`** at the repo root, or +- **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic. +- **`docs/adr/`** — read ADRs that touch the area you're about to work in. + +If any of these files don't exist, proceed silently. Don't flag their absence or suggest creating them upfront. The domain-modeling skill creates them lazily when terms or decisions are resolved. + +## File structure + +This repository uses the single-context layout: + +```text +/ +├── CONTEXT.md +├── docs/adr/ +│ ├── 0001-example-decision.md +│ └── 0002-another-decision.md +└── src/ +``` + +## Use the glossary's vocabulary + +When output names a domain concept, use the term defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids. + +If a concept isn't present in the glossary, reconsider whether the term belongs to the project or note the genuine documentation gap. + +## Flag ADR conflicts + +If output contradicts an existing ADR, surface the conflict explicitly rather than silently overriding it. diff --git a/docs/agents/issue-tracker.md b/docs/agents/issue-tracker.md new file mode 100644 index 00000000..78e863c2 --- /dev/null +++ b/docs/agents/issue-tracker.md @@ -0,0 +1,39 @@ +# Issue tracker: GitHub + +Issues and PRDs for this repo live as GitHub issues. Use the `gh` CLI for all operations. + +## Conventions + +- **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies. +- **Read an issue**: `gh issue view --comments`, filtering comments by `jq` and also fetching labels. +- **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters. +- **Comment on an issue**: `gh issue comment --body "..."` +- **Apply / remove labels**: `gh issue edit --add-label "..."` / `--remove-label "..."` +- **Close**: `gh issue close --comment "..."` + +Infer the repo from `git remote -v` — `gh` does this automatically when run inside a clone. + +## Pull requests as a triage surface + +**PRs as a request surface: no.** + +When set to `yes`, PRs run through the same labels and states as issues, using the `gh pr` equivalents. + +## When a skill says "publish to the issue tracker" + +Create a GitHub issue. + +## When a skill says "fetch the relevant ticket" + +Run `gh issue view --comments`. + +## Wayfinding operations + +Used by `/mattpocock-wayfinder`. The map is a single issue with child issues as tickets. + +- **Map**: a single issue labelled `wayfinder:map`, holding the Notes, Decisions-so-far, and Fog body. +- **Child ticket**: an issue linked to the map as a GitHub sub-issue. Where sub-issues are unavailable, use a task list and add `Part of #` to the child. +- **Blocking**: use GitHub’s native issue dependencies. Where unavailable, add a `Blocked by: #` line. +- **Frontier query**: list the map’s open, unassigned, unblocked children; first in map order wins. +- **Claim**: `gh issue edit --add-assignee @me`. +- **Resolve**: comment on and close the issue, then update the map’s Decisions-so-far. diff --git a/docs/agents/triage-labels.md b/docs/agents/triage-labels.md new file mode 100644 index 00000000..c9a23b66 --- /dev/null +++ b/docs/agents/triage-labels.md @@ -0,0 +1,15 @@ +# Triage Labels + +The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker. + +| Label in mattpocock/skills | Label in our tracker | Meaning | +| -------------------------- | -------------------- | ---------------------------------------- | +| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue | +| `needs-info` | `needs-info` | Waiting on reporter for more information | +| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent | +| `ready-for-human` | `ready-for-human` | Requires human implementation | +| `wontfix` | `wontfix` | Will not be actioned | + +When a skill mentions a role, use the corresponding label string from this table. + +Edit the right-hand column to match whatever vocabulary you actually use. From 375f3011d40568e13abfef37fc7b3f8e7a21db54 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 22:00:45 +0200 Subject: [PATCH 05/23] feat: add 'mattpocock-to-tickets' skill and update related inventory and tests --- .github/INVENTORY.md | 1 + .../scripts/plan_execution.py | 14 ++- .../references/managed-resources.yaml | 7 +- .github/skills/mattpocock-to-tickets/SKILL.md | 105 ++++++++++++++++++ .../mattpocock-to-tickets/agents/openai.yaml | 5 + .../scripts/test_plan_execution.py | 17 +++ .../scripts/test_cli.py | 2 +- .../scripts/test_manifest.py | 12 +- 8 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 .github/skills/mattpocock-to-tickets/SKILL.md create mode 100644 .github/skills/mattpocock-to-tickets/agents/openai.yaml diff --git a/.github/INVENTORY.md b/.github/INVENTORY.md index 2756a0a3..e3f0f783 100644 --- a/.github/INVENTORY.md +++ b/.github/INVENTORY.md @@ -139,6 +139,7 @@ This file is the exact path inventory for the live GitHub Copilot catalog in thi - `.github/skills/mattpocock-setup-matt-pocock-skills/SKILL.md` - `.github/skills/mattpocock-tdd/SKILL.md` - `.github/skills/mattpocock-to-spec/SKILL.md` +- `.github/skills/mattpocock-to-tickets/SKILL.md` - `.github/skills/mattpocock-triage/SKILL.md` - `.github/skills/mattpocock-wayfinder/SKILL.md` - `.github/skills/mattpocock-writing-great-skills/SKILL.md` diff --git a/.github/skills/internal-gateway-execute-plans/scripts/plan_execution.py b/.github/skills/internal-gateway-execute-plans/scripts/plan_execution.py index ba3925f6..a6605981 100644 --- a/.github/skills/internal-gateway-execute-plans/scripts/plan_execution.py +++ b/.github/skills/internal-gateway-execute-plans/scripts/plan_execution.py @@ -27,10 +27,13 @@ class Finding: REQUIRED_PLAN_HEADINGS = ( "Goal", - "Repository Preflight", "Global Constraints", ) +PLAN_HEADING_ALIASES = { + "Repository Preflight": ("Repository Preflight", "Preflight"), +} + REQUIRED_STATUS_HEADINGS = ( "Status", "Plan", @@ -104,6 +107,15 @@ def validate_plan(path: Path, repo_root: Path) -> list[Finding]: Finding("missing-heading", f"Plan missing required heading: {required}") ) + for canonical, aliases in PLAN_HEADING_ALIASES.items(): + if not any(alias in heading_set for alias in aliases): + findings.append( + Finding( + "missing-heading", + f"Plan missing required heading: {canonical}", + ) + ) + if "Task" not in " ".join(headings) and "## Task" not in text: findings.append( Finding("missing-task", "Plan must contain at least one task heading") diff --git a/.github/skills/local-agent-sync-external-resources/references/managed-resources.yaml b/.github/skills/local-agent-sync-external-resources/references/managed-resources.yaml index 3ed667e2..41b171a9 100644 --- a/.github/skills/local-agent-sync-external-resources/references/managed-resources.yaml +++ b/.github/skills/local-agent-sync-external-resources/references/managed-resources.yaml @@ -111,6 +111,9 @@ sources: - upstream: skills/engineering/implement local: .github/skills/mattpocock-implement canonical_name: mattpocock-implement + - upstream: skills/engineering/to-tickets + local: .github/skills/mattpocock-to-tickets + canonical_name: mattpocock-to-tickets - upstream: skills/engineering/tdd local: .github/skills/mattpocock-tdd canonical_name: mattpocock-tdd @@ -261,10 +264,6 @@ watchlist: upstream_id: prototype local_owner: unmanaged reason: Referenced by wayfinder but outside the user-approved import scope; keep visible until explicitly approved or mapped to a local owner. - - source_family: mattpocock/skills - upstream_id: to-tickets - local_owner: unmanaged - reason: Referenced by setup-matt-pocock-skills but not installed in this repository; keep visible until explicitly approved or mapped to a local owner. - source_family: mattpocock/skills upstream_id: qa local_owner: unmanaged diff --git a/.github/skills/mattpocock-to-tickets/SKILL.md b/.github/skills/mattpocock-to-tickets/SKILL.md new file mode 100644 index 00000000..6584e92c --- /dev/null +++ b/.github/skills/mattpocock-to-tickets/SKILL.md @@ -0,0 +1,105 @@ +--- +name: mattpocock-to-tickets +description: Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker — edges as text in one file per ticket locally, or native blocking links on a real tracker. +disable-model-invocation: true +--- + +# To Tickets + +Break a plan, spec, or conversation into a set of **tickets** — tracer-bullet vertical slices, each declaring the tickets that **block** it. + +The issue tracker and triage label vocabulary should have been provided to you — run `/mattpocock-setup-matt-pocock-skills` if not. + +## Process + +### 1. Gather context + +Work from whatever is already in the conversation context. If the user passes a reference (a spec path, an issue number or URL) as an argument, fetch it and read its full body and comments. + +### 2. Explore the codebase (optional) + +If you have not already explored the codebase, do so to understand the current state of the code. Ticket titles and descriptions should use the project's domain glossary vocabulary, and respect ADRs in the area you're touching. + +Look for opportunities to prefactor the code to make the implementation easier. "Make the change easy, then make the easy change." + +### 3. Draft vertical slices + +Break the work into **tracer bullet** tickets. + + + +- Each slice cuts a narrow but COMPLETE path through every layer (schema, API, UI, tests) — vertical, NOT a horizontal slice of one layer +- A completed slice is demoable or verifiable on its own +- Each slice is sized to fit in a single fresh context window +- Any prefactoring should be done first + + + +Give each ticket its **blocking edges** — the other tickets that must complete before it can start. A ticket with no blockers can start immediately. + +**Wide refactors are the exception to vertical slicing.** A **wide refactor** is one mechanical change — rename a column, retype a shared symbol — whose **blast radius** fans across the whole codebase, so a single edit breaks thousands of call sites at once and no vertical slice can land green. Don't force it into a tracer bullet; sequence it as **expand–contract**. First expand: add the new form beside the old so nothing breaks. Then migrate the call sites over in batches sized by blast radius (per package, per directory), each batch its own ticket blocked by the expand, keeping CI green batch to batch because the old form still exists. Finally contract: delete the old form once no caller remains, in a ticket blocked by every migrate batch. When even the batches can't stay green alone, keep the sequence but let them share an integration branch that all block a final integrate-and-verify ticket — green is promised only there. + +### 4. Quiz the user + +Present the proposed breakdown as a numbered list. For each ticket, show: + +- **Title**: short descriptive name +- **Blocked by**: which other tickets (if any) must complete first +- **What it delivers**: the end-to-end behaviour this ticket makes work + +Ask the user: + +- Does the granularity feel right? (too coarse / too fine) +- Are the blocking edges correct — does each ticket only depend on tickets that genuinely gate it? +- Should any tickets be merged or split further? + +Iterate until the user approves the breakdown. + +### 5. Publish the tickets to the configured tracker + +Publish the approved tickets. **How** depends on the tracker `/mattpocock-setup-matt-pocock-skills` configured — the tickets are the same either way, only the shape of the blocking edges changes: + +- **Local files** → write one file per ticket under `.scratch//issues/-.md`, numbered from `01` in dependency order (blockers first). Each file's "Blocked by" lists the numbers/titles it depends on. Use the per-ticket file template below — one ticket per file, never a single combined file. +- **A real issue tracker (GitHub, Linear, …)** → publish one issue per ticket in dependency order (blockers first) so each ticket's blocking edges can reference real identifiers. Use the platform's native blocking / sub-issue relationship where it has one; otherwise set each ticket's "Blocked by" to the blocking issues. Apply the `ready-for-agent` triage label unless instructed otherwise — the tickets are agent-grabbable by construction. + +Work the **frontier**: any ticket whose blockers are all done. For a purely linear chain that means top to bottom. + +Do NOT close or modify any parent issue. + + + +# + +**What to build:** the end-to-end behaviour this ticket makes work, from the user's perspective — not a layer-by-layer implementation list. + +**Blocked by:** the numbers/titles of the tickets that gate this one, or "None — can start immediately". + +**Status:** ready-for-agent + +- [ ] Acceptance criterion 1 +- [ ] Acceptance criterion 2 + + + + + +## Parent + +A reference to the parent issue on the tracker (if the source was an existing issue, otherwise omit this section). + +## What to build + +The end-to-end behaviour this ticket makes work, from the user's perspective — not layer-by-layer implementation. + +## Acceptance criteria + +- [ ] Criterion 1 +- [ ] Criterion 2 + +## Blocked by + +- A reference to each blocking ticket, or "None — can start immediately". + + + +In either form, avoid specific file paths or code snippets — they go stale fast. Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it and note briefly that it came from a prototype. Trim to the decision-rich parts — not a working demo, just the important bits. diff --git a/.github/skills/mattpocock-to-tickets/agents/openai.yaml b/.github/skills/mattpocock-to-tickets/agents/openai.yaml new file mode 100644 index 00000000..24605a5d --- /dev/null +++ b/.github/skills/mattpocock-to-tickets/agents/openai.yaml @@ -0,0 +1,5 @@ +interface: + display_name: "To Tickets" + short_description: "Split a plan into tracer-bullet tickets" +policy: + allow_implicit_invocation: false diff --git a/tests/github/skills/internal-gateway-execute-plans/scripts/test_plan_execution.py b/tests/github/skills/internal-gateway-execute-plans/scripts/test_plan_execution.py index 6475e19c..0979e52a 100644 --- a/tests/github/skills/internal-gateway-execute-plans/scripts/test_plan_execution.py +++ b/tests/github/skills/internal-gateway-execute-plans/scripts/test_plan_execution.py @@ -34,6 +34,23 @@ def test_valid_plan_is_bound_to_its_sha256(valid_plan: Path) -> None: assert compute_sha256(valid_plan).startswith("sha256:") +def test_plan_accepts_preflight_heading_alias(tmp_path: Path) -> None: + (tmp_path / "AGENTS.md").write_text("# agents\n") + (tmp_path / ".github").mkdir() + staged = tmp_path / "tmp" / "superpowers" / "plans" + staged.mkdir(parents=True) + plan = staged / "preflight-alias.md" + plan.write_text( + "# Plan\n\n" + "## Goal\n\n- Validate the plan.\n\n" + "## Preflight\n\n- Use the repository validator.\n\n" + "## Global Constraints\n\n- Keep the plan unchanged.\n\n" + "## Task 1: Validate\n\n- [ ] Run the check.\n" + ) + + assert validate_plan(plan, repo_root=tmp_path) == [] + + def test_plan_outside_retained_plan_directory_is_rejected(tmp_path: Path) -> None: plan = tmp_path / "plan.md" plan.write_text("# Plan\n") diff --git a/tests/github/skills/local-agent-sync-external-resources/scripts/test_cli.py b/tests/github/skills/local-agent-sync-external-resources/scripts/test_cli.py index 689b26ba..1afabe17 100644 --- a/tests/github/skills/local-agent-sync-external-resources/scripts/test_cli.py +++ b/tests/github/skills/local-agent-sync-external-resources/scripts/test_cli.py @@ -69,7 +69,7 @@ def test_audit_does_not_fetch_or_write(repo_root: Path) -> None: payload = json.loads(result.stdout) assert payload["mode"] == "audit" assert payload["repository_changed"] is False - assert payload["managed_assets"] == 57 + assert payload["managed_assets"] == 58 def test_apply_refuses_dirty_target(tmp_path: Path) -> None: diff --git a/tests/github/skills/local-agent-sync-external-resources/scripts/test_manifest.py b/tests/github/skills/local-agent-sync-external-resources/scripts/test_manifest.py index bc07e3b0..044c0792 100644 --- a/tests/github/skills/local-agent-sync-external-resources/scripts/test_manifest.py +++ b/tests/github/skills/local-agent-sync-external-resources/scripts/test_manifest.py @@ -139,8 +139,8 @@ def test_live_manifest_preserves_declared_scope(repo_root: Path) -> None: / ".github/skills/local-agent-sync-external-resources/references/managed-resources.yaml" ) - assert len(manifest.assets) == 57 - assert len(manifest.watchlist) == 12 + assert len(manifest.assets) == 58 + assert len(manifest.watchlist) == 11 matt_source = next( source for source in manifest.sources if source.source_id == "mattpocock-skills" ) @@ -150,7 +150,12 @@ def test_live_manifest_preserves_declared_scope(repo_root: Path) -> None: item.upstream_id for item in manifest.watchlist if item.source_family == "mattpocock/skills" - } >= {"prototype", "to-tickets", "qa"} + } >= {"prototype", "qa"} + assert "to-tickets" not in { + item.upstream_id + for item in manifest.watchlist + if item.source_family == "mattpocock/skills" + } assert "triage" not in { item.upstream_id for item in manifest.watchlist @@ -162,6 +167,7 @@ def test_live_manifest_preserves_declared_scope(repo_root: Path) -> None: "mattpocock-codebase-design", "mattpocock-improve-codebase-architecture", "mattpocock-implement", + "mattpocock-to-tickets", "mattpocock-tdd", "mattpocock-to-spec", "mattpocock-setup-matt-pocock-skills", From 6bd9ea10eec137ebef22bf8e19349a0e77fef418 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 22:13:13 +0200 Subject: [PATCH 06/23] feat: enhance chat projection and output structure for internal review agents, add tests for consistency and completeness --- .../internal-gateway-review-code.agent.md | 62 ++++++--------- .../internal-gateway-review-generic.agent.md | 56 ++++++------- .../internal-review-ai-resources.prompt.md | 4 + .../internal-review-ai-resources/SKILL.md | 8 +- .../agents/openai.yaml | 2 +- .../references/report-contract.md | 79 +++++++++++-------- .../review-usefulness-replay-fixture.md | 34 ++------ .github/skills/internal-review-code/SKILL.md | 14 +++- .../internal-review-code/agents/openai.yaml | 2 +- .../test_review_chat_projection_contract.py | 58 ++++++++++++++ .../test_report_contract.py | 49 +++++++++++- ...ew_code_simplification_routing_contract.py | 18 +++++ 12 files changed, 241 insertions(+), 145 deletions(-) create mode 100644 tests/github/agents/test_review_chat_projection_contract.py diff --git a/.github/agents/internal-gateway-review-code.agent.md b/.github/agents/internal-gateway-review-code.agent.md index b33b3053..134421dd 100644 --- a/.github/agents/internal-gateway-review-code.agent.md +++ b/.github/agents/internal-gateway-review-code.agent.md @@ -63,53 +63,35 @@ Before presenting the final report, pressure-test the review with `internal-gate If the counter-analysis exposes a material gap, reopen the review and return `Verdict: NEEDS INVESTIGATION` instead of presenting an unsupported approval or request-changes verdict. -## Output Format +## User-facing chat projection -Categorize every finding: +Keep the full review record and counter-analysis internal. In normal chat, +project only the decision-relevant result and match the user's chat language. -**Critical** - Must fix before merge (security vulnerability, data loss risk, broken functionality) +Start with exactly four fields in this order: -**Important** - Should fix before merge (missing test, wrong abstraction, poor error handling) +- `🔎`: localized verdict and counts by severity. +- `📌`: one sentence explaining why that verdict follows. +- `🧪`: reviewed scope, completed validation, and any material evidence gap. +- `👉`: one user action and the consequence of accepting it. -**Suggestion** - Consider for improvement (naming, code style, optional optimization) +Map Critical findings to `B` identifiers, Important findings to `I` +identifiers, and Suggestions to `S` identifiers; show every blocking and important finding; +consolidate equivalent findings and list all affected locations under one identifier. +Keep suggestions compact. -## Review Output Template +Every material finding contains `Location`, `Evidence`, `Impact`, and +`Correction`. Add `Expected verification` when closure is not obvious. +Mark uncertainty inline as `to confirm`; do not create another severity. -```markdown -## Review Summary +Do not print empty sections, the internal review gate, the counter-analysis +record, or a decision trace. Surface those facts only through the verdict or +evidence-gap field when they change the user's decision. -**Verdict:** APPROVE | REQUEST CHANGES | NEEDS INVESTIGATION - -**Overview:** [1-2 sentences summarizing the change and overall assessment] - -### Critical Issues -- [File:line] [Description, impact, and recommended fix] - -### Important Issues -- [File:line] [Description, impact, and recommended fix] - -### Suggestions -- [File:line] [Description and recommended fix when useful] - -### Sound Decisions / Preserved Conventions -- [Evidence-backed note explaining why a risky-looking choice is acceptable or why a local convention should be preserved] - -### Verification Story -- Tests reviewed: [yes/no, observations] -- Build verified: [yes/no] -- Security checked: [yes/no, observations] -- Validation missing: [specific command, test, or review gap] - -### Critical Counter-Analysis Result -- Result: [passed/reopened] -- Notes: [severity changes, false positives removed, missing evidence, or residual uncertainty] - -### Residual Risk -- [Specific remaining risk, or "No material residual risk found within reviewed scope."] - -### Next Decision -- [accept | patch | investigate | accept with risk] -``` +For request-changes results, the action may invite the user to request a +separate follow-up for named finding IDs, but it must state that no changes were applied. +Approval results state that no user action is required. +Investigation results ask for the exact missing evidence or authorization. ## Rules diff --git a/.github/agents/internal-gateway-review-generic.agent.md b/.github/agents/internal-gateway-review-generic.agent.md index 825f44e1..11c91c86 100644 --- a/.github/agents/internal-gateway-review-generic.agent.md +++ b/.github/agents/internal-gateway-review-generic.agent.md @@ -57,46 +57,36 @@ Before presenting the final report, pressure-test findings with `internal-gatewa If the counter-analysis exposes a material gap, reopen the review and return `review gate: reopen` instead of presenting an unsupported no-finding claim or final verdict. -## Output Format +## User-facing chat projection -Use this report shape: +Keep the full review record and counter-analysis internal. In normal chat, +project only the decision-relevant result and match the user's chat language. -```markdown -## Review Summary +Start with exactly four fields in this order: -**Verdict:** APPROVE | REQUEST CHANGES | NEEDS INVESTIGATION +- `🔎`: localized verdict and counts by severity. +- `📌`: one sentence explaining why that verdict follows. +- `🧪`: reviewed scope, completed validation, and any material evidence gap. +- `👉`: one user action and the consequence of accepting it. -**Review Gate:** satisfied | reopen +Map Critical findings to `B` identifiers, Important findings to `I` +identifiers, and Suggestions to `S` identifiers; show every blocking and important finding; +consolidate equivalent findings and list all affected locations under one identifier. +Keep suggestions compact. -**Overview:** [1-2 sentences summarizing the target, reviewed surface, and overall assessment] +Every material finding contains `Location`, `Evidence`, `Impact`, and +`Correction`. Add `Expected verification` when closure is not obvious. +Mark uncertainty inline as `to confirm`; do not create another severity. -### Blocking Findings -- [Path or evidence point] [Finding, impact, severity, confidence, and recommended fix direction] +Do not print empty sections, the internal review gate, the counter-analysis +record, or a decision trace. Surface those facts only through the verdict or +evidence-gap field when they change the user's decision. Keep `review gate: +reopen` as internal state. -### Important Findings -- [Path or evidence point] [Finding, impact, severity, confidence, and recommended fix direction] - -### Suggestions -- [Path or evidence point] [Improvement that is useful but not blocking] - -### Sound Decisions / Preserved Conventions -- [Evidence-backed note explaining why a risky-looking choice is acceptable or why a local convention should be preserved] - -### Verification Story -- Evidence reviewed: [files, diff, prompt, catalog, workflow, or retained package] -- Validation reviewed: [commands or checks already run] -- Validation missing: [specific command, check, or manual review gap] - -### Critical Counter-Analysis Result -- Result: [passed/reopened] -- Notes: [severity changes, false positives removed, missing evidence, or residual uncertainty] - -### Residual Risk -- [Specific remaining risk, or "No material residual risk found within reviewed scope."] - -### Next Decision -- [accept | patch | investigate | plan separately | accept with risk] -``` +For request-changes results, the action may invite the user to request a +separate follow-up for named finding IDs, but it must state that no changes were applied. +Approval results state that no user action is required. +Investigation results ask for the exact missing evidence or authorization. ## Review Rules diff --git a/.github/prompts/internal-review-ai-resources.prompt.md b/.github/prompts/internal-review-ai-resources.prompt.md index dbaed877..43787636 100644 --- a/.github/prompts/internal-review-ai-resources.prompt.md +++ b/.github/prompts/internal-review-ai-resources.prompt.md @@ -28,6 +28,10 @@ ${input:constraints:List no-touch areas, rollout constraints, evidence limits, o Output preference: ${input:output:Write chat-only, retained report under tmp/, or infer from target size} +For `chat-only`, use the adaptive chat projection owned by the selected review +lane. For retained output, preserve the retained report contract and return a +compact chat summary with the retained path. + Use these repository sources first: - [AGENTS.md](../../AGENTS.md) diff --git a/.github/skills/internal-review-ai-resources/SKILL.md b/.github/skills/internal-review-ai-resources/SKILL.md index e56340ad..bc859a7f 100644 --- a/.github/skills/internal-review-ai-resources/SKILL.md +++ b/.github/skills/internal-review-ai-resources/SKILL.md @@ -100,9 +100,11 @@ Bundle coverage rules: see `references/review-profiles.md` 'bundle minimum evide ## Output -Required sections: see `references/report-contract.md` 'Required sections'. The review -output should always be decision-useful and include an explicit no-findings result -when no material findings exist. +- Chat projection: see `references/report-contract.md` 'Chat projection'. +- Retained output: see `references/report-contract.md` 'Retained output'. + +The review output should always be decision-useful and include an explicit +no-findings result when no material findings exist. ## Validation diff --git a/.github/skills/internal-review-ai-resources/agents/openai.yaml b/.github/skills/internal-review-ai-resources/agents/openai.yaml index 08545262..93fb32d7 100644 --- a/.github/skills/internal-review-ai-resources/agents/openai.yaml +++ b/.github/skills/internal-review-ai-resources/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Review AI Resources" short_description: "Review internal AI resource bundles" - default_prompt: "Use $internal-review-ai-resources to assess an AI resource, bundle, or catalog path and recommend keep, patch, split, or retire actions." + default_prompt: "Use $internal-review-ai-resources to assess an AI resource, bundle, or catalog path, use the adaptive chat projection for the user-facing result, and recommend keep, patch, split, or retire actions." diff --git a/.github/skills/internal-review-ai-resources/references/report-contract.md b/.github/skills/internal-review-ai-resources/references/report-contract.md index 2ea2c725..4db1d717 100644 --- a/.github/skills/internal-review-ai-resources/references/report-contract.md +++ b/.github/skills/internal-review-ai-resources/references/report-contract.md @@ -47,25 +47,45 @@ Use one primary action per finding or summary line: - `retained-report`: retained output under `tmp/` only when the user asked for it or the target is already a retained package -## Adaptive layout patterns - -Use the shortest layout that still supports the user's decision. Section names -may vary, but the final answer must preserve the decision logic. - -For normal AI-resource reviews, prefer: - -1. verdict with confidence -2. material findings, defect-first -3. evidence digest -4. decision trace -5. next step -6. residual risk - -For high-severity findings, lead with findings, then impact and next step. - -For no-finding or low-finding reviews, make the decision logic explicit with a -verdict, evidence digest, decision trace, next step, and residual risk. Do not -invent extra findings to make a small review look more substantial. +## Chat projection + +For `chat-only` reviews, use the shortest projection that still supports the +user's decision. Start with exactly four fields in this order: + +- `🔎`: a localized verdict and counts by severity. +- `📌`: one sentence explaining why that verdict follows. +- `🧪`: reviewed scope, completed validation, and any material evidence gap. +- `👉`: one user action and the consequence of accepting it. + +Visible labels match the user's chat language. Canonical uppercase decision +values and evidence labels are internal by default. Map Critical findings to +`B` identifiers, Important findings to `I` identifiers, and Suggestions to +`S` identifiers. Show every blocking and important finding, consolidate +equivalent findings, and keep suggestions compact. + +Every material finding contains `Location`, `Evidence`, `Impact`, and +`Correction`. Add `Expected verification` when closure is not obvious. Mark +uncertainty inline as `to confirm` and do not create another severity. + +Keep counter-analysis records, review gates, decision traces, and internal +evidence digests hidden unless they materially change the verdict. Missing +proof stays visible through `🧪`. The final action names one user response and +states its consequence; a review never implies that a patch was already +applied. + +## Retained output + +Use retained output only when the user asks for it or the selected target is a +retained review package. Preserve profile-proportional detail, evidence +labels, evidence digest, decision trace, validation gaps, and residual risk +when the retained artifact needs them. Retained output may keep canonical +uppercase decision values and internal evidence labels. + +Retained review completion returns a compact chat card plus the retained path. +The chat summary must remain distinct from the retained report and must not +replace its evidence, decision trace, validation gaps, or residual-risk +detail. Keep retained reports under `tmp/` and preserve their existing file +layout. ## Evidence compression @@ -95,23 +115,12 @@ When a proof cannot be run or loaded, report: Partial evidence may support a verdict, but the unavailable focused proof stays visible as residual risk. -## Required sections - -Every final review should include: - -1. selected profile and target -2. findings first, or an explicit no-findings result -3. evidence labels for each material claim -4. evidence digest -5. decision trace -6. decision or recommended next action -7. validation path or explicit evidence gap -8. residual risk - -Decision trace and evidence digest are expected for normal reviews; see Adaptive layout patterns. +## Conditional requirements -Small reviews may merge sections only when the verdict, evidence digest, -decision trace, next action, and residual risk remain understandable. +Chat-only output follows `Chat projection`. Retained output follows `Retained +output` and returns the compact chat card with the retained path. Use the +selected profile and target as internal review context, and surface them in +chat only when they change the user's decision. ## Completeness pass diff --git a/.github/skills/internal-review-ai-resources/references/review-usefulness-replay-fixture.md b/.github/skills/internal-review-ai-resources/references/review-usefulness-replay-fixture.md index 0cdc02d4..2ffd7634 100644 --- a/.github/skills/internal-review-ai-resources/references/review-usefulness-replay-fixture.md +++ b/.github/skills/internal-review-ai-resources/references/review-usefulness-replay-fixture.md @@ -30,34 +30,12 @@ without becoming long reports. ## Compressed Output Shape ```markdown -## Verdict +🔎 **Esito:** approvabile con un miglioramento facoltativo. +📌 **Perché:** il prompt pack passa il validator, ma il profilo non ha una regressione dedicata. +🧪 **Evidenza:** validator e sync verificati; pytest focalizzato non disponibile. +👉 **Azione richiesta:** nessuna correzione obbligatoria; chiedi una fase separata per aggiungere S1 se vuoi ridurre il rischio. -No immediate runtime break observed. The live `coach-personale` pack passes the -updated validator, but the tightened profile lacks dedicated regression -coverage. +## 💡 Suggerimenti (1) -## Findings - -Low: `coach-personale` profile rules changed without a focused pass/fail test. - -## Evidence Digest - -Checked branch diff, validator helper, live prompt pack, nearby tests, and -inventory/sync references. - -## Decision Trace - -Runtime break is not supported because the live pack passes. Sync drift is not -supported because the changed surface is the validator helper and catalog -references remain present. The supported risk is test protection for the new -profile contract. - -## Next Step - -Add focused `coach-personale` validator tests for the required tokens and -support files. - -## Residual Risk - -Focused pytest execution was unavailable in the active environment. +- **S1:** aggiungere test pass/fail specifici per il profilo `coach-personale`. ``` diff --git a/.github/skills/internal-review-code/SKILL.md b/.github/skills/internal-review-code/SKILL.md index 52d2a910..f11341d3 100644 --- a/.github/skills/internal-review-code/SKILL.md +++ b/.github/skills/internal-review-code/SKILL.md @@ -25,6 +25,11 @@ repository-owned entrypoint and the local boundaries below. It must not redefine the core's five axes, review order, approval standard, finding categories, structural remedies, or verification posture. +The core owns review reasoning and severity. This wrapper owns the public chat projection +and repository-facing boundaries. The projection may reorder and compress supported +evidence, but it must not introduce another review axis, severity model, approval +standard, or remediation workflow. + ## Boundaries - Review only the requested code surface and the supporting tests, spec, task, @@ -38,8 +43,8 @@ categories, structural remedies, or verification posture. change the review. - Do not load `awesome-copilot-security-review` automatically. Use it only when the user explicitly asks for security-specialist depth. -- Do not add another severity model, review lens set, workflow, or output - template around the core. +- Do not redefine the core review model. Project its result through the same + `🔎`, `📌`, `🧪`, and `👉` semantics used by the code gateway. - If the requested fixed point, diff, or code target is missing, invalid, or empty, stop at the core preflight and state the evidence gap. - If no spec or task context exists, follow the core no-spec path and state the @@ -63,3 +68,8 @@ Before reporting the review, confirm that: - security-specialist escalation was used only on explicit user request; - simplification is surfaced only as a separate follow-up backed by a concrete readability or complexity finding; - `addyosmani-code-simplification` was not loaded or executed during review. +- all Critical and Important findings remain visible; +- `B`/`I`/`S` identifiers map to the core finding categories; +- material findings include concrete evidence, impact, correction, and expected verification; +- the projection contains one boundary-safe user action; +- internal counter-analysis details stay hidden unless they alter the verdict. diff --git a/.github/skills/internal-review-code/agents/openai.yaml b/.github/skills/internal-review-code/agents/openai.yaml index b376c03f..bc6bae74 100644 --- a/.github/skills/internal-review-code/agents/openai.yaml +++ b/.github/skills/internal-review-code/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Review Code" short_description: "Repository wrapper for five-axis code review" - default_prompt: "Use $internal-review-code as the repository wrapper, follow $addyosmani-code-review-and-quality as the full review core, and use $awesome-copilot-security-review only if the user explicitly asks for security-specialist depth." + default_prompt: "Use $internal-review-code as the repository wrapper, follow $addyosmani-code-review-and-quality as the full review core, return the result through the adaptive chat projection with one user action, and state that remediation requires a separate follow-up; use $awesome-copilot-security-review only if the user explicitly asks for security-specialist depth." diff --git a/tests/github/agents/test_review_chat_projection_contract.py b/tests/github/agents/test_review_chat_projection_contract.py new file mode 100644 index 00000000..72c470b8 --- /dev/null +++ b/tests/github/agents/test_review_chat_projection_contract.py @@ -0,0 +1,58 @@ +from pathlib import Path + +REPO_ROOT = next( + parent + for parent in Path(__file__).resolve().parents + if (parent / "AGENTS.md").exists() and (parent / ".github").exists() +) +AGENT_PATHS = ( + REPO_ROOT / ".github/agents/internal-gateway-review-code.agent.md", + REPO_ROOT / ".github/agents/internal-gateway-review-generic.agent.md", +) +CARD_MARKERS = ("🔎", "📌", "🧪", "👉") +MATERIAL_FIELDS = ( + "Location", + "Evidence", + "Impact", + "Correction", + "Expected verification", +) +LEGACY_PUBLIC_SECTIONS = ( + "### Verification Story", + "### Critical Counter-Analysis Result", + "### Residual Risk", + "### Next Decision", + "**Review Gate:**", +) + + +def _agent_texts() -> tuple[str, ...]: + return tuple(path.read_text(encoding="utf-8") for path in AGENT_PATHS) + + +def test_review_agents_define_the_same_public_card_fields() -> None: + for text in _agent_texts(): + for marker in CARD_MARKERS: + assert marker in text + assert "match the user's chat language" in text + assert "one user action" in text + + +def test_review_agents_define_complete_material_findings() -> None: + for text in _agent_texts(): + for field in MATERIAL_FIELDS: + assert field in text + assert "consolidate equivalent findings" in text + assert "show every blocking and important finding" in text + + +def test_review_agents_hide_legacy_internal_sections() -> None: + for text in _agent_texts(): + for heading in LEGACY_PUBLIC_SECTIONS: + assert heading not in text + + +def test_review_agents_keep_fixing_in_a_separate_follow_up() -> None: + for text in _agent_texts(): + assert "separate follow-up" in text + assert "no changes were applied" in text diff --git a/tests/github/skills/internal-review-ai-resources/test_report_contract.py b/tests/github/skills/internal-review-ai-resources/test_report_contract.py index bd0bdad4..1ffd66ea 100644 --- a/tests/github/skills/internal-review-ai-resources/test_report_contract.py +++ b/tests/github/skills/internal-review-ai-resources/test_report_contract.py @@ -10,18 +10,31 @@ REPO_ROOT / ".github/skills/internal-review-ai-resources/references/report-contract.md" ) +FIXTURE_PATH = ( + REPO_ROOT + / ".github/skills/internal-review-ai-resources/references" + / "review-usefulness-replay-fixture.md" +) +AGENT_PATH = ( + REPO_ROOT + / ".github/skills/internal-review-ai-resources/agents/openai.yaml" +) +PROMPT_PATH = REPO_ROOT / ".github/prompts/internal-review-ai-resources.prompt.md" REVIEW_PROFILES_PATH = ( REPO_ROOT / ".github/skills/internal-review-ai-resources/references/review-profiles.md" ) +CARD_MARKERS = ("🔎", "📌", "🧪", "👉") def test_skill_output_points_to_report_contract_required_sections() -> None: skill_text = SKILL_PATH.read_text() contract_text = REPORT_CONTRACT_PATH.read_text() - assert "## Required sections" in contract_text - assert "Required sections: see `references/report-contract.md`" in skill_text + assert "## Chat projection" in contract_text + assert "## Retained output" in contract_text + assert "Chat projection: see `references/report-contract.md`" in skill_text + assert "Retained output: see `references/report-contract.md`" in skill_text def test_profile_names_are_consistent_across_bundle() -> None: @@ -40,3 +53,35 @@ def test_decision_vocabulary_uses_patch_not_revise() -> None: assert "PATCH" in contract_text assert "revise" not in skill_text.lower().split("review")[0] or True assert "`revise`" not in skill_text + + +def test_report_contract_separates_chat_from_retained_output() -> None: + contract_text = REPORT_CONTRACT_PATH.read_text(encoding="utf-8") + + assert "## Chat projection" in contract_text + assert "## Retained output" in contract_text + assert "retained path" in contract_text + for marker in CARD_MARKERS: + assert marker in contract_text + + +def test_replay_fixture_uses_the_adaptive_chat_shape() -> None: + fixture_text = FIXTURE_PATH.read_text(encoding="utf-8") + + for marker in CARD_MARKERS: + assert marker in fixture_text + for legacy_heading in ( + "## Evidence Digest", + "## Decision Trace", + "## Residual Risk", + ): + assert legacy_heading not in fixture_text + + +def test_direct_entrypoints_preserve_chat_and_retained_distinction() -> None: + runtime_text = AGENT_PATH.read_text(encoding="utf-8") + prompt_text = PROMPT_PATH.read_text(encoding="utf-8") + + assert "adaptive chat projection" in runtime_text + assert "chat-only" in prompt_text + assert "retained path" in prompt_text diff --git a/tests/github/skills/internal-review-code/test_review_code_simplification_routing_contract.py b/tests/github/skills/internal-review-code/test_review_code_simplification_routing_contract.py index 2b8de6b2..6aab23a8 100644 --- a/tests/github/skills/internal-review-code/test_review_code_simplification_routing_contract.py +++ b/tests/github/skills/internal-review-code/test_review_code_simplification_routing_contract.py @@ -7,6 +7,7 @@ ) SKILL_PATH = REPO_ROOT / ".github/skills/internal-review-code/SKILL.md" AGENT_PATH = REPO_ROOT / ".github/skills/internal-review-code/agents/openai.yaml" +CARD_MARKERS = ("🔎", "📌", "🧪", "👉") def test_code_review_routes_simplification_as_a_separate_follow_up() -> None: @@ -22,3 +23,20 @@ def test_code_review_routes_simplification_as_a_separate_follow_up() -> None: def test_code_review_agent_does_not_preload_simplification() -> None: assert "addyosmani-code-simplification" not in AGENT_PATH.read_text() + + +def test_code_review_wrapper_owns_only_the_public_chat_projection() -> None: + skill_text = SKILL_PATH.read_text(encoding="utf-8") + + assert "The core owns review reasoning and severity" in skill_text + assert "This wrapper owns the public chat projection" in skill_text + for marker in CARD_MARKERS: + assert marker in skill_text + assert "retained review engine" not in skill_text + + +def test_code_review_runtime_prompt_requests_the_adaptive_projection() -> None: + prompt_text = AGENT_PATH.read_text(encoding="utf-8") + + assert "adaptive chat projection" in prompt_text + assert "separate follow-up" in prompt_text From 10ebc6e0e73e68b501162fc11791a7716f0c7861 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 22:31:29 +0200 Subject: [PATCH 07/23] Refactor PDF handling and documentation updates - Enhanced PDF form field documentation in forms.md to clarify checkbox, radio group, and multiple choice field structures. - Improved reference.md with detailed comments on PDF manipulation using pypdfium2 and pdf-lib. - Updated scripts in anthropic-pdf, anthropic-pptx, and anthropic-xlsx to ensure executable permissions. - Revised domain.md and issue-tracker documentation to reflect accurate command references and improve clarity. - Adjusted superpowers-brainstorming SKILL.md to streamline the questioning process and enhance the design approval workflow. - Updated GLOSSARY.md to correct skill references and improve consistency across documentation. --- .github/skills/anthropic-docx/SKILL.md | 6 +- .../skills/anthropic-docx/scripts/__init__.py | 0 .../anthropic-docx/scripts/accept_changes.py | 0 .../skills/anthropic-docx/scripts/comment.py | 0 .../anthropic-docx/scripts/merge_runs.py | 0 .../anthropic-docx/scripts/office/validate.py | 0 .github/skills/anthropic-pdf/SKILL.md | 56 ++++++++++-- .github/skills/anthropic-pdf/forms.md | 12 ++- .github/skills/anthropic-pdf/reference.md | 91 +++++++++++++++++-- .../scripts/extract_form_structure.py | 0 .../anthropic-pptx/scripts/add_slide.py | 0 .../skills/anthropic-pptx/scripts/clean.py | 0 .../anthropic-pptx/scripts/office/validate.py | 0 .../anthropic-pptx/scripts/thumbnail.py | 0 .../anthropic-xlsx/scripts/office/validate.py | 0 .../skills/anthropic-xlsx/scripts/recalc.py | 0 .../domain.md | 2 +- .../issue-tracker-github.md | 4 +- .../issue-tracker-gitlab.md | 4 +- .../issue-tracker-local.md | 2 +- .github/skills/mattpocock-triage/SKILL.md | 2 +- .github/skills/mattpocock-wayfinder/SKILL.md | 4 +- .../GLOSSARY.md | 2 +- .../skills/superpowers-brainstorming/SKILL.md | 70 ++++---------- 24 files changed, 172 insertions(+), 83 deletions(-) mode change 100644 => 100755 .github/skills/anthropic-docx/scripts/__init__.py mode change 100644 => 100755 .github/skills/anthropic-docx/scripts/accept_changes.py mode change 100644 => 100755 .github/skills/anthropic-docx/scripts/comment.py mode change 100644 => 100755 .github/skills/anthropic-docx/scripts/merge_runs.py mode change 100644 => 100755 .github/skills/anthropic-docx/scripts/office/validate.py mode change 100644 => 100755 .github/skills/anthropic-pdf/scripts/extract_form_structure.py mode change 100644 => 100755 .github/skills/anthropic-pptx/scripts/add_slide.py mode change 100644 => 100755 .github/skills/anthropic-pptx/scripts/clean.py mode change 100644 => 100755 .github/skills/anthropic-pptx/scripts/office/validate.py mode change 100644 => 100755 .github/skills/anthropic-pptx/scripts/thumbnail.py mode change 100644 => 100755 .github/skills/anthropic-xlsx/scripts/office/validate.py mode change 100644 => 100755 .github/skills/anthropic-xlsx/scripts/recalc.py diff --git a/.github/skills/anthropic-docx/SKILL.md b/.github/skills/anthropic-docx/SKILL.md index 2b1fe9c2..7f4fedb7 100644 --- a/.github/skills/anthropic-docx/SKILL.md +++ b/.github/skills/anthropic-docx/SKILL.md @@ -10,7 +10,7 @@ A `.docx` is a ZIP archive of XML files. Choose your approach by task: | Task | Approach | |---|---| -| **Create** a new document | Write a `anthropic-docx` (npm) script — see gotchas below | +| **Create** a new document | Write a `docx` (npm) script — see gotchas below | | **Edit** an existing document | `unzip` → edit `word/document.xml` → `zip` (docx-js cannot open existing files) | | **Read** content | `pandoc -t markdown file.docx` | @@ -18,7 +18,7 @@ A `.docx` is a ZIP archive of XML files. Choose your approach by task: ## Creating with docx-js — gotchas -`anthropic-docx` is preinstalled — do not run `npm install` first; write the script and `require('docx')` directly. Only if that require fails: `npm install docx`. The model knows the API; these are the footguns: +`docx` is preinstalled — do not run `npm install` first; write the script and `require('docx')` directly. Only if that require fails: `npm install docx`. The model knows the API; these are the footguns: - **Page size defaults to A4.** For US Letter set `page: { size: { width: 12240, height: 15840 } }` (DXA; 1440 = 1″). - **Landscape:** pass portrait dimensions and `orientation: PageOrientation.LANDSCAPE` — docx-js swaps width/height internally. @@ -88,4 +88,4 @@ The script writes `comments.xml`, `commentsExtended.xml`, `commentsIds.xml`, `co ## Dependencies -`anthropic-docx` (npm, preinstalled — install only if `require('docx')` fails) · `pandoc` · LibreOffice (`soffice`) · `pdftoppm` (Poppler) +`docx` (npm, preinstalled — install only if `require('docx')` fails) · `pandoc` · LibreOffice (`soffice`) · `pdftoppm` (Poppler) diff --git a/.github/skills/anthropic-docx/scripts/__init__.py b/.github/skills/anthropic-docx/scripts/__init__.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-docx/scripts/accept_changes.py b/.github/skills/anthropic-docx/scripts/accept_changes.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-docx/scripts/comment.py b/.github/skills/anthropic-docx/scripts/comment.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-docx/scripts/merge_runs.py b/.github/skills/anthropic-docx/scripts/merge_runs.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-docx/scripts/office/validate.py b/.github/skills/anthropic-docx/scripts/office/validate.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-pdf/SKILL.md b/.github/skills/anthropic-pdf/SKILL.md index 5481d699..5cd70b0d 100644 --- a/.github/skills/anthropic-pdf/SKILL.md +++ b/.github/skills/anthropic-pdf/SKILL.md @@ -1,6 +1,7 @@ --- name: anthropic-pdf -description: "Use when tasks involve reading, creating, or reviewing PDF files where rendering and layout matter; prefer visual checks by rendering pages (Poppler) and use Python tools such as `reportlab`, `pdfplumber`, and `pypdf` for generation and extraction." +description: Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill. +license: Proprietary. LICENSE.txt has complete terms --- # PDF Processing Guide @@ -14,9 +15,11 @@ This guide covers essential PDF processing operations using Python libraries and ```python from pypdf import PdfReader, PdfWriter +# Read a PDF reader = PdfReader("document.pdf") print(f"Pages: {len(reader.pages)}") +# Extract text text = "" for page in reader.pages: text += page.extract_text() @@ -62,13 +65,11 @@ print(f"Creator: {meta.creator}") #### Rotate Pages ```python -from pypdf import PdfReader, PdfWriter - reader = PdfReader("input.pdf") writer = PdfWriter() page = reader.pages[0] -page.rotate(90) +page.rotate(90) # Rotate 90 degrees clockwise writer.add_page(page) with open("rotated.pdf", "wb") as output: @@ -107,10 +108,11 @@ with pdfplumber.open("document.pdf") as pdf: for page in pdf.pages: tables = page.extract_tables() for table in tables: - if table: + if table: # Check if table is not empty df = pd.DataFrame(table[1:], columns=table[0]) all_tables.append(df) +# Combine all tables if all_tables: combined_df = pd.concat(all_tables, ignore_index=True) combined_df.to_excel("extracted_tables.xlsx", index=False) @@ -126,10 +128,14 @@ from reportlab.pdfgen import canvas c = canvas.Canvas("hello.pdf", pagesize=letter) width, height = letter +# Add text c.drawString(100, height - 100, "Hello World!") c.drawString(100, height - 120, "This is a PDF created with reportlab") + +# Add a line c.line(100, height - 140, 400, height - 140) +# Save c.save() ``` @@ -143,6 +149,7 @@ doc = SimpleDocTemplate("report.pdf", pagesize=letter) styles = getSampleStyleSheet() story = [] +# Add content title = Paragraph("Report Title", styles['Title']) story.append(title) story.append(Spacer(1, 12)) @@ -151,15 +158,17 @@ body = Paragraph("This is the body of the report. " * 20, styles['Normal']) story.append(body) story.append(PageBreak()) +# Page 2 story.append(Paragraph("Page 2", styles['Heading1'])) story.append(Paragraph("Content for page 2", styles['Normal'])) +# Build PDF doc.build(story) ``` #### Subscripts and Superscripts -**IMPORTANT**: Never use Unicode subscript/superscript characters in ReportLab PDFs. The built-in fonts do not include these glyphs, causing them to render as solid black boxes. +**IMPORTANT**: Never use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉, ⁰¹²³⁴⁵⁶⁷⁸⁹) in ReportLab PDFs. The built-in fonts do not include these glyphs, causing them to render as solid black boxes. Instead, use ReportLab's XML markup tags in Paragraph objects: ```python @@ -168,32 +177,54 @@ from reportlab.lib.styles import getSampleStyleSheet styles = getSampleStyleSheet() +# Subscripts: use tag chemical = Paragraph("H2O", styles['Normal']) + +# Superscripts: use tag squared = Paragraph("x2 + y2", styles['Normal']) ``` +For canvas-drawn text (not Paragraph objects), manually adjust font the size and position rather than using Unicode subscripts/superscripts. + ## Command-Line Tools ### pdftotext (poppler-utils) ```bash +# Extract text pdftotext input.pdf output.txt + +# Extract text preserving layout pdftotext -layout input.pdf output.txt -pdftotext -f 1 -l 5 input.pdf output.txt + +# Extract specific pages +pdftotext -f 1 -l 5 input.pdf output.txt # Pages 1-5 ``` ### qpdf ```bash +# Merge PDFs qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf + +# Split pages qpdf input.pdf --pages . 1-5 -- pages1-5.pdf qpdf input.pdf --pages . 6-10 -- pages6-10.pdf -qpdf input.pdf output.pdf --rotate=+90:1 + +# Rotate pages +qpdf input.pdf output.pdf --rotate=+90:1 # Rotate page 1 by 90 degrees + +# Remove password qpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf ``` ### pdftk (if available) ```bash +# Merge pdftk file1.pdf file2.pdf cat output merged.pdf + +# Split pdftk input.pdf burst + +# Rotate pdftk input.pdf rotate 1east output rotated.pdf ``` @@ -201,11 +232,14 @@ pdftk input.pdf rotate 1east output rotated.pdf ### Extract Text from Scanned PDFs ```python +# Requires: pip install pytesseract pdf2image import pytesseract from pdf2image import convert_from_path +# Convert PDF to images images = convert_from_path('scanned.pdf') +# OCR each page text = "" for i, image in enumerate(images): text += f"Page {i+1}:\n" @@ -219,8 +253,10 @@ print(text) ```python from pypdf import PdfReader, PdfWriter +# Create watermark (or load existing) watermark = PdfReader("watermark.pdf").pages[0] +# Apply to all pages reader = PdfReader("document.pdf") writer = PdfWriter() @@ -234,7 +270,10 @@ with open("watermarked.pdf", "wb") as output: ### Extract Images ```bash +# Using pdfimages (poppler-utils) pdfimages -j input.pdf output_prefix + +# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc. ``` ### Password Protection @@ -247,6 +286,7 @@ writer = PdfWriter() for page in reader.pages: writer.add_page(page) +# Add password writer.encrypt("userpassword", "ownerpassword") with open("encrypted.pdf", "wb") as output: diff --git a/.github/skills/anthropic-pdf/forms.md b/.github/skills/anthropic-pdf/forms.md index 5f634ab9..6e7e1e0d 100644 --- a/.github/skills/anthropic-pdf/forms.md +++ b/.github/skills/anthropic-pdf/forms.md @@ -14,6 +14,7 @@ If the PDF has fillable form fields: "rect": ([left, bottom, right, top] bounding box in PDF coordinates, y=0 is the bottom of the page), "type": ("text", "checkbox", "radio_group", or "choice"), }, + // Checkboxes have "checked_value" and "unchecked_value" properties: { "field_id": (unique ID for the field), "page": (page number, 1-based), @@ -21,6 +22,7 @@ If the PDF has fillable form fields: "checked_value": (Set the field to this value to check the checkbox), "unchecked_value": (Set the field to this value to uncheck the checkbox), }, + // Radio groups have a "radio_options" list with the possible choices. { "field_id": (unique ID for the field), "page": (page number, 1-based), @@ -30,8 +32,10 @@ If the PDF has fillable form fields: "value": (set the field to this value to select this radio option), "rect": (bounding box for the radio button for this option) }, + // Other radio options ] }, + // Multiple choice fields have a "choice_options" list with the possible choices: { "field_id": (unique ID for the field), "page": (page number, 1-based), @@ -41,6 +45,7 @@ If the PDF has fillable form fields: "value": (set the field to this value to select this option), "text": (display text of the option) }, + // Other choice options ], } ] @@ -52,17 +57,18 @@ Then analyze the images to determine the purpose of each form field (make sure t ``` [ { - "field_id": "last_name", + "field_id": "last_name", // Must match the field_id from `extract_form_field_info.py` "description": "The user's last name", - "page": 1, + "page": 1, // Must match the "page" value in field_info.json "value": "Simpson" }, { "field_id": "Checkbox12", "description": "Checkbox to be checked if the user is 18 or over", "page": 1, - "value": "/On" + "value": "/On" // If this is a checkbox, use its "checked_value" value to check it. If it's a radio button group, use one of the "value" values in "radio_options". }, + // more fields ] ``` - Run the `fill_fillable_fields.py` script from this file's directory to create a filled-in PDF: diff --git a/.github/skills/anthropic-pdf/reference.md b/.github/skills/anthropic-pdf/reference.md index 3012f4d1..bd4cd7ae 100644 --- a/.github/skills/anthropic-pdf/reference.md +++ b/.github/skills/anthropic-pdf/reference.md @@ -12,17 +12,21 @@ pypdfium2 is a Python binding for PDFium (Chromium's PDF library). It's excellen import pypdfium2 as pdfium from PIL import Image +# Load PDF pdf = pdfium.PdfDocument("document.pdf") -page = pdf[0] +# Render page to image +page = pdf[0] # First page bitmap = page.render( - scale=2.0, - rotation=0 + scale=2.0, # Higher resolution + rotation=0 # No rotation ) +# Convert to PIL Image img = bitmap.to_pil() img.save("page_1.png", "PNG") +# Process multiple pages for i, page in enumerate(pdf): bitmap = page.render(scale=1.5) img = bitmap.to_pil() @@ -51,12 +55,15 @@ import { PDFDocument } from 'pdf-lib'; import fs from 'fs'; async function manipulatePDF() { + // Load existing PDF const existingPdfBytes = fs.readFileSync('input.pdf'); const pdfDoc = await PDFDocument.load(existingPdfBytes); + // Get page count const pageCount = pdfDoc.getPageCount(); console.log(`Document has ${pageCount} pages`); + // Add new page const newPage = pdfDoc.addPage([600, 400]); newPage.drawText('Added by pdf-lib', { x: 100, @@ -64,6 +71,7 @@ async function manipulatePDF() { size: 16 }); + // Save modified PDF const pdfBytes = await pdfDoc.save(); fs.writeFileSync('modified.pdf', pdfBytes); } @@ -77,12 +85,15 @@ import fs from 'fs'; async function createPDF() { const pdfDoc = await PDFDocument.create(); + // Add fonts const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica); const helveticaBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold); - const page = pdfDoc.addPage([595, 842]); + // Add page + const page = pdfDoc.addPage([595, 842]); // A4 size const { width, height } = page.getSize(); + // Add text with styling page.drawText('Invoice #12345', { x: 50, y: height - 50, @@ -91,6 +102,7 @@ async function createPDF() { color: rgb(0.2, 0.2, 0.8) }); + // Add rectangle (header background) page.drawRectangle({ x: 40, y: height - 100, @@ -99,6 +111,7 @@ async function createPDF() { color: rgb(0.9, 0.9, 0.9) }); + // Add table-like content const items = [ ['Item', 'Qty', 'Price', 'Total'], ['Widget', '2', '$50', '$100'], @@ -131,17 +144,21 @@ import { PDFDocument } from 'pdf-lib'; import fs from 'fs'; async function mergePDFs() { + // Create new document const mergedPdf = await PDFDocument.create(); + // Load source PDFs const pdf1Bytes = fs.readFileSync('doc1.pdf'); const pdf2Bytes = fs.readFileSync('doc2.pdf'); const pdf1 = await PDFDocument.load(pdf1Bytes); const pdf2 = await PDFDocument.load(pdf2Bytes); + // Copy pages from first PDF const pdf1Pages = await mergedPdf.copyPages(pdf1, pdf1.getPageIndices()); pdf1Pages.forEach(page => mergedPdf.addPage(page)); + // Copy specific pages from second PDF (pages 0, 2, 4) const pdf2Pages = await mergedPdf.copyPages(pdf2, [0, 2, 4]); pdf2Pages.forEach(page => mergedPdf.addPage(page)); @@ -158,17 +175,21 @@ PDF.js is Mozilla's JavaScript library for rendering PDFs in the browser. ```javascript import * as pdfjsLib from 'pdfjs-dist'; -pdfjsLib.GlobalWorkerOptions.workerSrc = './pdf.worker.js'; +// Configure worker (important for performance) +pdfjsLib.GlobalWorkerOptions.workerSrc = './anthropic-pdf.worker.js'; async function renderPDF() { + // Load PDF const loadingTask = pdfjsLib.getDocument('document.pdf'); const pdf = await loadingTask.promise; console.log(`Loaded PDF with ${pdf.numPages} pages`); + // Get first page const page = await pdf.getPage(1); const viewport = page.getViewport({ scale: 1.5 }); + // Render to canvas const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.height = viewport.height; @@ -194,6 +215,7 @@ async function extractText() { let fullText = ''; + // Extract text from all pages for (let i = 1; i <= pdf.numPages; i++) { const page = await pdf.getPage(i); const textContent = await page.getTextContent(); @@ -204,6 +226,7 @@ async function extractText() { fullText += `\n--- Page ${i} ---\n${pageText}`; + // Get text with coordinates for advanced processing const textWithCoords = textContent.items.map(item => ({ text: item.str, x: item.transform[4], @@ -245,20 +268,33 @@ async function extractAnnotations() { #### Extract Text with Bounding Box Coordinates ```bash +# Extract text with bounding box coordinates (essential for structured data) pdftotext -bbox-layout document.pdf output.xml + +# The XML output contains precise coordinates for each text element ``` #### Advanced Image Conversion ```bash +# Convert to PNG images with specific resolution pdftoppm -png -r 300 document.pdf output_prefix + +# Convert specific page range with high resolution pdftoppm -png -r 600 -f 1 -l 3 document.pdf high_res_pages + +# Convert to JPEG with quality setting pdftoppm -jpeg -jpegopt quality=85 -r 200 document.pdf jpeg_output ``` #### Extract Embedded Images ```bash +# Extract all embedded images with metadata pdfimages -j -p document.pdf page_images + +# List image info without extracting pdfimages -list document.pdf + +# Extract images in their original format pdfimages -all document.pdf images/img ``` @@ -266,24 +302,41 @@ pdfimages -all document.pdf images/img #### Complex Page Manipulation ```bash +# Split PDF into groups of pages qpdf --split-pages=3 input.pdf output_group_%02d.pdf + +# Extract specific pages with complex ranges qpdf input.pdf --pages input.pdf 1,3-5,8,10-end -- extracted.pdf + +# Merge specific pages from multiple PDFs qpdf --empty --pages doc1.pdf 1-3 doc2.pdf 5-7 doc3.pdf 2,4 -- combined.pdf ``` #### PDF Optimization and Repair ```bash +# Optimize PDF for web (linearize for streaming) qpdf --linearize input.pdf optimized.pdf + +# Remove unused objects and compress qpdf --optimize-level=all input.pdf compressed.pdf + +# Attempt to repair corrupted PDF structure qpdf --check input.pdf qpdf --fix-qdf damaged.pdf repaired.pdf + +# Show detailed PDF structure for debugging qpdf --show-all-pages input.pdf > structure.txt ``` #### Advanced Encryption ```bash +# Add password protection with specific permissions qpdf --encrypt user_pass owner_pass 256 --print=none --modify=none -- input.pdf encrypted.pdf + +# Check encryption status qpdf --show-encryption encrypted.pdf + +# Remove password protection (requires password) qpdf --password=secret123 --decrypt encrypted.pdf decrypted.pdf ``` @@ -298,10 +351,12 @@ import pdfplumber with pdfplumber.open("document.pdf") as pdf: page = pdf.pages[0] + # Extract all text with coordinates chars = page.chars - for char in chars[:10]: + for char in chars[:10]: # First 10 characters print(f"Char: '{char['text']}' at x:{char['x0']:.1f} y:{char['y0']:.1f}") + # Extract text by bounding box (left, top, right, bottom) bbox_text = page.within_bbox((100, 100, 400, 200)).extract_text() ``` @@ -313,6 +368,7 @@ import pandas as pd with pdfplumber.open("complex_table.pdf") as pdf: page = pdf.pages[0] + # Extract tables with custom settings for complex layouts table_settings = { "vertical_strategy": "lines", "horizontal_strategy": "lines", @@ -321,6 +377,7 @@ with pdfplumber.open("complex_table.pdf") as pdf: } tables = page.extract_tables(table_settings) + # Visual debugging for table extraction img = page.to_image(resolution=150) img.save("debug_layout.png") ``` @@ -333,19 +390,23 @@ from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib import colors +# Sample data data = [ ['Product', 'Q1', 'Q2', 'Q3', 'Q4'], ['Widgets', '120', '135', '142', '158'], ['Gadgets', '85', '92', '98', '105'] ] +# Create PDF with table doc = SimpleDocTemplate("report.pdf") elements = [] +# Add title styles = getSampleStyleSheet() title = Paragraph("Quarterly Sales Report", styles['Title']) elements.append(title) +# Add table with advanced styling table = Table(data) table.setStyle(TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), colors.grey), @@ -368,6 +429,7 @@ doc.build(elements) #### Method 1: Using pdfimages (fastest) ```bash +# Extract all images with original quality pdfimages -all document.pdf images/img ``` @@ -381,12 +443,21 @@ def extract_figures(pdf_path, output_dir): pdf = pdfium.PdfDocument(pdf_path) for page_num, page in enumerate(pdf): + # Render high-resolution page bitmap = page.render(scale=3.0) img = bitmap.to_pil() + # Convert to numpy for processing img_array = np.array(img) + # Simple figure detection (non-white regions) mask = np.any(img_array != [255, 255, 255], axis=2) + + # Find contours and extract bounding boxes + # (This is simplified - real implementation would need more sophisticated detection) + + # Save detected figures + # ... implementation depends on specific needs ``` ### Batch PDF Processing with Error Handling @@ -442,6 +513,7 @@ from pypdf import PdfWriter, PdfReader reader = PdfReader("input.pdf") writer = PdfWriter() +# Crop page (left, bottom, right, top in points) page = reader.pages[0] page.mediabox.left = 50 page.mediabox.bottom = 50 @@ -475,6 +547,7 @@ with open("cropped.pdf", "wb") as output: ### 5. Memory Management ```python +# Process PDFs in chunks def process_large_pdf(pdf_path, chunk_size=10): reader = PdfReader(pdf_path) total_pages = len(reader.pages) @@ -486,6 +559,7 @@ def process_large_pdf(pdf_path, chunk_size=10): for i in range(start_idx, end_idx): writer.add_page(reader.pages[i]) + # Process chunk with open(f"chunk_{start_idx//chunk_size}.pdf", "wb") as output: writer.write(output) ``` @@ -494,6 +568,7 @@ def process_large_pdf(pdf_path, chunk_size=10): ### Encrypted PDFs ```python +# Handle password-protected PDFs from pypdf import PdfReader try: @@ -506,12 +581,14 @@ except Exception as e: ### Corrupted PDFs ```bash +# Use qpdf to repair qpdf --check corrupted.pdf qpdf --replace-input corrupted.pdf ``` ### Text Extraction Issues ```python +# Fallback to OCR for scanned PDFs import pytesseract from pdf2image import convert_from_path @@ -532,4 +609,4 @@ def extract_text_with_ocr(pdf_path): - **poppler-utils**: GPL-2 License - **qpdf**: Apache License - **pdf-lib**: MIT License -- **pdfjs-dist**: Apache License +- **pdfjs-dist**: Apache License \ No newline at end of file diff --git a/.github/skills/anthropic-pdf/scripts/extract_form_structure.py b/.github/skills/anthropic-pdf/scripts/extract_form_structure.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-pptx/scripts/add_slide.py b/.github/skills/anthropic-pptx/scripts/add_slide.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-pptx/scripts/clean.py b/.github/skills/anthropic-pptx/scripts/clean.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-pptx/scripts/office/validate.py b/.github/skills/anthropic-pptx/scripts/office/validate.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-pptx/scripts/thumbnail.py b/.github/skills/anthropic-pptx/scripts/thumbnail.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-xlsx/scripts/office/validate.py b/.github/skills/anthropic-xlsx/scripts/office/validate.py old mode 100644 new mode 100755 diff --git a/.github/skills/anthropic-xlsx/scripts/recalc.py b/.github/skills/anthropic-xlsx/scripts/recalc.py old mode 100644 new mode 100755 diff --git a/.github/skills/mattpocock-setup-matt-pocock-skills/domain.md b/.github/skills/mattpocock-setup-matt-pocock-skills/domain.md index a03afcc7..16cef7d1 100644 --- a/.github/skills/mattpocock-setup-matt-pocock-skills/domain.md +++ b/.github/skills/mattpocock-setup-matt-pocock-skills/domain.md @@ -8,7 +8,7 @@ How the engineering skills should consume this repo's domain documentation when - **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic. - **`docs/adr/`** — read ADRs that touch the area you're about to work in. In multi-context repos, also check `src//docs/adr/` for context-scoped decisions. -If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/mattpocock-domain-modeling` skill (reached via `/mattpocock-grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved. +If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/mattpocock-domain-modeling` skill (reached via `/mattpocock-grill-with-docs` and `/mattpocock-improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved. ## File structure diff --git a/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-github.md b/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-github.md index c4a3be7b..f8902128 100644 --- a/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-github.md +++ b/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-github.md @@ -15,7 +15,7 @@ Infer the repo from `git remote -v` — `gh` does this automatically when run in ## Pull requests as a triage surface -**PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; `/triage` reads this flag.)_ +**PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; `/mattpocock-triage` reads this flag.)_ When set to `yes`, PRs run through the same labels and states as issues, using the `gh pr` equivalents: @@ -38,7 +38,7 @@ Run `gh issue view --comments`. Used by `/mattpocock-wayfinder`. The **map** is a single issue with **child** issues as tickets. - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`. -- **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #` at the top of the child body. Labels: `wayfinder:` (`mattpocock-research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. +- **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #` at the top of the child body. Labels: `wayfinder:` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. - **Blocking**: GitHub's **native issue dependencies** — the canonical, UI-visible representation. Add an edge with `gh api --method POST repos///issues//dependencies/blocked_by -F issue_id=`, where `` is the blocker's numeric **database id** (`gh api repos///issues/ --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only — the live gate). Where dependencies aren't available, fall back to a `Blocked by: #, #` line at the top of the child body. A ticket is unblocked when every blocker is closed. - **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or an assignee; first in map order wins. - **Claim**: `gh issue edit --add-assignee @me` — the session's first write. diff --git a/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-gitlab.md b/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-gitlab.md index 0c8c92b2..ada31c7e 100644 --- a/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-gitlab.md +++ b/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-gitlab.md @@ -16,7 +16,7 @@ Infer the repo from `git remote -v` — `glab` does this automatically when run ## Merge requests as a triage surface -**MRs as a request surface: no.** _(Set to `yes` if this repo treats external merge requests as feature requests; `/triage` reads this flag.)_ +**MRs as a request surface: no.** _(Set to `yes` if this repo treats external merge requests as feature requests; `/mattpocock-triage` reads this flag.)_ When set to `yes`, MRs run through the same labels and states as issues, using the `glab mr` equivalents: @@ -39,7 +39,7 @@ Run `glab issue view --comments`. Used by `/mattpocock-wayfinder`. The **map** is a single issue with **child** issues as tickets. - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `glab issue create --label wayfinder:map`. (On GitLab tiers with native epics, an epic may hold the map instead; a labelled issue works everywhere.) -- **Child ticket**: an issue carrying `Part of #` at the top of its description and labels `wayfinder:` (`mattpocock-research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. +- **Child ticket**: an issue carrying `Part of #` at the top of its description and labels `wayfinder:` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. - **Blocking**: GitLab's **native blocking link** — the canonical, UI-visible representation. Add it with the `/blocked_by #` quick action, posted as a note (`glab issue note --message "/blocked_by #"`). Native blocking links are a Premium/Ultimate feature; on the free tier (or where unavailable) fall back to a `Blocked by: #, #` line at the top of the description. A ticket is unblocked when every blocker is closed. - **Frontier query**: `glab issue list -F json` scoped to the map's children, drop any with an open blocker — a native `blocked_by` link to an open issue (`glab api projects/:id/issues/:iid/links`), or an open issue in the `Blocked by` line — or an assignee; first in map order wins. - **Claim**: `glab issue update --assignee @me` — the session's first write. diff --git a/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-local.md b/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-local.md index a7f1a765..25cf9ae8 100644 --- a/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-local.md +++ b/.github/skills/mattpocock-setup-matt-pocock-skills/issue-tracker-local.md @@ -23,7 +23,7 @@ Read the file at the referenced path. The user will normally pass the path or th Used by `/mattpocock-wayfinder`. The **map** is a file with one **child** file per ticket. - **Map**: `.scratch//map.md` — the Notes / Decisions-so-far / Fog body. -- **Child ticket**: `.scratch//issues/NN-.md`, numbered from `01`, with the question in the body. A `Type:` line records the ticket type (`mattpocock-research`/`prototype`/`grilling`/`task`); a `Status:` line records `claimed`/`resolved`. +- **Child ticket**: `.scratch//issues/NN-.md`, numbered from `01`, with the question in the body. A `Type:` line records the ticket type (`research`/`prototype`/`grilling`/`task`); a `Status:` line records `claimed`/`resolved`. - **Blocking**: a `Blocked by: NN, NN` line near the top. A ticket is unblocked when every file it lists is `resolved`. - **Frontier**: scan `.scratch//issues/` for files that are open, unblocked, and unclaimed; first by number wins. - **Claim**: set `Status: claimed` and save before any work. diff --git a/.github/skills/mattpocock-triage/SKILL.md b/.github/skills/mattpocock-triage/SKILL.md index 760a8842..d4567072 100644 --- a/.github/skills/mattpocock-triage/SKILL.md +++ b/.github/skills/mattpocock-triage/SKILL.md @@ -40,7 +40,7 @@ For a PR, the same states read against the attached code: `ready-for-agent` mean Every triaged issue should carry exactly one category role and one state role. If state roles conflict, flag it and ask the maintainer before doing anything else. -These are canonical role names — the actual label strings used in the issue tracker may differ. The mapping should have been provided to you - run `/setup-matt-pocock-skills` if not. +These are canonical role names — the actual label strings used in the issue tracker may differ. The mapping should have been provided to you - run `/mattpocock-setup-matt-pocock-skills` if not. State transitions: an unlabeled issue normally goes to `needs-triage` first; from there it moves to `needs-info`, `ready-for-agent`, `ready-for-human`, or `wontfix`. `needs-info` returns to `needs-triage` once the reporter replies. The maintainer can override at any time — flag transitions that look unusual and ask before proceeding. diff --git a/.github/skills/mattpocock-wayfinder/SKILL.md b/.github/skills/mattpocock-wayfinder/SKILL.md index 456cc0b7..e3005e26 100644 --- a/.github/skills/mattpocock-wayfinder/SKILL.md +++ b/.github/skills/mattpocock-wayfinder/SKILL.md @@ -62,7 +62,7 @@ Each ticket is a **child issue** of the map; the tracker's issue id is its ident ``` -Each ticket carries a `wayfinder:` label — one of `mattpocock-research`, `prototype`, `grilling`, `task` (see [Ticket Types](#ticket-types)). +Each ticket carries a `wayfinder:` label — one of `research`, `prototype`, `grilling`, `task` (see [Ticket Types](#ticket-types)). A session **claims** a ticket by assigning it to the dev driving the map, **first**, before any work, so concurrent sessions skip it. That assignee _is_ the claim: an open, unassigned ticket is unclaimed. @@ -112,7 +112,7 @@ User invokes with a loose idea. 2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** — the way to the destination is already clear, the whole journey small enough for one session — you don't need a map. Stop and ask the user how they'd like to proceed. 3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**. 4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog — the **Not yet specified** section. -5. **Fire the research subagents.** For each `mattpocock-research` ticket you just created, spin up a `/mattpocock-research` subagent to resolve it in parallel, capturing its findings on a throwaway `research/` branch with a context pointer from the ticket. +5. **Fire the research subagents.** For each `research` ticket you just created, spin up a `/mattpocock-research` subagent to resolve it in parallel, capturing its findings on a throwaway `research/` branch with a context pointer from the ticket. 6. Stop — charting is one session's work; it hand-resolves nothing. ### Work through the map diff --git a/.github/skills/mattpocock-writing-great-skills/GLOSSARY.md b/.github/skills/mattpocock-writing-great-skills/GLOSSARY.md index 935459f8..752f0c07 100644 --- a/.github/skills/mattpocock-writing-great-skills/GLOSSARY.md +++ b/.github/skills/mattpocock-writing-great-skills/GLOSSARY.md @@ -1,6 +1,6 @@ # Glossary — Building Great Skills -The domain model for what makes a skill great. A skill exists to wrangle determinism out of a stochastic system; the root virtue is **Predictability**, and every term below is a lever on it. This is the disclosed reference for [`mattpocock-writing-great-skills`](SKILL.md). +The domain model for what makes a skill great. A skill exists to wrangle determinism out of a stochastic system; the root virtue is **Predictability**, and every term below is a lever on it. This is the disclosed reference for [`writing-great-skills`](SKILL.md). The terms are grouped by axis: **Invocation** (how a skill is reached), **Information Hierarchy** (how its content is arranged), **Steering** (how the agent's runtime behaviour is shaped), and **Pruning** (how it is kept lean). Each **failure mode** lives beside the lever that cures it, tagged _failure mode_. diff --git a/.github/skills/superpowers-brainstorming/SKILL.md b/.github/skills/superpowers-brainstorming/SKILL.md index 41c68c6f..b36ca7ff 100644 --- a/.github/skills/superpowers-brainstorming/SKILL.md +++ b/.github/skills/superpowers-brainstorming/SKILL.md @@ -7,7 +7,7 @@ description: "You MUST use this before any creative work - creating features, bu Help turn ideas into fully formed designs and specs through natural collaborative dialogue. -Start by understanding the current project context, then Ask clarifying questions in numbered bulk question blocks. Each question must include a short recommendation, a short reason for that recommendation, and the default that will be treated as accepted when the user accepts the suggestions. Once you understand what you're building, decide whether a retained spec adds real design value or whether moving directly to an implementation plan is the better next step. +Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design and get user approval. Do NOT invoke any implementation skill, write any code, scaffold any project, or take any implementation action until you have presented a design and the user has approved it. This applies to EVERY project regardless of perceived simplicity. @@ -23,38 +23,34 @@ You MUST create a task for each of these items and complete them in order: 1. **Explore project context** — check files, docs, recent commits 2. **Offer the visual companion just-in-time** — NOT upfront. The first time a question would genuinely be clearer shown than described, offer it then (its own message); on approval its browser tab opens for you. If no visual question ever arises, never offer it. See the Visual Companion section below. -3. **Ask clarifying questions** — use numbered bulk question blocks with `Question`, `Recommendation`, `Why`, and `Default if accepted` +3. **Ask clarifying questions** — one at a time, understand purpose/constraints/success criteria 4. **Propose 2-3 approaches** — with trade-offs and your recommendation 5. **Present design** — in sections scaled to their complexity, get user approval after each section -6. **Run the Design-Depth Gate** — choose `Decision: direct plan` or `Decision: spec first`, and tell the user why -7. **Write design doc when needed** — if the gate chooses `spec first` and the user wants a retained file, save it to `tmp/superpowers/specs/YYYY-MM-DD--design.md`; never commit files from `tmp/` -8. **Spec self-review when needed** — quick inline check for placeholders, contradictions, ambiguity, scope (see below) -9. **User reviews written spec when needed** — ask user to review the spec file before proceeding -10. **Transition to implementation planning** — invoke writing-plans skill after the user approves either the design or the direct-plan recommendation +6. **Write design doc** — save to `tmp/superpowers/specs/YYYY-MM-DD--design.md` and commit +7. **Spec self-review** — quick inline check for placeholders, contradictions, ambiguity, scope (see below) +8. **User reviews written spec** — ask user to review the spec file before proceeding +9. **Transition to implementation** — invoke writing-plans skill to create implementation plan ## Process Flow ```dot digraph brainstorming { "Explore project context" [shape=box]; - "Ask bulk clarifying questions" [shape=box]; + "Ask clarifying questions" [shape=box]; "Propose 2-3 approaches" [shape=box]; "Present design sections" [shape=box]; "User approves design?" [shape=diamond]; - "Design-Depth Gate" [shape=diamond]; "Write design doc" [shape=box]; "Spec self-review\n(fix inline)" [shape=box]; "User reviews spec?" [shape=diamond]; "Invoke writing-plans skill" [shape=doublecircle]; - "Explore project context" -> "Ask bulk clarifying questions"; - "Ask bulk clarifying questions" -> "Propose 2-3 approaches"; + "Explore project context" -> "Ask clarifying questions"; + "Ask clarifying questions" -> "Propose 2-3 approaches"; "Propose 2-3 approaches" -> "Present design sections"; "Present design sections" -> "User approves design?"; "User approves design?" -> "Present design sections" [label="no, revise"]; - "User approves design?" -> "Design-Depth Gate" [label="yes"]; - "Design-Depth Gate" -> "Invoke writing-plans skill" [label="direct plan"]; - "Design-Depth Gate" -> "Write design doc" [label="spec first"]; + "User approves design?" -> "Write design doc" [label="yes"]; "Write design doc" -> "Spec self-review\n(fix inline)"; "Spec self-review\n(fix inline)" -> "User reviews spec?"; "User reviews spec?" -> "Write design doc" [label="changes requested"]; @@ -62,7 +58,7 @@ digraph brainstorming { } ``` -**The terminal state is invoking writing-plans.** Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans. The path to writing-plans may be either `Decision: direct plan` or `Decision: spec first`. +**The terminal state is invoking writing-plans.** Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans. ## The Process @@ -71,13 +67,9 @@ digraph brainstorming { - Check out the current project state first (files, docs, recent commits) - Before asking detailed questions, assess scope: if the request describes multiple independent subsystems (e.g., "build a platform with chat, file storage, billing, and analytics"), flag this immediately. Don't spend questions refining details of a project that needs to be decomposed first. - If the project is too large for a single spec, help the user decompose into sub-projects: what are the independent pieces, how do they relate, what order should they be built? Then brainstorm the first sub-project through the normal design flow. Each sub-project gets its own spec → plan → implementation cycle. -- For appropriately-scoped projects, ask clarifying questions in numbered bulk question blocks to refine the idea +- For appropriately-scoped projects, ask questions one at a time to refine the idea - Prefer multiple choice questions when possible, but open-ended is fine too -- Each numbered question must use this format: `Question`, `Recommendation`, `Why`, and `Default if accepted` -- The recommendation and why must be clear and brief -- The user may accept all suggested defaults, accept only some numbered defaults, or override any numbered recommendation -- Accepted defaults do not mean discovery is complete. If the accepted answers create contradictions, weak assumptions, unresolved risks, or dependent decisions, ask another focused numbered bulk question block. -- Ask another focused numbered bulk question block only for unresolved, dependent, or reopened branches. Do not ask questions that project evidence can answer. +- Only one question per message - if a topic needs more exploration, break it into multiple questions - Focus on understanding: purpose, constraints, success criteria **Exploring approaches:** @@ -85,6 +77,7 @@ digraph brainstorming { - Propose 2-3 different approaches with trade-offs - Present options conversationally with your recommendation and reasoning - Lead with your recommended option and explain why +- YAGNI ruthlessly - remove unnecessary features from every approach and design **Presenting the design:** @@ -94,23 +87,6 @@ digraph brainstorming { - Cover: architecture, components, data flow, error handling, testing - Be ready to go back and clarify if something doesn't make sense -**Design-Depth Gate:** - -Before writing a retained spec, decide whether the spec has meaningful marginal value over going directly to an implementation plan. - -Choose `Decision: direct plan` when the target, owner, scope, constraints, rejected alternatives, and validation path are already clear, and a retained spec would mostly duplicate the implementation plan. - -Choose `Decision: spec first` when product, design, architecture, data flow, user experience, rollout, or risk decisions are still material enough that a retained spec would reduce the chance of building the wrong thing. - -In both cases, tell the user the decision and one short reason: - -- `Decision: direct plan` -- `Why: ` -- `Decision: spec first` -- `Why: ` - -Ask for user approval before invoking writing-plans. Direct plan skips the retained spec, not the user approval gate. - **Design for isolation and clarity:** - Break the system into smaller units that each have one clear purpose, communicate through well-defined interfaces, and can be understood and tested independently @@ -128,11 +104,10 @@ Ask for user approval before invoking writing-plans. Direct plan skips the retai **Documentation:** -- Write the validated design (spec) to chat by default -- Persist it to `tmp/superpowers/specs/YYYY-MM-DD--design.md` only when `Decision: spec first` is chosen and the user explicitly wants a retained file +- Write the validated design (spec) to `tmp/superpowers/specs/YYYY-MM-DD--design.md` - (User preferences for spec location override this default) - Use elements-of-style:writing-clearly-and-concisely skill if available -- Never commit files from `tmp/` +- Commit the design document to git **Spec Self-Review:** After writing the spec document, look at it with fresh eyes: @@ -147,24 +122,15 @@ Fix any issues inline. No need to re-review — just fix and move on. **User Review Gate:** After the spec review loop passes, ask the user to review the written spec before proceeding: -> "Spec written to ``. Please review it and let me know if you want to make any changes before we start writing out the implementation plan." +> "Spec written and committed to ``. Please review it and let me know if you want to make any changes before we start writing out the implementation plan." Wait for the user's response. If they request changes, make them and re-run the spec review loop. Only proceed once the user approves. **Implementation:** -- Invoke the writing-plans skill to create a detailed implementation plan after the user approves either `Decision: direct plan` or the reviewed spec +- Invoke the writing-plans skill to create a detailed implementation plan - Do NOT invoke any other skill. writing-plans is the next step. -## Key Principles - -- **Bulk guided question blocks** - Ask the full known question set together, with recommendations, reasons, and defaults -- **Multiple choice preferred** - Easier to answer than open-ended when possible -- **YAGNI ruthlessly** - Remove unnecessary features from all designs -- **Explore alternatives** - Always propose 2-3 approaches before settling -- **Incremental validation** - Present design, get approval before moving on -- **Be flexible** - Go back and clarify when something doesn't make sense - ## Visual Companion A browser-based companion for showing mockups, diagrams, and visual options during brainstorming. Available as a tool — not a mode. Accepting the companion means it's available for questions that benefit from visual treatment; it does NOT mean every question goes through the browser. From 3831549816e13760e701388234362490ca6aa727 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 22:47:49 +0200 Subject: [PATCH 08/23] feat: enhance agent documentation, add validation boundaries, and improve debug log analysis --- .../internal-gateway-review-code.agent.md | 5 + .../internal-gateway-review-generic.agent.md | 5 + .../local-sync-external-resources.agent.md | 11 ++ .github/scripts/lib/catalog_checks.py | 2 - .github/skills/internal-gcp/SKILL.md | 2 +- .../internal-gcp/references/routing-matrix.md | 2 +- .../local-copilot-log-analyzer/SKILL.md | 12 ++ .../agents/openai.yaml | 2 +- .markdownlint-cli2.jsonc | 7 + AGENTS.md | 2 +- Makefile | 12 +- ..._local_sync_external_resources_contract.py | 30 ++++ .../scripts/test_critical_master_validator.py | 6 - .../test_review_chat_projection_contract.py | 0 .../test_makefile_skill_script_references.py | 8 +- .../fixtures/direct-session.jsonl | 3 + .../test_debug_logs.py | 83 +++++++++++ tools/analyze_copilot_debug_log/debug_logs.py | 138 +++++++++++++++++- 18 files changed, 305 insertions(+), 25 deletions(-) create mode 100644 tests/github/agents/test_local_sync_external_resources_contract.py rename tests/github/{agents => skills/internal-gateway-review-code}/test_review_chat_projection_contract.py (100%) create mode 100644 tests/tools/analyze_copilot_debug_log/fixtures/direct-session.jsonl create mode 100644 tests/tools/analyze_copilot_debug_log/test_debug_logs.py diff --git a/.github/agents/internal-gateway-review-code.agent.md b/.github/agents/internal-gateway-review-code.agent.md index 134421dd..a6bf26fa 100644 --- a/.github/agents/internal-gateway-review-code.agent.md +++ b/.github/agents/internal-gateway-review-code.agent.md @@ -15,18 +15,21 @@ You are an experienced Staff Engineer conducting a thorough code review. Your ro Evaluate every change across these five dimensions: ### 1. Correctness + - Does the code do what the spec/task says it should? - Are edge cases handled (null, empty, boundary values, error paths)? - Do the tests actually verify the behavior? Are they testing the right things? - Are there race conditions, off-by-one errors, or state inconsistencies? ### 2. Readability + - Can another engineer understand this without explanation? - Are names descriptive and consistent with project conventions? - Is the control flow straightforward (no deeply nested logic)? - Is the code well-organized (related code grouped, clear boundaries)? ### 3. Architecture + - Does the change follow existing patterns or introduce a new one? - If a new pattern, is it justified and documented? - Are module boundaries maintained? Any circular dependencies? @@ -34,6 +37,7 @@ Evaluate every change across these five dimensions: - Are dependencies flowing in the right direction? ### 4. Security + - Is user input validated and sanitized at system boundaries? - Are secrets kept out of code, logs, and version control? - Is authentication/authorization checked where needed? @@ -41,6 +45,7 @@ Evaluate every change across these five dimensions: - Any new dependencies with known vulnerabilities? ### 5. Performance + - Any N+1 query patterns? - Any unbounded loops or unconstrained data fetching? - Any synchronous operations that should be async? diff --git a/.github/agents/internal-gateway-review-generic.agent.md b/.github/agents/internal-gateway-review-generic.agent.md index 11c91c86..7678950e 100644 --- a/.github/agents/internal-gateway-review-generic.agent.md +++ b/.github/agents/internal-gateway-review-generic.agent.md @@ -17,26 +17,31 @@ You are the repository generic review gateway. Review concrete non-code or mixed Evaluate the target through the dimensions that apply to its surface: ### 1. Intent And Scope + - Is the review target concrete enough to judge? - Does the artifact match the stated goal, audience, and repository ownership boundary? - Are exclusions, assumptions, and decision points explicit? ### 2. Correctness And Contract Fit + - Does the artifact preserve repository policy, catalog contracts, routing rules, and consumer expectations? - Are names, paths, frontmatter, metadata, and referenced assets accurate? - Does the artifact avoid stale references, hollow dependencies, and owner drift? ### 3. Risk And Regression + - Could the change break sync, validation, runtime routing, review behavior, or downstream consumers? - Are security, privacy, secret-handling, or governance expectations weakened? - Are rollout, compatibility, and reversibility risks understood? ### 4. Ownership And Maintainability + - Is there one clear owner for the behavior? - Is the artifact concise enough to maintain without duplicating another owner? - Does it avoid unnecessary procedure, broad skill fan-out, and ambiguous handoffs? ### 5. Validation And Evidence + - What validation has already been run? - What validation is still missing? - Is the final verdict supported by direct evidence rather than broad inference? diff --git a/.github/agents/local-sync-external-resources.agent.md b/.github/agents/local-sync-external-resources.agent.md index 71d73226..54d6c40d 100644 --- a/.github/agents/local-sync-external-resources.agent.md +++ b/.github/agents/local-sync-external-resources.agent.md @@ -50,6 +50,17 @@ contract instead of reproducing its procedure here. - When changing the sync tooling itself, do not refresh or modify imported resources in the same task. +## Post-Apply Validation Boundaries + +1. After repository mutation, run the closest focused validation as its own next action. +2. Stop on the first failure and report the failing evidence. +3. Only after the focused check passes, run remaining declared validations and + a bounded worktree summary in one subsequent terminal action with + short-circuit semantics. +4. Keep separately authorized, interactive, or networked operations outside + that consolidated action. +5. Do not repeat unchanged command output across progress and final reports. + ## Outcome Report the core skill's complete result without optimistic compression: diff --git a/.github/scripts/lib/catalog_checks.py b/.github/scripts/lib/catalog_checks.py index 24142d83..bc39ff04 100644 --- a/.github/scripts/lib/catalog_checks.py +++ b/.github/scripts/lib/catalog_checks.py @@ -8,8 +8,6 @@ from .inventory import collect_inventory_sections, parse_inventory_markdown from .shared import ( - IGNORED_SYNC_FILENAMES, - IGNORED_SYNC_PARTS, IMPORTED_ASSET_OVERRIDES_PATH, INVENTORY_PATH, LEGACY_AGENT_TOOL_IDS, diff --git a/.github/skills/internal-gcp/SKILL.md b/.github/skills/internal-gcp/SKILL.md index dbc746ba..43f8ca59 100644 --- a/.github/skills/internal-gcp/SKILL.md +++ b/.github/skills/internal-gcp/SKILL.md @@ -164,4 +164,4 @@ Include: - Confirm assumptions, active lenses, and the main tradeoff are named instead of implied. - Confirm the recommendation includes reversibility or blast-radius guidance when the choice is hard to unwind. - Confirm cost-value or operational impact is called out when it materially changes the recommendation. -- Confirm the answer states when freshness matters and which current Google Cloud fact still needs validation. \ No newline at end of file +- Confirm the answer states when freshness matters and which current Google Cloud fact still needs validation. diff --git a/.github/skills/internal-gcp/references/routing-matrix.md b/.github/skills/internal-gcp/references/routing-matrix.md index 7b5371a3..a17f1cea 100644 --- a/.github/skills/internal-gcp/references/routing-matrix.md +++ b/.github/skills/internal-gcp/references/routing-matrix.md @@ -26,4 +26,4 @@ ## Review rule -Prefer a direct specialist whenever a reasonable reviewer can name one primary owner from the request itself. Activate the fallback only when the request does not identify a primary owner and clarification is required before a specialist can engage. The fallback is not a prerequisite for ordinary GCP work and must never activate all GCP skills by default. \ No newline at end of file +Prefer a direct specialist whenever a reasonable reviewer can name one primary owner from the request itself. Activate the fallback only when the request does not identify a primary owner and clarification is required before a specialist can engage. The fallback is not a prerequisite for ordinary GCP work and must never activate all GCP skills by default. diff --git a/.github/skills/local-copilot-log-analyzer/SKILL.md b/.github/skills/local-copilot-log-analyzer/SKILL.md index 8f6466ea..2362667f 100644 --- a/.github/skills/local-copilot-log-analyzer/SKILL.md +++ b/.github/skills/local-copilot-log-analyzer/SKILL.md @@ -53,6 +53,18 @@ or aggregation logic in ad-hoc scripts or one-off shell pipelines. command, output format, and the exact aggregate or slice that supported the conclusion. +## Measurement And Privacy + +- The `debug-logs` command accepts direct `.jsonl` paths as well as existing + JSON, OTLP, legacy-session, and prompt-export inputs. +- Report cache-read tokens, uncached input tokens, output tokens, and AIU + separately when present. Treat gross cumulative input as context volume, not + realized savings. +- Require a before/after run for an optimization claim; otherwise label it as + an upper bound. +- Keep raw prompt, response, reasoning, user-request, and tool-result bodies + excluded from output by default. + ## Validation - `bash tools/analyze_copilot_debug_log/run.sh prompt-exports --help` diff --git a/.github/skills/local-copilot-log-analyzer/agents/openai.yaml b/.github/skills/local-copilot-log-analyzer/agents/openai.yaml index 3fff04f6..56a15fc0 100644 --- a/.github/skills/local-copilot-log-analyzer/agents/openai.yaml +++ b/.github/skills/local-copilot-log-analyzer/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Local Copilot Log Analyzer" short_description: "Analyze Copilot debug logs and prompt exports with bounded, aggregate-first output" - default_prompt: "Use $local-copilot-log-analyzer to analyze GitHub Copilot Chat debug logs or prompt exports in this repository. Route to the canonical tools/analyze_copilot_debug_log wrapper, start aggregate-first, prefer bounded markdown or json output, and avoid full dumps unless they are the missing evidence." + default_prompt: "Use $local-copilot-log-analyzer to analyze GitHub Copilot Chat debug logs or prompt exports in this repository. Route to the canonical tools/analyze_copilot_debug_log wrapper, which accepts direct .jsonl paths, start aggregate-first, report cache-read, uncached-input, output, and AIU separately when present, treat gross cumulative input as context volume rather than realized savings, require before/after evidence or label optimization as an upper bound, prefer bounded markdown or json output, and keep raw bodies excluded unless they are the missing evidence." diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc index ece0204a..0b03a014 100644 --- a/.markdownlint-cli2.jsonc +++ b/.markdownlint-cli2.jsonc @@ -9,13 +9,20 @@ ".github/scripts/.venv/**", // Ignore local tool virtualenv artifacts generated during development. "tools/analyze_copilot_debug_log/.venv/**", + // Ignore any generated virtual environment, including task-specific variants. + "**/.venv*/**", + // Ignore temporary retained execution artifacts outside tmp/. + ".superpowers/**", // Test fixtures are intentionally non-document-shaped markdown inputs. "tests/fixtures/critical_output_*.md", // Skill bundle card fixtures are emoji cards, not structured Markdown documents. ".github/skills/internal-gateway-critical-master/fixtures/*.md", + // Retained-plan and status fixtures intentionally start at contract-owned H2 headings. + ".github/skills/internal-gateway-execute-plans/fixtures/*.md", // Ignore local OpenCode runtime artifacts. ".opencode/**", // Preserve imported support skill families verbatim by default; lint only repo-owned Markdown. + ".github/skills/!(internal-*|local-*)/**", ".github/skills/antigravity-*/**", ".github/skills/awesome-copilot-*/**", ".github/skills/graphify/**", diff --git a/AGENTS.md b/AGENTS.md index b2ea85ad..f0dd1053 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -121,7 +121,7 @@ exists. Use `graphify path "" ""` for relationship questions and `graphify for focused-concept questions. These return a scoped subgraph, usually much smaller than the full report or raw grep output. -Triggers: "how do I…", "where is…", "what does … do", "add/modify a ", +Triggers: "how do I…", "where is…", "what does … do", "add/modify a ``", "explain the architecture", or anything that depends on how files or classes relate. If `graphify-out/wiki/index.md` exists, use it for broad navigation. Read `graphify-out/GRAPH_REPORT.md` diff --git a/Makefile b/Makefile index 654a2d40..afdcae68 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ catalog-fast-check: scripts-bootstrap fi github-catalog-validation: python-version-check - @bash ./github_catalog_validation.sh + @$(SCRIPTS_RUNNER) github_catalog_validation --root . test: scripts-bootstrap @$(SCRIPTS_VENV)/bin/python -m pytest tests -q @@ -68,16 +68,20 @@ skill-lint: scripts-bootstrap @$(SCRIPTS_RUNNER) validate_internal_skills --root . --strict docs-lint: - @if command -v markdownlint-cli2 >/dev/null 2>&1; then \ - markdownlint-cli2 $(MARKDOWNLINT_PATTERNS); \ - elif command -v npx >/dev/null 2>&1; then \ + @if command -v npx >/dev/null 2>&1; then \ if [ -n "$${CI:-}" ]; then \ npx --yes markdownlint-cli2@$(MARKDOWNLINT_VERSION) $(MARKDOWNLINT_PATTERNS); \ elif npm exec --offline --yes markdownlint-cli2@$(MARKDOWNLINT_VERSION) -- --version >/dev/null 2>&1; then \ npm exec --offline --yes markdownlint-cli2@$(MARKDOWNLINT_VERSION) -- $(MARKDOWNLINT_PATTERNS); \ + elif command -v markdownlint-cli2 >/dev/null 2>&1 \ + && markdownlint-cli2 --version 2>/dev/null | grep -Fq "markdownlint-cli2 v$(MARKDOWNLINT_VERSION)"; then \ + markdownlint-cli2 $(MARKDOWNLINT_PATTERNS); \ else \ printf '%s\n' 'markdownlint-cli2 is not installed or cached; skipping markdown lint outside CI.'; \ fi; \ + elif command -v markdownlint-cli2 >/dev/null 2>&1 \ + && markdownlint-cli2 --version 2>/dev/null | grep -Fq "markdownlint-cli2 v$(MARKDOWNLINT_VERSION)"; then \ + markdownlint-cli2 $(MARKDOWNLINT_PATTERNS); \ else \ printf '%s\n' 'npx not installed; skipping markdown lint.'; \ fi diff --git a/tests/github/agents/test_local_sync_external_resources_contract.py b/tests/github/agents/test_local_sync_external_resources_contract.py new file mode 100644 index 00000000..197eddea --- /dev/null +++ b/tests/github/agents/test_local_sync_external_resources_contract.py @@ -0,0 +1,30 @@ +from pathlib import Path + +AGENT_PATH = ( + Path(__file__).resolve().parents[3] + / ".github/agents" + / ("local-sync-external-resources" + ".agent.md") +) + + +def test_post_apply_validation_actions_are_bounded() -> None: + text = AGENT_PATH.read_text(encoding="utf-8") + + assert "focused validation" in text + assert "its own next action" in text + assert "remaining declared validations" in text + assert "one subsequent terminal action" in text + assert "short-circuit" in text + assert "Stop on the first failure" in text + + +def test_sync_contract_preserves_safety_boundaries() -> None: + text = AGENT_PATH.read_text(encoding="utf-8") + + assert "Bare `sync` means `apply`; never promote" in text + assert "Run networked `prepare` only when the user explicitly requests" in text + assert "Treat `--allow-dirty` as explicit risk acceptance" in text + assert "Stop when the request would change manifest scope" in text + assert "bare `sync` may run networked `prepare`" not in text + assert "infer `--allow-dirty`" not in text + assert "modify the sync manifest during an apply run" not in text diff --git a/tests/github/skills/internal-gateway-critical-master/scripts/test_critical_master_validator.py b/tests/github/skills/internal-gateway-critical-master/scripts/test_critical_master_validator.py index d20b5f79..feccfd9b 100644 --- a/tests/github/skills/internal-gateway-critical-master/scripts/test_critical_master_validator.py +++ b/tests/github/skills/internal-gateway-critical-master/scripts/test_critical_master_validator.py @@ -247,9 +247,3 @@ def test_cli_unreadable_file_exits_nonzero_with_stderr() -> None: ) assert result.returncode != 0 assert result.stderr.strip() != "" - - -def test_cli_make_target_includes_strict() -> None: - makefile = (REPO_ROOT / "Makefile").read_text(encoding="utf-8") - assert "--strict" in makefile - assert "critical-validate" in makefile diff --git a/tests/github/agents/test_review_chat_projection_contract.py b/tests/github/skills/internal-gateway-review-code/test_review_chat_projection_contract.py similarity index 100% rename from tests/github/agents/test_review_chat_projection_contract.py rename to tests/github/skills/internal-gateway-review-code/test_review_chat_projection_contract.py diff --git a/tests/test_makefile_skill_script_references.py b/tests/test_makefile_skill_script_references.py index f90a33e7..04c7c7a0 100644 --- a/tests/test_makefile_skill_script_references.py +++ b/tests/test_makefile_skill_script_references.py @@ -1,6 +1,5 @@ from pathlib import Path - REPO_ROOT = next( parent for parent in Path(__file__).resolve().parents @@ -21,3 +20,10 @@ def test_makefile_does_not_reference_skill_scripts() -> None: "plan_execution", ) assert not any(marker in makefile for marker in forbidden) + + +def test_github_catalog_validation_uses_the_repository_script_runner() -> None: + makefile = (REPO_ROOT / "Makefile").read_text(encoding="utf-8") + + assert "$(SCRIPTS_RUNNER) github_catalog_validation" in makefile + assert "./github_catalog_validation.sh" not in makefile diff --git a/tests/tools/analyze_copilot_debug_log/fixtures/direct-session.jsonl b/tests/tools/analyze_copilot_debug_log/fixtures/direct-session.jsonl new file mode 100644 index 00000000..663ea014 --- /dev/null +++ b/tests/tools/analyze_copilot_debug_log/fixtures/direct-session.jsonl @@ -0,0 +1,3 @@ +{"ts":1,"sid":"session-1","type":"llm_request","name":"chat:test-model","status":"ok","attrs":{"inputTokens":100,"cachedTokens":80,"outputTokens":10,"copilotUsageNanoAiu":500000000,"userRequest":"must-not-leak","inputMessages":"must-not-leak"}} +{"ts":2,"sid":"session-1","type":"llm_request","name":"chat:test-model","status":"ok","attrs":{"inputTokens":120,"cachedTokens":100,"outputTokens":20,"copilotUsageNanoAiu":250000000}} +{"ts":3,"sid":"session-1","type":"tool_call","name":"run_in_terminal","status":"ok","attrs":{"result":"ok"}} diff --git a/tests/tools/analyze_copilot_debug_log/test_debug_logs.py b/tests/tools/analyze_copilot_debug_log/test_debug_logs.py new file mode 100644 index 00000000..90134e3e --- /dev/null +++ b/tests/tools/analyze_copilot_debug_log/test_debug_logs.py @@ -0,0 +1,83 @@ +import json +from pathlib import Path + +import pytest + +from tools.analyze_copilot_debug_log.debug_logs import ( + build_report, + load_input, + render_markdown, +) + +DIRECT_FIXTURE = Path(__file__).parent / "fixtures/direct-session.jsonl" + + +def test_build_report_accepts_direct_jsonl() -> None: + report = build_report([DIRECT_FIXTURE]) + + aggregate = report["aggregate"] + assert aggregate["request_count"] == 2 + assert aggregate["input_tokens"] == 220 + assert aggregate["output_tokens"] == 30 + assert aggregate["cache_read_tokens"] == 180 + assert aggregate["non_cached_input_tokens"] == 40 + assert aggregate["aiu_total"] == 0.75 + assert report["sessions"][0]["first_context_tokens"] == 100 + assert report["sessions"][0]["last_context_tokens"] == 120 + assert report["sessions"][0]["max_context_tokens"] == 120 + assert report["sessions"][0]["tool_calls"] == 1 + assert report["sessions"][0]["tool_result_bytes"] == 2 + assert "must-not-leak" not in json.dumps(report) + + +def test_load_input_accepts_one_json_document(tmp_path: Path) -> None: + path = tmp_path / "sessions.json" + path.write_text('{"sessions": []}', encoding="utf-8") + + assert load_input(path) == {"sessions": []} + + +def test_load_input_accepts_empty_lines_around_one_json_document( + tmp_path: Path, +) -> None: + path = tmp_path / "events.jsonl" + path.write_text('\n{"type":"tool_call"}\n\n', encoding="utf-8") + + assert load_input(path) == {"type": "tool_call"} + + +def test_load_input_reports_malformed_jsonl_line_without_content( + tmp_path: Path, +) -> None: + path = tmp_path / "events.jsonl" + path.write_text('{"type":"tool_call"}\nnot-json\n', encoding="utf-8") + + with pytest.raises(ValueError, match=r"events\.jsonl.*line 2") as error: + load_input(path) + + assert "not-json" not in str(error.value) + + +def test_build_report_preserves_legacy_session_input(tmp_path: Path) -> None: + path = tmp_path / "legacy.json" + path.write_text( + json.dumps({"sessions": [{"id": "legacy", "requests": []}]}), + encoding="utf-8", + ) + + report = build_report([path]) + + assert report["sessions"][0]["session_id"] == "legacy" + assert report["unsupported_input_count"] == 0 + + +def test_markdown_reports_cache_uncached_and_aiu() -> None: + report = build_report([DIRECT_FIXTURE]) + + markdown = render_markdown(report) + + assert "| AIU |" in markdown + assert "| 180 | 40 |" in markdown + assert "| 0.75 |" in markdown + assert "must-not-leak" not in markdown + assert "| ok |" not in markdown diff --git a/tools/analyze_copilot_debug_log/debug_logs.py b/tools/analyze_copilot_debug_log/debug_logs.py index 7b86ee7a..e406cfaf 100644 --- a/tools/analyze_copilot_debug_log/debug_logs.py +++ b/tools/analyze_copilot_debug_log/debug_logs.py @@ -183,6 +183,121 @@ def normalize_log_records(value: object) -> list[dict[str, object]]: return records +def load_input(path: Path) -> object: + text = path.read_text(encoding="utf-8") + try: + return json.loads(text) + except json.JSONDecodeError: + records: list[dict[str, object]] = [] + for line_number, line in enumerate(text.splitlines(), start=1): + if not line.strip(): + continue + try: + value = json.loads(line) + except json.JSONDecodeError as error: + raise ValueError( + f"{path.name}: invalid JSONL at line {line_number}" + ) from error + if not isinstance(value, dict): + raise ValueError( + f"{path.name}: JSONL line {line_number} must be an object" + ) + records.append(value) + return records + + +def _direct_numeric(value: object) -> int | float: + if isinstance(value, bool) or not isinstance(value, (int, float)): + return 0 + return value + + +def summarize_direct_events( + events: list[dict[str, object]], source_name: str +) -> list[dict[str, object]]: + llm_requests = [event for event in events if event.get("type") == "llm_request"] + tool_calls = [event for event in events if event.get("type") == "tool_call"] + nano_aiu_divisor = 1_000_000_000 + + input_tokens_total = 0 + output_tokens_total = 0 + cache_read_total = 0 + non_cached_total = 0 + aiu_total = 0.0 + context_series: list[int] = [] + tool_result_bytes = 0 + error_count = 0 + session_id = next( + ( + event.get("sid") + for event in events + if isinstance(event.get("sid"), str) and event.get("sid") + ), + source_name, + ) + + for event in llm_requests: + attrs = event.get("attrs") + attributes = attrs if isinstance(attrs, dict) else {} + input_tokens = max(int(_direct_numeric(attributes.get("inputTokens"))), 0) + cached_tokens = int(_direct_numeric(attributes.get("cachedTokens"))) + cached_tokens = min(max(cached_tokens, 0), input_tokens) + output_tokens = max(int(_direct_numeric(attributes.get("outputTokens"))), 0) + nano_aiu = _direct_numeric(attributes.get("copilotUsageNanoAiu")) + input_tokens_total += input_tokens + output_tokens_total += output_tokens + cache_read_total += cached_tokens + non_cached_total += input_tokens - cached_tokens + aiu_total += float(nano_aiu) / nano_aiu_divisor + context_series.append(input_tokens) + + for event in tool_calls: + attrs = event.get("attrs") + attributes = attrs if isinstance(attrs, dict) else {} + tool_result_bytes += measure_payload_bytes(attributes.get("result")) + if str(event.get("status") or "").lower() in {"error", "failed", "failure"}: + error_count += 1 + + return [ + { + "session_id": str(session_id), + "title": str(session_id), + "model_request_count": len(llm_requests), + "tool_call_count": len(tool_calls), + "request_count": len(llm_requests), + "input_tokens": input_tokens_total, + "output_tokens": output_tokens_total, + "cache_read_tokens": cache_read_total, + "estimated_cache_read_tokens": None, + "non_cached_input_tokens": non_cached_total, + "estimated_non_cached_input_tokens": None, + "aiu_total": round(aiu_total, 6), + "estimated_aiu_total": None, + "request_message_bytes": 0, + "tool_calls": len(tool_calls), + "tool_result_bytes": tool_result_bytes, + "tool_result_volume_bytes": tool_result_bytes, + "tool_schema_bytes": 0, + "error_count": error_count, + "invocation_error_count": error_count, + "missing_memory_path_error_count": 0, + "graphify_invocation_count": 0, + "graphify_discovery_count": 0, + "max_context_tokens": max(context_series) if context_series else 0, + "runtime_context_tokens": max(context_series) if context_series else 0, + "context_growth_tokens": ( + max(context_series[-1] - context_series[0], 0) + if len(context_series) > 1 + else 0 + ), + "first_context_tokens": context_series[0] if context_series else 0, + "last_context_tokens": context_series[-1] if context_series else 0, + "tool_schema_count": None, + "limits": ["direct-debug-jsonl", "summary-only"], + } + ] + + def extract_int(mapping: dict[str, object], *keys: str) -> int | None: for key in keys: value = mapping.get(key) @@ -613,8 +728,14 @@ def summarize_legacy_sessions(data: dict[str, object]) -> list[dict[str, object] return summaries -def summarize_input(path: Path) -> tuple[str, list[dict[str, object]], int]: - data = json.loads(path.read_text(encoding="utf-8")) +def summarize_input( + path: Path, data: object +) -> tuple[str, list[dict[str, object]], int]: + if path.suffix.lower() == ".jsonl" and isinstance(data, list): + events = [item for item in data if isinstance(item, dict)] + return "direct-jsonl", summarize_direct_events(events, path.name), 0 + if isinstance(data, dict) and data.get("type") in {"llm_request", "tool_call"}: + return "direct-jsonl", summarize_direct_events([data], path.name), 0 if isinstance(data, dict) and isinstance(data.get("resourceSpans"), list): return ( "otlp", @@ -709,9 +830,9 @@ def build_report(paths: list[Path]) -> dict[str, object]: raw_snapshot_count = 0 unsupported_inputs: list[str] = [] for path in paths: - data = json.loads(path.read_text(encoding="utf-8")) - kind, summaries, snapshot_like_count = summarize_input(path) - if kind in {"otlp", "otlp-legacy"}: + data = load_input(path) + kind, summaries, snapshot_like_count = summarize_input(path, data) + if kind in {"otlp", "otlp-legacy", "direct-jsonl"}: session_summaries.extend(summaries) continue if kind == "prompt-export": @@ -796,12 +917,13 @@ def render_markdown(report: dict[str, object]) -> str: lines = [ "# Debug Log Summary", "", - "| Session | Requests | Input tokens | Output tokens | Cache read | Non-cached input | First ctx | Last ctx | Max ctx | Tool bytes | Errors |", - "| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |", + "| Session | Requests | Input tokens | Output tokens | Cache read | Non-cached input | AIU | First ctx | Last ctx | Max ctx | Tool bytes | Errors |", + "| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |", ] for summary in sessions: + aiu = f"{as_float(summary.get('aiu_total')):.6f}".rstrip("0").rstrip(".") lines.append( - f"| {summary['title']} | {summary['request_count']} | {summary['input_tokens']} | {summary['output_tokens']} | {summary.get('cache_read_tokens', 0)} | {summary.get('non_cached_input_tokens', 0)} | {summary.get('first_context_tokens', 0)} | {summary.get('last_context_tokens', 0)} | {summary.get('max_context_tokens', 0)} | {summary.get('tool_result_bytes', 0)} | {summary.get('error_count', 0)} |" + f"| {summary['title']} | {summary['request_count']} | {summary['input_tokens']} | {summary['output_tokens']} | {summary.get('cache_read_tokens', 0)} | {summary.get('non_cached_input_tokens', 0)} | {aiu or '0'} | {summary.get('first_context_tokens', 0)} | {summary.get('last_context_tokens', 0)} | {summary.get('max_context_tokens', 0)} | {summary.get('tool_result_bytes', 0)} | {summary.get('error_count', 0)} |" ) lines.append("") lines.append( From 8d9d410b71846f62906ca759e2954f5bb8098093 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 22:53:47 +0200 Subject: [PATCH 09/23] Refactor agent-os commands and skills - Removed the following command files: - index-standards.md - inject-standards.md - plan-product.md - shape-spec.md - Deleted corresponding skills: - agent-os-discover-standards - agent-os-index-standards - agent-os-inject-standards - agent-os-plan-product - agent-os-shape-spec - Updated inventory to reflect the removal of agent-os skills. - Adjusted markdown linting patterns to exclude agent-os command files. - Deleted the standards index file (index.yml) as it is no longer needed. - Updated regex patterns in routing contract tests to remove references to agent-os skills. --- .../commands/agent-os/discover-standards.md | 261 ---------------- .claude/commands/agent-os/index-standards.md | 124 -------- .claude/commands/agent-os/inject-standards.md | 291 ------------------ .claude/commands/agent-os/plan-product.md | 204 ------------ .claude/commands/agent-os/shape-spec.md | 267 ---------------- .github/INVENTORY.md | 5 - .../agent-os-discover-standards/SKILL.md | 49 --- .../skills/agent-os-index-standards/SKILL.md | 47 --- .../skills/agent-os-inject-standards/SKILL.md | 49 --- .github/skills/agent-os-plan-product/SKILL.md | 46 --- .github/skills/agent-os-shape-spec/SKILL.md | 48 --- Makefile | 2 +- agent-os/standards/index.yml | 2 - .../test_internal_aws_routing_contract.py | 2 +- .../test_internal_azure_routing_contract.py | 2 +- .../test_internal_gcp_routing_contract.py | 2 +- .../test_internal_github_routing_contract.py | 2 +- 17 files changed, 5 insertions(+), 1398 deletions(-) delete mode 100644 .claude/commands/agent-os/discover-standards.md delete mode 100644 .claude/commands/agent-os/index-standards.md delete mode 100644 .claude/commands/agent-os/inject-standards.md delete mode 100644 .claude/commands/agent-os/plan-product.md delete mode 100644 .claude/commands/agent-os/shape-spec.md delete mode 100644 .github/skills/agent-os-discover-standards/SKILL.md delete mode 100644 .github/skills/agent-os-index-standards/SKILL.md delete mode 100644 .github/skills/agent-os-inject-standards/SKILL.md delete mode 100644 .github/skills/agent-os-plan-product/SKILL.md delete mode 100644 .github/skills/agent-os-shape-spec/SKILL.md delete mode 100644 agent-os/standards/index.yml diff --git a/.claude/commands/agent-os/discover-standards.md b/.claude/commands/agent-os/discover-standards.md deleted file mode 100644 index b5de63ee..00000000 --- a/.claude/commands/agent-os/discover-standards.md +++ /dev/null @@ -1,261 +0,0 @@ -# Discover Standards - -Extract tribal knowledge from your codebase into concise, documented standards. - -## Important Guidelines - -- **Always use AskUserQuestion tool** when asking the user anything -- **Write concise standards** — Use minimal words. Standards must be scannable by AI agents without bloating context windows. -- **Offer suggestions** — Present options the user can confirm, choose between, or correct. Don't make them think harder than necessary. - -## Process - -### Step 1: Determine Focus Area - -Check if the user specified an area when running this command. If they did, skip to Step 2. - -If no area was specified: - -1. Analyze the codebase structure (folders, file types, patterns) -2. Identify 3-5 major areas. Examples: - - **Frontend areas:** UI components, styling/CSS, state management, forms, routing - - **Backend areas:** API routes, database/models, authentication, background jobs - - **Cross-cutting:** Error handling, validation, testing, naming conventions, file structure -3. Use AskUserQuestion to present the areas: - -``` -I've identified these areas in your codebase: - -1. **API Routes** (src/api/) — Request handling, response formats -2. **Database** (src/models/, src/db/) — Models, queries, migrations -3. **React Components** (src/components/) — UI patterns, props, state -4. **Authentication** (src/auth/) — Login, sessions, permissions - -Which area should we focus on for discovering standards? (Pick one, or suggest a different area) -``` - -Wait for user response before proceeding. - -### Step 2: Analyze & Present Findings - -Once an area is determined: - -1. Read key files in that area (5-10 representative files) -2. Look for patterns that are: - - **Unusual or unconventional** — Not standard framework/library patterns - - **Opinionated** — Specific choices that could have gone differently - - **Tribal** — Things a new developer wouldn't know without being told - - **Consistent** — Patterns repeated across multiple files - -3. Use AskUserQuestion to present findings and let user select: - -``` -I analyzed [area] and found these potential standards worth documenting: - -1. **API Response Envelope** — All responses use { success, data, error } structure -2. **Error Codes** — Custom error codes like AUTH_001, DB_002 with specific meanings -3. **Pagination Pattern** — Cursor-based pagination with consistent param names - -Which would you like to document? - -Options: -- "Yes, all of them" -- "Just 1 and 3" -- "Add: [your suggestion]" -- "Skip this area" -``` - -Wait for user selection before proceeding. - -### Step 3: Ask Why, Then Draft Each Standard - -**IMPORTANT:** For each selected standard, you MUST complete this full loop before moving to the next standard: - -1. **Ask 1-2 clarifying questions** about the "why" behind the pattern. Use your AskUserQuestion tool for this. -2. **Wait for user response** -3. **Draft the standard** incorporating their answer -4. **Confirm with user** before creating the file -5. **Create the file** if approved - -Example questions to ask (adapt based on the specific standard): - -- "What problem does this pattern solve? Why not use the default/common approach?" -- "Are there exceptions where this pattern shouldn't be used?" -- "What's the most common mistake a developer or agent makes with this?" - -**Do NOT batch all questions upfront.** Process one standard at a time through the full loop. - -### Step 4: Create the Standard File - -For each standard (after completing Step 3's Q&A): - -1. Determine the appropriate folder (create if needed): - - `api/`, `database/`, `javascript/`, `css/`, `backend/`, `testing/`, `global/` - -2. Check if a related standard file already exists — append to it if so - -3. Draft the content and use AskUserQuestion to confirm: - -``` -Here's the draft for api/response-format.md: - ---- -# API Response Format - -All API responses use this envelope: - -\`\`\`json -{ "success": true, "data": { ... } } -{ "success": false, "error": { "code": "...", "message": "..." } } -\`\`\` - -- Never return raw data without the envelope -- Error responses must include both code and message -- Success responses omit the error field entirely ---- - -Create this file? (yes / edit: [your changes] / skip) -``` - -4. Create or update the file in `agent-os/standards/[folder]/` -5. **Then repeat Steps 3-4 for the next selected standard** - -### Step 5: Update the Index - -After all standards are created: - -1. Scan `agent-os/standards/` for all `.md` files -2. For each new file without an index entry, use AskUserQuestion: - -``` -New standard needs an index entry: - File: api/response-format.md - -Suggested description: "API response envelope structure and error format" - -Accept this description? (yes / or type a better one) -``` - -3. Update `agent-os/standards/index.yml`: - -```yaml -api: - response-format: - description: API response envelope structure and error format -``` - -Alphabetize by folder, then by filename. - -### Step 6: Offer to Continue - -Use AskUserQuestion: - -``` -Standards created for [area]: -- api/response-format.md -- api/error-codes.md - -Would you like to discover standards in another area, or are we done? -``` - -## Output Location - -All standards: `agent-os/standards/[folder]/[standard].md` -Index file: `agent-os/standards/index.yml` - -## Writing Concise Standards - -Standards will be injected into AI context windows. Every word costs tokens. Follow these rules: - -- **Lead with the rule** — State what to do first, explain why second (if needed) -- **Use code examples** — Show, don't tell -- **Skip the obvious** — Don't document what the code already makes clear -- **One standard per concept** — Don't combine unrelated patterns -- **Bullet points over paragraphs** — Scannable beats readable - -**Good:** -```markdown -# Error Responses - -Use error codes: `AUTH_001`, `DB_001`, `VAL_001` - -\`\`\`json -{ "success": false, "error": { "code": "AUTH_001", "message": "..." } } -\`\`\` - -- Always include both code and message -- Log full error server-side, return safe message to client -``` - -**Bad:** -```markdown -# Error Handling Guidelines - -When an error occurs in our application, we have established a consistent pattern for how errors should be formatted and returned to the client. This helps maintain consistency across our API and makes it easier for frontend developers to handle errors appropriately... -[continues for 3 more paragraphs] -``` - -## Example: Full Loop for One Standard - -Here's how to process a single standard through the complete workflow: - -**1. Present findings (Step 2):** -``` -I found these patterns in your API code: -1. **Response Envelope** — All responses use { success, data, error } -2. **Error Codes** — Custom codes like AUTH_001 - -Which would you like to document? -``` - -User: "Both" - -**2. Ask why for first standard (Step 3):** -``` -For the Response Envelope pattern: -- What problem does this solve? Why not return raw data? -- Are there any endpoints that don't use this pattern? -``` - -User: "We use it so the frontend always knows where to find the data. All endpoints use it, no exceptions." - -**3. Draft first standard (Step 3 continued):** -``` -Here's the draft for api/response-envelope.md: - ---- -# Response Envelope - -All API responses use this structure: -\`\`\`json -{ "success": true, "data": { ... } } -{ "success": false, "error": { ... } } -\`\`\` - -- Frontend always checks `success` first, then reads `data` or `error` -- No exceptions — every endpoint uses this format ---- - -Create this file? -``` - -User: "Yes" - -**4. Create file, then move to next standard:** - -[Create the file] - -**5. Ask why for second standard (back to Step 3):** -``` -For the Error Codes pattern: -- What's the naming convention for codes? -- Where should new error codes be documented? -``` - -User: "Format is AREA_NUMBER like AUTH_001. We keep a list in the wiki." - -**6. Draft second standard, confirm, create file...** - -[Continue until all selected standards are done] - -**Key point:** Complete the full ask → draft → confirm → create cycle for each standard before starting the next one. diff --git a/.claude/commands/agent-os/index-standards.md b/.claude/commands/agent-os/index-standards.md deleted file mode 100644 index 7967c6f7..00000000 --- a/.claude/commands/agent-os/index-standards.md +++ /dev/null @@ -1,124 +0,0 @@ -# Index Standards - -Rebuild and maintain the standards index file (`index.yml`). - -## Purpose - -The index enables `/inject-standards` to suggest relevant standards without reading all files. It maps each standard to a brief description for quick matching. - -## Process - -### Step 1: Scan for Standards Files - -1. List all `.md` files in `agent-os/standards/` and its subfolders -2. Build a list of all standards organized by folder: - ``` - root/coding-style.md # Files in standards/ root use "root" as the folder name - root/naming.md - api/response-format.md - api/error-handling.md - database/migrations.md - ``` - -**Note:** `root` is a reserved keyword — it refers to `.md` files directly in `agent-os/standards/` (not in a subfolder). Do not create an actual folder named "root". - -### Step 2: Load Existing Index - -Read `agent-os/standards/index.yml` if it exists. Note which entries already have descriptions. - -### Step 3: Identify Changes - -Compare the file scan with the existing index: - -- **New files** — Standards files without index entries -- **Deleted files** — Index entries for files that no longer exist -- **Existing files** — Already indexed, keep as-is - -### Step 4: Handle New Files - -For each new standard file that needs an index entry: - -1. Read the file to understand its content -2. Use AskUserQuestion to propose a description: - -``` -New standard needs indexing: - File: api/response-format.md - -Suggested description: "API response envelope structure and error format" - -Accept? (yes / or type a better description) -``` - -Keep descriptions to **one short sentence** — they're for matching, not documentation. - -### Step 5: Handle Deleted Files - -If there are index entries for files that no longer exist: - -1. List them for the user -2. Remove them from the index automatically (no confirmation needed) - -Report: "Removed 2 stale index entries: api/old-pattern.md, testing/deprecated.md" - -### Step 6: Write Updated Index - -Generate `agent-os/standards/index.yml` with this structure: - -```yaml -folder-name: - file-name: - description: Brief description here -``` - -**Rules:** -- Alphabetize folders -- Alphabetize files within each folder -- File names without `.md` extension -- One-line descriptions only - -**Example:** -```yaml -root: - coding-style: - description: General coding style, formatting, linting rules - naming: - description: File naming, variable naming, class naming conventions - -api: - error-handling: - description: Error codes, exception handling, error response format - response-format: - description: API response envelope structure, status codes, pagination - -database: - migrations: - description: Migration file structure, naming conventions, rollback patterns -``` - -**Note:** `root` appears first and contains standards files that live directly in `agent-os/standards/` (not in subfolders). - -### Step 7: Report Results - -Summarize what changed: - -``` -Index updated: - ✓ 2 new entries added - ✓ 1 stale entry removed - ✓ 8 entries unchanged - -Total: 9 standards indexed -``` - -## When to Run - -- After manually creating or deleting standards files -- If `/inject-standards` suggestions seem out of sync -- To clean up a messy or outdated index - -**Note:** `/discover-standards` runs this automatically as its final step, so you usually don't need to call it separately after discovering standards. - -## Output - -Updates `agent-os/standards/index.yml` diff --git a/.claude/commands/agent-os/inject-standards.md b/.claude/commands/agent-os/inject-standards.md deleted file mode 100644 index f7875a61..00000000 --- a/.claude/commands/agent-os/inject-standards.md +++ /dev/null @@ -1,291 +0,0 @@ -# Inject Standards - -Inject relevant standards into the current context, formatted appropriately for the situation. - -## Usage Modes - -This command supports two modes: - -### Auto-Suggest Mode (no arguments) -``` -/inject-standards -``` -Analyzes context and suggests relevant standards. - -### Explicit Mode (with arguments) -``` -/inject-standards api # All standards in api/ -/inject-standards api/response-format # Single file -/inject-standards api/response-format api/auth # Multiple files -/inject-standards root # All standards in the root folder -/inject-standards root/naming # Single file from root folder -``` -Directly injects specified standards without suggestions. - -**Note:** `root` is a reserved keyword — it refers to `.md` files directly in `agent-os/standards/` (not in a subfolder). - -## Process - -### Step 1: Detect Context Scenario - -Before injecting standards, determine which scenario we're in. Read the current conversation and check if we're in plan mode. - -**Three scenarios:** - -1. **Conversation** — Regular chat, implementing code, answering questions -2. **Creating a Skill** — Building a `.claude/skills/` file -3. **Shaping/Planning** — In plan mode, building a spec, running `/shape-spec` - -**Detection logic:** - -- If currently in plan mode OR conversation clearly mentions "spec", "plan", "shape" → **Shaping/Planning** -- If conversation clearly mentions creating a skill, editing `.claude/skills/`, or building a reusable procedure → **Creating a Skill** -- Otherwise → **Ask to confirm** (do not assume) - -**If neither skill nor plan is clearly detected**, use AskUserQuestion to confirm: - -``` -I'll inject the relevant standards. How should I format them? - -1. **Conversation** — Read standards into our chat (for implementation work) -2. **Skill** — Output file references to include in a skill you're building -3. **Plan** — Output file references to include in a plan/spec - -Which scenario? (1, 2, or 3) -``` - -Always ask when uncertain — don't assume conversation by default. - -### Step 2: Read the Index (Auto-Suggest Mode) - -Read `agent-os/standards/index.yml` to get the list of available standards and their descriptions. - -If index.yml doesn't exist or is empty: -``` -No standards index found. Run /discover-standards first to create standards, -or /index-standards if you have standards files without an index. -``` - -### Step 3: Analyze Work Context - -Look at the current conversation to understand what the user is working on: -- What type of work? (API, database, UI, etc.) -- What technologies mentioned? -- What's the goal? - -### Step 4: Match and Suggest - -Match index descriptions against the context. Use AskUserQuestion to present suggestions: - -``` -Based on your task, these standards may be relevant: - -1. **api/response-format** — API response envelope structure, status codes -2. **api/error-handling** — Error codes, exception handling, error responses -3. **global/naming** — File naming, variable naming conventions - -Inject these standards? (yes / just 1 and 3 / add: database/migrations / none) -``` - -Keep suggestions focused — typically 2-5 standards. Don't overwhelm with too many options. - -### Step 5: Inject Based on Scenario - -Format the output differently based on the detected scenario: - ---- - -#### Scenario: Conversation - -Read the standards and announce them: - -``` -I've read the following standards as they are relevant to what we're working on: - ---- Standard: api/response-format --- - -[full content of the standard file] - ---- End Standard --- - ---- Standard: api/error-handling --- - -[full content of the standard file] - ---- End Standard --- - -**Key points:** -- All API responses use { success, data, error } envelope -- Error codes follow AUTH_xxx, DB_xxx pattern -``` - ---- - -#### Scenario: Creating a Skill - -First, use AskUserQuestion to determine how to include the standards: - -``` -How should these standards be included in your skill? - -1. **References** — Add @ file paths that point to the standards (keeps skill lightweight, standards stay in sync) -2. **Copy content** — Paste the full standards content into the skill (self-contained, but won't update if standards change) - -Which approach? (1 or 2) -``` - -**If References (option 1):** - -``` -Be sure to include references to the following standards files in the appropriate location in the file(s) that make up this skill: - -@agent-os/standards/api/response-format.md -@agent-os/standards/api/error-handling.md -@agent-os/standards/global/naming.md - -These standards cover: -- API response envelope structure, status codes -- Error codes, exception handling, error responses -- File naming, variable naming conventions -``` - -**If Copy content (option 2):** - -``` -Include the following standards content in your skill: - ---- Standard: api/response-format --- - -[full content of the standard file] - ---- End Standard --- - ---- Standard: api/error-handling --- - -[full content of the standard file] - ---- End Standard --- - -These standards cover: -- API response envelope structure, status codes -- Error codes, exception handling, error responses -- File naming, variable naming conventions -``` - ---- - -#### Scenario: Shaping/Planning - -First, use AskUserQuestion to determine how to include the standards: - -``` -How should these standards be included in your plan? - -1. **References** — Add @ file paths that point to the standards (keeps plan lightweight, standards stay in sync) -2. **Copy content** — Paste the full standards content into the plan (self-contained, but won't update if standards change) - -Which approach? (1 or 2) -``` - -**If References (option 1):** - -``` -Be sure to include references to the following standards files in the appropriate location in the plan we're building: - -@agent-os/standards/api/response-format.md -@agent-os/standards/api/error-handling.md -@agent-os/standards/global/naming.md - -These standards cover: -- API response envelope structure, status codes -- Error codes, exception handling, error responses -- File naming, variable naming conventions -``` - -**If Copy content (option 2):** - -``` -Include the following standards content in your plan: - ---- Standard: api/response-format --- - -[full content of the standard file] - ---- End Standard --- - ---- Standard: api/error-handling --- - -[full content of the standard file] - ---- End Standard --- - -These standards cover: -- API response envelope structure, status codes -- Error codes, exception handling, error responses -- File naming, variable naming conventions -``` - ---- - -### Step 6: Surface Related Skills (Conversation scenario only) - -When in conversation scenario, check if `.claude/skills/` exists and contains related skills: - -``` -Related Skills you might want to use: -- create-api-endpoint — Scaffolds new API endpoints following these standards -``` - -Don't invoke skills automatically — just surface them for awareness. - ---- - -## Explicit Mode - -When arguments are provided, skip the suggestion step but still detect scenario. - -### Step 1: Detect Scenario - -Same as auto-suggest mode. - -### Step 2: Parse Arguments - -Arguments can be: -- **Folder name** — `api` → inject all `.md` files in `agent-os/standards/api/` -- **Folder/file** — `api/response-format` → inject `agent-os/standards/api/response-format.md` -- **Root folder** — `root` → inject all `.md` files directly in `agent-os/standards/` (not in subfolders) -- **Root file** — `root/naming` → inject `agent-os/standards/naming.md` - -Multiple arguments inject multiple standards. - -### Step 3: Validate - -Check that specified files/folders exist. If not: - -``` -Standard not found: api/nonexistent - -Available standards in api/: -- response-format -- error-handling -- authentication - -Did you mean one of these? -``` - -### Step 4: Inject Based on Scenario - -Same formatting as auto-suggest mode, based on detected scenario. - ---- - -## Tips - -- **Run early** — Inject standards at the start of a task, before implementation -- **Be specific** — If you know which standards apply, use explicit mode -- **Check the index** — If suggestions seem wrong, run `/index-standards` to rebuild -- **Keep standards concise** — Injected standards consume tokens; shorter is better - -## Integration - -This command is called internally by `/shape-spec` to inject relevant standards during planning. You can also invoke it directly anytime you need standards in context. diff --git a/.claude/commands/agent-os/plan-product.md b/.claude/commands/agent-os/plan-product.md deleted file mode 100644 index bd8bf16e..00000000 --- a/.claude/commands/agent-os/plan-product.md +++ /dev/null @@ -1,204 +0,0 @@ -# Plan Product - -Establish foundational product documentation through an interactive conversation. Creates mission, roadmap, and tech stack files in `agent-os/product/`. - -## Important Guidelines - -- **Always use AskUserQuestion tool** when asking the user anything -- **Keep it lightweight** — gather enough to create useful docs without over-documenting -- **One question at a time** — don't overwhelm with multiple questions - -## Process - -### Step 1: Check for Existing Product Docs - -Check if `agent-os/product/` exists and contains any of these files: -- `mission.md` -- `roadmap.md` -- `tech-stack.md` - -**If any files exist**, use AskUserQuestion: - -``` -I found existing product documentation: -- mission.md: [exists/missing] -- roadmap.md: [exists/missing] -- tech-stack.md: [exists/missing] - -Would you like to: -1. Start fresh (replace all) -2. Update specific files -3. Cancel - -(Choose 1, 2, or 3) -``` - -If option 2, ask which files to update and only gather info for those. -If option 3, stop here. - -**If no files exist**, proceed to Step 2. - -### Step 2: Gather Product Vision (for mission.md) - -Use AskUserQuestion: - -``` -Let's define your product's mission. - -**What problem does this product solve?** - -(Describe the core problem or pain point you're addressing) -``` - -After they respond, use AskUserQuestion: - -``` -**Who is this product for?** - -(Describe your target users or audience) -``` - -After they respond, use AskUserQuestion: - -``` -**What makes your solution unique?** - -(What's the key differentiator or approach?) -``` - -### Step 3: Gather Roadmap (for roadmap.md) - -Use AskUserQuestion: - -``` -Now let's outline your development roadmap. - -**What are the must-have features for launch (MVP)?** - -(List the core features needed for the first usable version) -``` - -After they respond, use AskUserQuestion: - -``` -**What features are planned for after launch?** - -(List features you'd like to add in future phases, or say "none yet") -``` - -### Step 4: Establish Tech Stack (for tech-stack.md) - -First, check if `agent-os/standards/global/tech-stack.md` exists. - -**If the tech-stack standard exists**, read it and use AskUserQuestion: - -``` -I found a tech stack standard in your standards: - -[Summarize the key technologies from global/tech-stack.md] - -Does this project use the same tech stack, or does it differ? - -1. Same as standard (use as-is) -2. Different (I'll specify) - -(Choose 1 or 2) -``` - -If they choose option 1, use the standard's content for tech-stack.md. -If they choose option 2, proceed to ask them to specify (see below). - -**If no tech-stack standard exists** (or they chose option 2 above), use AskUserQuestion: - -``` -**What technologies does this project use?** - -Please describe your tech stack: -- Frontend: (e.g., React, Vue, vanilla JS, or N/A) -- Backend: (e.g., Rails, Node, Django, or N/A) -- Database: (e.g., PostgreSQL, MongoDB, or N/A) -- Other: (hosting, APIs, tools, etc.) -``` - -### Step 5: Generate Files - -Create the `agent-os/product/` directory if it doesn't exist. - -Generate each file based on the information gathered: - -#### mission.md - -```markdown -# Product Mission - -## Problem - -[Insert what problem this product solves - from Step 2] - -## Target Users - -[Insert who this product is for - from Step 2] - -## Solution - -[Insert what makes the solution unique - from Step 2] -``` - -#### roadmap.md - -```markdown -# Product Roadmap - -## Phase 1: MVP - -[Insert must-have features for launch - from Step 3] - -## Phase 2: Post-Launch - -[Insert planned future features - from Step 3, or "To be determined" if they said none yet] -``` - -#### tech-stack.md - -```markdown -# Tech Stack - -[Organize the tech stack information into logical sections] - -## Frontend - -[Frontend technologies, or "N/A" if not applicable] - -## Backend - -[Backend technologies, or "N/A" if not applicable] - -## Database - -[Database choice, or "N/A" if not applicable] - -## Other - -[Other tools, hosting, services - or omit this section if nothing mentioned] -``` - -### Step 6: Confirm Completion - -After creating all files, output to user: - -``` -✓ Product documentation created: - - agent-os/product/mission.md - agent-os/product/roadmap.md - agent-os/product/tech-stack.md - -Review these files to ensure they accurately capture your product vision. -You can edit them directly or run /plan-product again to update. -``` - -## Tips - -- If the user provides very brief answers, that's fine — the docs can be expanded later -- If they want to skip a section, create the file with a placeholder like "To be defined" -- The `/shape-spec` command will read these files when planning features, so having them populated helps with context diff --git a/.claude/commands/agent-os/shape-spec.md b/.claude/commands/agent-os/shape-spec.md deleted file mode 100644 index e06d4853..00000000 --- a/.claude/commands/agent-os/shape-spec.md +++ /dev/null @@ -1,267 +0,0 @@ -# Shape Spec - -Gather context and structure planning for significant work. **Run this command while in plan mode.** - -## Important Guidelines - -- **Always use AskUserQuestion tool** when asking the user anything -- **Offer suggestions** — Present options the user can confirm, adjust, or correct -- **Keep it lightweight** — This is shaping, not exhaustive documentation - -## Prerequisites - -This command **must be run in plan mode**. - -**Before proceeding, check if you are currently in plan mode.** - -If NOT in plan mode, **stop immediately** and tell the user: - -``` -Shape-spec must be run in plan mode. Please enter plan mode first, then run /shape-spec again. -``` - -Do not proceed with any steps below until confirmed to be in plan mode. - -## Process - -### Step 1: Clarify What We're Building - -Use AskUserQuestion to understand the scope: - -``` -What are we building? Please describe the feature or change. - -(Be as specific as you like — I'll ask follow-up questions if needed) -``` - -Based on their response, ask 1-2 clarifying questions if the scope is unclear. Examples: -- "Is this a new feature or a change to existing functionality?" -- "What's the expected outcome when this is done?" -- "Are there any constraints or requirements I should know about?" - -### Step 2: Gather Visuals - -Use AskUserQuestion: - -``` -Do you have any visuals to reference? - -- Mockups or wireframes -- Screenshots of similar features -- Examples from other apps - -(Paste images, share file paths, or say "none") -``` - -If visuals are provided, note them for inclusion in the spec folder. - -### Step 3: Identify Reference Implementations - -Use AskUserQuestion: - -``` -Is there similar code in this codebase I should reference? - -Examples: -- "The comments feature is similar to what we're building" -- "Look at how src/features/notifications/ handles real-time updates" -- "No existing references" - -(Point me to files, folders, or features to study) -``` - -If references are provided, read and analyze them to inform the plan. - -### Step 4: Check Product Context - -Check if `agent-os/product/` exists and contains files. - -If it exists, read key files (like `mission.md`, `roadmap.md`, `tech-stack.md`) and use AskUserQuestion: - -``` -I found product context in agent-os/product/. Should this feature align with any specific product goals or constraints? - -Key points from your product docs: -- [summarize relevant points] - -(Confirm alignment or note any adjustments) -``` - -If no product folder exists, skip this step. - -### Step 5: Surface Relevant Standards - -Read `agent-os/standards/index.yml` to identify relevant standards based on the feature being built. - -Use AskUserQuestion to confirm: - -``` -Based on what we're building, these standards may apply: - -1. **api/response-format** — API response envelope structure -2. **api/error-handling** — Error codes and exception handling -3. **database/migrations** — Migration patterns - -Should I include these in the spec? (yes / adjust: remove 3, add frontend/forms) -``` - -Read the confirmed standards files to include their content in the plan context. - -### Step 6: Generate Spec Folder Name - -Create a folder name using this format: -``` -YYYY-MM-DD-HHMM-{feature-slug}/ -``` - -Where: -- Date/time is current timestamp -- Feature slug is derived from the feature description (lowercase, hyphens, max 40 chars) - -Example: `2026-01-15-1430-user-comment-system/` - -**Note:** If `agent-os/specs/` doesn't exist, create it when saving the spec folder. - -### Step 7: Structure the Plan - -Now build the plan with **Task 1 always being "Save spec documentation"**. - -Present this structure to the user: - -``` -Here's the plan structure. Task 1 saves all our shaping work before implementation begins. - ---- - -## Task 1: Save Spec Documentation - -Create `agent-os/specs/{folder-name}/` with: - -- **plan.md** — This full plan -- **shape.md** — Shaping notes (scope, decisions, context from our conversation) -- **standards.md** — Relevant standards that apply to this work -- **references.md** — Pointers to reference implementations studied -- **visuals/** — Any mockups or screenshots provided - -## Task 2: [First implementation task] - -[Description based on the feature] - -## Task 3: [Next task] - -... - ---- - -Does this plan structure look right? I'll fill in the implementation tasks next. -``` - -### Step 8: Complete the Plan - -After Task 1 is confirmed, continue building out the remaining implementation tasks based on: -- The feature scope from Step 1 -- Patterns from reference implementations (Step 3) -- Constraints from standards (Step 5) - -Each task should be specific and actionable. - -### Step 9: Ready for Execution - -When the full plan is ready: - -``` -Plan complete. When you approve and execute: - -1. Task 1 will save all spec documentation first -2. Then implementation tasks will proceed - -Ready to start? (approve / adjust) -``` - -## Output Structure - -The spec folder will contain: - -``` -agent-os/specs/{YYYY-MM-DD-HHMM-feature-slug}/ -├── plan.md # The full plan -├── shape.md # Shaping decisions and context -├── standards.md # Which standards apply and key points -├── references.md # Pointers to similar code -└── visuals/ # Mockups, screenshots (if any) -``` - -## shape.md Content - -The shape.md file should capture: - -```markdown -# {Feature Name} — Shaping Notes - -## Scope - -[What we're building, from Step 1] - -## Decisions - -- [Key decisions made during shaping] -- [Constraints or requirements noted] - -## Context - -- **Visuals:** [List of visuals provided, or "None"] -- **References:** [Code references studied] -- **Product alignment:** [Notes from product context, or "N/A"] - -## Standards Applied - -- api/response-format — [why it applies] -- api/error-handling — [why it applies] -``` - -## standards.md Content - -Include the full content of each relevant standard: - -```markdown -# Standards for {Feature Name} - -The following standards apply to this work. - ---- - -## api/response-format - -[Full content of the standard file] - ---- - -## api/error-handling - -[Full content of the standard file] -``` - -## references.md Content - -```markdown -# References for {Feature Name} - -## Similar Implementations - -### {Reference 1 name} - -- **Location:** `src/features/comments/` -- **Relevance:** [Why this is relevant] -- **Key patterns:** [What to borrow from this] - -### {Reference 2 name} - -... -``` - -## Tips - -- **Keep shaping fast** — Don't over-document. Capture enough to start, refine as you build. -- **Visuals are optional** — Not every feature needs mockups. -- **Standards guide, not dictate** — They inform the plan but aren't always mandatory. -- **Specs are discoverable** — Months later, someone can find this spec and understand what was built and why. diff --git a/.github/INVENTORY.md b/.github/INVENTORY.md index e3f0f783..08b32a28 100644 --- a/.github/INVENTORY.md +++ b/.github/INVENTORY.md @@ -34,11 +34,6 @@ This file is the exact path inventory for the live GitHub Copilot catalog in thi - `.github/skills/addyosmani-code-review-and-quality/SKILL.md` - `.github/skills/addyosmani-code-simplification/SKILL.md` -- `.github/skills/agent-os-discover-standards/SKILL.md` -- `.github/skills/agent-os-index-standards/SKILL.md` -- `.github/skills/agent-os-inject-standards/SKILL.md` -- `.github/skills/agent-os-plan-product/SKILL.md` -- `.github/skills/agent-os-shape-spec/SKILL.md` - `.github/skills/anthropic-docx/SKILL.md` - `.github/skills/anthropic-pdf/SKILL.md` - `.github/skills/anthropic-pptx/SKILL.md` diff --git a/.github/skills/agent-os-discover-standards/SKILL.md b/.github/skills/agent-os-discover-standards/SKILL.md deleted file mode 100644 index e741dd60..00000000 --- a/.github/skills/agent-os-discover-standards/SKILL.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: agent-os-discover-standards -description: Portable workflow for discovering concise project standards and writing them to agent-os/standards/ for Copilot and Codex sessions without Claude slash-command dependencies. ---- - -# Agent OS Discover Standards - -## Referenced skills - -- `agent-os-index-standards`: on-demand refresh of `agent-os/standards/index.yml` after standard files are added or removed. - -## When to use - -- You need to discover tribal conventions from code and store them as reusable standards. -- The target output is one or more files under `agent-os/standards/`. -- You want a Copilot/Codex-friendly flow with explicit user confirmations. - -## When not to use - -- You only need to rebuild the index; use `agent-os-index-standards`. -- You are implementing code changes rather than documenting standards. -- You need to execute standards, not author or refine them. - -## Workflow - -1. Propose a focused area to inspect (or confirm the area provided by the user). -2. Review representative files and extract only non-obvious, repeated, opinionated patterns. -3. For each candidate standard, ask 1-2 short why/exceptions questions before drafting. -4. Draft one concise standard at a time and request explicit approval before writing. -5. Write approved files to `agent-os/standards//.md`; append to a related existing file instead of creating a duplicate. -6. After finishing one area, offer to discover standards in another area or stop. -7. Refresh the index with `agent-os-index-standards` when file changes are complete. - -## Boundaries - -- Keep standards concise and scannable for AI context windows. -- Do not copy framework defaults unless they are project-specific constraints. -- Do not write files without user confirmation. - -## Validation - -- New standards are located under `agent-os/standards/`. -- Each standard contains one concept with concrete examples when useful. -- `agent-os/standards/index.yml` is updated after additions or deletions. - -## Source command parity - -- Derived from `.claude/commands/agent-os/discover-standards.md`. -- Runtime language is portable for Copilot and Codex and does not rely on Claude slash commands. diff --git a/.github/skills/agent-os-index-standards/SKILL.md b/.github/skills/agent-os-index-standards/SKILL.md deleted file mode 100644 index 8a830fb5..00000000 --- a/.github/skills/agent-os-index-standards/SKILL.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -name: agent-os-index-standards -description: Portable workflow for rebuilding agent-os/standards/index.yml from standards files with deterministic ordering and short descriptions. ---- - -# Agent OS Index Standards - -## Referenced skills - -- None. - -## When to use - -- `agent-os/standards/index.yml` is stale, missing entries, or includes deleted files. -- Standards files were recently added, renamed, or removed. - -## When not to use - -- You need to discover new standards from code; use `agent-os-discover-standards`. -- You need to inject standards into a conversation or plan; use `agent-os-inject-standards`. - -## Workflow - -1. Scan `agent-os/standards/` recursively for `.md` files. -2. Interpret files in `agent-os/standards/` root as the reserved folder key `root`. -3. Load the current `agent-os/standards/index.yml` when present. -4. For each new file, propose a one-sentence description and confirm it before writing. -5. Remove stale index entries for deleted files automatically. -6. Write YAML sorted by folder name and then file name. -7. Report what changed: entries added, removed, and unchanged. - -## Boundaries - -- Keep descriptions to one short sentence. -- Use filenames without `.md` extension in index keys. -- Do not create a physical `root/` folder. - -## Validation - -- Every standard file has an index entry. -- No index entry points to a missing file. -- Ordering is deterministic (alphabetical folders, alphabetical file keys). - -## Source command parity - -- Derived from `.claude/commands/agent-os/index-standards.md`. -- Runtime language is portable for Copilot and Codex and does not rely on Claude slash commands. diff --git a/.github/skills/agent-os-inject-standards/SKILL.md b/.github/skills/agent-os-inject-standards/SKILL.md deleted file mode 100644 index 176d1045..00000000 --- a/.github/skills/agent-os-inject-standards/SKILL.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: agent-os-inject-standards -description: Portable workflow for selecting and injecting relevant standards from agent-os/standards/ into implementation, skill-authoring, or planning contexts. ---- - -# Agent OS Inject Standards - -## Referenced skills - -- `agent-os-index-standards`: on-demand repair when `agent-os/standards/index.yml` is missing or stale. - -## When to use - -- You need standards context for code work, planning, or skill authoring. -- You want automatic suggestions from `agent-os/standards/index.yml`. -- You need explicit injection of chosen folders or files. - -## When not to use - -- You need to create new standards from source code; use `agent-os-discover-standards`. -- You need only to refresh index metadata; use `agent-os-index-standards`. - -## Workflow - -1. Determine scenario: conversation, skill authoring, or planning. -2. In auto mode, read `agent-os/standards/index.yml` and propose 2-5 relevant standards. -3. In explicit mode, resolve folder/file targets directly, treating `root` as the reserved key for files directly in `agent-os/standards/`. -4. In explicit mode, if a target is missing, list available standards in that folder and ask for the intended one instead of injecting. -5. Confirm what to include, then inject either file references or full content. -6. In the conversation scenario, surface related repository skills by name for awareness without invoking them. -7. If index is missing or empty, stop and request indexing via `agent-os-index-standards`. - -## Boundaries - -- Do not auto-load unrelated standards. -- Ask for confirmation when scenario is ambiguous. -- Keep output focused and lightweight. -- Surface related skills only; never invoke them automatically. - -## Validation - -- Injected standards exist on disk under `agent-os/standards/`. -- Scenario-specific format is respected (conversation vs. skill vs. plan). -- Suggestions remain narrow and relevant to the active task. - -## Source command parity - -- Derived from `.claude/commands/agent-os/inject-standards.md`. -- Runtime language is portable for Copilot and Codex and does not rely on Claude slash commands. diff --git a/.github/skills/agent-os-plan-product/SKILL.md b/.github/skills/agent-os-plan-product/SKILL.md deleted file mode 100644 index cb746b43..00000000 --- a/.github/skills/agent-os-plan-product/SKILL.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: agent-os-plan-product -description: Portable workflow for creating or updating agent-os/product mission, roadmap, and tech-stack documents through lightweight guided questions. ---- - -# Agent OS Plan Product - -## Referenced skills - -- `agent-os-inject-standards`: on-demand lookup of relevant standards, including `agent-os/standards/global/tech-stack.md` when present. - -## When to use - -- Product context docs are missing or outdated in `agent-os/product/`. -- You need a lightweight mission, roadmap, and tech-stack baseline for later planning. - -## When not to use - -- You are shaping a concrete feature spec; use `agent-os-shape-spec`. -- You only need one small edit in product docs without guided discovery. - -## Workflow - -1. Check which files already exist: `mission.md`, `roadmap.md`, `tech-stack.md`. -2. If files exist, ask whether to replace all, update selected files, or cancel. -3. Collect concise inputs for product problem, target users, and differentiator. -4. Collect MVP and post-launch feature priorities. -5. Reuse `agent-os/standards/global/tech-stack.md` when applicable, otherwise collect stack details. -6. Write or update files under `agent-os/product/` with clear sections. - -## Boundaries - -- Do not overwrite existing docs without explicit user confirmation. -- Keep content concise and editable. -- If answers are incomplete, use clear placeholders instead of inventing detail. - -## Validation - -- Target files exist under `agent-os/product/` after approval. -- Content reflects user-provided inputs and selected update mode. -- Tech stack section clearly distinguishes frontend, backend, database, and other tools when relevant. - -## Source command parity - -- Derived from `.claude/commands/agent-os/plan-product.md`. -- Runtime language is portable for Copilot and Codex and does not rely on Claude slash commands. diff --git a/.github/skills/agent-os-shape-spec/SKILL.md b/.github/skills/agent-os-shape-spec/SKILL.md deleted file mode 100644 index 2ccb64bd..00000000 --- a/.github/skills/agent-os-shape-spec/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: agent-os-shape-spec -description: Portable workflow for shaping significant work into agent-os/specs// with clear scope, references, standards, and execution-ready tasks. ---- - -# Agent OS Shape Spec - -## Referenced skills - -- `agent-os-inject-standards`: on-demand discovery and inclusion of relevant standards during shaping. -- `agent-os-plan-product`: on-demand product-context refresh when `agent-os/product/` context is missing or stale. - -## When to use - -- Significant work needs explicit shaping before implementation. -- You need to save reusable planning artifacts under `agent-os/specs/`. - -## When not to use - -- The request is a small direct edit with clear validation. -- You are not in a planning context and no spec package is needed. - -## Workflow - -1. Confirm planning context and feature scope with short clarification questions. -2. Collect optional visuals and reference implementations. -3. Read product context from `agent-os/product/` when available. -4. Identify relevant standards from `agent-os/standards/index.yml` and confirm inclusion. -5. Create `agent-os/specs/YYYY-MM-DD-HHMM-/`. -6. Build an execution plan where Task 1 is always saving spec documentation. -7. Prepare `plan.md`, `shape.md`, `standards.md`, `references.md`, and `visuals/` as applicable. - -## Boundaries - -- Use explicit user approval language; do not rely on Claude-only plan-mode mechanics. -- Keep shaping lightweight and actionable. -- Do not auto-start implementation from shaping output without approval. - -## Validation - -- Spec folder uses `YYYY-MM-DD-HHMM-` naming under `agent-os/specs/`. -- Task 1 in `plan.md` is "Save spec documentation". -- Supporting files capture scope, decisions, standards, and references relevant to the work. - -## Source command parity - -- Derived from `.claude/commands/agent-os/shape-spec.md`. -- Runtime language is portable for Copilot and Codex and does not rely on Claude slash commands. diff --git a/Makefile b/Makefile index afdcae68..741add58 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ RUFF := $(if $(wildcard $(SCRIPTS_VENV)/bin/ruff),$(SCRIPTS_VENV)/bin/ruff,ruff) CATALOG_FAST_TESTS := tests/github/scripts/lib/test_inventory.py tests/github/scripts/lib/test_repo_paths.py tests/github/scripts/test_install_graphify_hooks.py tests/github/scripts/test_run_sh_dispatch.py tests/test_repository_test_layout_contract.py CATALOG_FAST_INCLUDE_TOKEN_RISKS ?= 0 MARKDOWNLINT_VERSION := 0.18.1 -MARKDOWNLINT_PATTERNS := "**/*.md" "\#tmp/**" "\#graphify-out/**" "\#.graphify_*" "\#.claude/commands/agent-os/**" +MARKDOWNLINT_PATTERNS := "**/*.md" "\#tmp/**" "\#graphify-out/**" "\#.graphify_*" .PHONY: help python-version-check lint catalog-lint catalog-fast-check github-catalog-validation test scripts-bootstrap catalog-check catalog-audit inventory-build token-risks skill-lint docs-lint all diff --git a/agent-os/standards/index.yml b/agent-os/standards/index.yml deleted file mode 100644 index 769180c3..00000000 --- a/agent-os/standards/index.yml +++ /dev/null @@ -1,2 +0,0 @@ -# Agent OS Standards Index - diff --git a/tests/github/skills/internal-aws/test_internal_aws_routing_contract.py b/tests/github/skills/internal-aws/test_internal_aws_routing_contract.py index eda79e3e..3b24d16a 100644 --- a/tests/github/skills/internal-aws/test_internal_aws_routing_contract.py +++ b/tests/github/skills/internal-aws/test_internal_aws_routing_contract.py @@ -128,7 +128,7 @@ def test_specialists_name_internal_aws_only_as_uncertainty_fallback() -> None: ) SKILL_REFERENCE_PATTERN = re.compile( - r"`((?:internal|awesome|openai|superpowers|agent-os|antigravity|addyosmani" + r"`((?:internal|awesome|openai|superpowers|antigravity|addyosmani" r"|local|mattpocock|terraform|vercel|customize|grill|graphify)-[a-z0-9-]+)`" ) diff --git a/tests/github/skills/internal-azure/test_internal_azure_routing_contract.py b/tests/github/skills/internal-azure/test_internal_azure_routing_contract.py index 4aee4676..faed1cfc 100644 --- a/tests/github/skills/internal-azure/test_internal_azure_routing_contract.py +++ b/tests/github/skills/internal-azure/test_internal_azure_routing_contract.py @@ -147,7 +147,7 @@ def test_specialists_name_internal_azure_only_as_uncertainty_fallback() -> None: ) SKILL_REFERENCE_PATTERN = re.compile( - r"`((?:internal|awesome|openai|superpowers|agent-os|antigravity|addyosmani" + r"`((?:internal|awesome|openai|superpowers|antigravity|addyosmani" r"|local|mattpocock|terraform|vercel|customize|grill|graphify)-[a-z0-9-]+)`" ) diff --git a/tests/github/skills/internal-gcp/test_internal_gcp_routing_contract.py b/tests/github/skills/internal-gcp/test_internal_gcp_routing_contract.py index f9a27b08..fdd7c6cf 100644 --- a/tests/github/skills/internal-gcp/test_internal_gcp_routing_contract.py +++ b/tests/github/skills/internal-gcp/test_internal_gcp_routing_contract.py @@ -144,7 +144,7 @@ def test_specialists_name_internal_gcp_only_as_uncertainty_fallback() -> None: ) SKILL_REFERENCE_PATTERN = re.compile( - r"`((?:internal|awesome|openai|superpowers|agent-os|antigravity|addyosmani" + r"`((?:internal|awesome|openai|superpowers|antigravity|addyosmani" r"|local|mattpocock|terraform|vercel|customize|grill|graphify)-[a-z0-9-]+)`" ) diff --git a/tests/github/skills/internal-github/test_internal_github_routing_contract.py b/tests/github/skills/internal-github/test_internal_github_routing_contract.py index 51901d84..f53c398f 100644 --- a/tests/github/skills/internal-github/test_internal_github_routing_contract.py +++ b/tests/github/skills/internal-github/test_internal_github_routing_contract.py @@ -142,7 +142,7 @@ def test_specialists_name_internal_github_only_as_uncertainty_fallback() -> None ) SKILL_REFERENCE_PATTERN = re.compile( - r"`((?:internal|awesome|openai|superpowers|agent-os|antigravity|addyosmani" + r"`((?:internal|awesome|openai|superpowers|antigravity|addyosmani" r"|local|mattpocock|terraform|vercel|customize|grill|graphify)-[a-z0-9-]+)`" ) From 5b4b01df4a1a25e4a3ab50616fed04ee2e62f5a3 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 23:34:45 +0200 Subject: [PATCH 10/23] feat: remove deprecated internal-review-ai-resources skill and related files; enhance internal-skill-creator description; add tests for lifecycle and retirement coverage --- .github/INVENTORY.md | 2 - .../internal-gateway-review-generic.agent.md | 2 +- .../internal-review-ai-resources.prompt.md | 85 ----------- .github/scripts/lib/token_risks.py | 29 ---- .../internal-review-ai-resources/SKILL.md | 125 ---------------- .../agents/openai.yaml | 4 - .../references/report-contract.md | 139 ------------------ .../references/review-checklist.md | 84 ----------- .../references/review-profiles.md | 97 ------------ .../review-usefulness-replay-fixture.md | 41 ------ .../skills/internal-skill-creator/SKILL.md | 19 ++- .../internal-skill-creator/agents/openai.yaml | 2 +- .../references/authoring-and-evaluation.md | 28 ++++ ...nternal_gateway_review_generic_contract.py | 30 ++++ .../test_report_contract.py | 87 ----------- .../test_internal_skill_creator_contract.py | 33 +++++ ...est_retired_ai_resource_review_contract.py | 25 ++++ 17 files changed, 131 insertions(+), 701 deletions(-) delete mode 100644 .github/prompts/internal-review-ai-resources.prompt.md delete mode 100644 .github/skills/internal-review-ai-resources/SKILL.md delete mode 100644 .github/skills/internal-review-ai-resources/agents/openai.yaml delete mode 100644 .github/skills/internal-review-ai-resources/references/report-contract.md delete mode 100644 .github/skills/internal-review-ai-resources/references/review-checklist.md delete mode 100644 .github/skills/internal-review-ai-resources/references/review-profiles.md delete mode 100644 .github/skills/internal-review-ai-resources/references/review-usefulness-replay-fixture.md create mode 100644 tests/github/agents/test_internal_gateway_review_generic_contract.py delete mode 100644 tests/github/skills/internal-review-ai-resources/test_report_contract.py create mode 100644 tests/github/skills/internal-skill-creator/test_retired_ai_resource_review_contract.py diff --git a/.github/INVENTORY.md b/.github/INVENTORY.md index 08b32a28..25d5ace7 100644 --- a/.github/INVENTORY.md +++ b/.github/INVENTORY.md @@ -112,7 +112,6 @@ This file is the exact path inventory for the live GitHub Copilot catalog in thi - `.github/skills/internal-python-project/SKILL.md` - `.github/skills/internal-python-script/SKILL.md` - `.github/skills/internal-python/SKILL.md` -- `.github/skills/internal-review-ai-resources/SKILL.md` - `.github/skills/internal-review-code/SKILL.md` - `.github/skills/internal-review-high-level/SKILL.md` - `.github/skills/internal-skill-creator/SKILL.md` @@ -202,4 +201,3 @@ These vendor-prefixed imported document skills remain support-only depth for rep - `.github/prompts/internal-architecture-md-creator.prompt.md` - `.github/prompts/internal-mega-review.prompt.md` -- `.github/prompts/internal-review-ai-resources.prompt.md` diff --git a/.github/agents/internal-gateway-review-generic.agent.md b/.github/agents/internal-gateway-review-generic.agent.md index 7678950e..9af67e18 100644 --- a/.github/agents/internal-gateway-review-generic.agent.md +++ b/.github/agents/internal-gateway-review-generic.agent.md @@ -48,7 +48,7 @@ Evaluate the target through the dimensions that apply to its surface: ## Generic Review Surfaces -- **AI resources:** agents, skills, prompts, instructions, bundle siblings, catalog entries, sync behavior, and customization drift. +- **AI resources:** agents, skills, prompts, instructions, bundle siblings, catalog entries, sync behavior, and customization drift. For material changes, check compatibility, propagation, periodic review, and retirement readiness using affected inventory, sync, validators, and tests; record an explicit evidence gap when a surface is unavailable. - **Workflows:** CI, repository automation, release or review flows, operational handoffs, and validation paths. - **Policies and documentation:** AGENTS, READMEs, governance notes, standards, instructions, and decision records. - **Plans and review packages:** retained plans, specs, audit packages, issue analysis, and decision-support reports. diff --git a/.github/prompts/internal-review-ai-resources.prompt.md b/.github/prompts/internal-review-ai-resources.prompt.md deleted file mode 100644 index 43787636..00000000 --- a/.github/prompts/internal-review-ai-resources.prompt.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -name: "internal-review-ai-resources" -agent: "internal-gateway-review-generic" -description: "Review repository-owned AI resources, referenced assets, and flow behavior across AGENTS.md and .github" -argument-hint: "Target one file, one or more folders, the full AI catalog, or an existing retained report package" ---- - - - -Primary goal: -${input:goal:Describe why this review is needed and what decision it must support} - -Review target: -${input:target:List one resource, several folders, the full AI catalog, or an existing retained report package} - -Consumer surfaces: -${input:consumers:List relevant consumers such as GitHub Copilot, Codex, local sync, or write infer from repository evidence} - -Known local assumptions or concerns: -${input:assumptions:List internal wrappers, imported-resource posture, known drift, prior findings, or write infer from repository evidence} - -Desired depth: -${input:depth:Choose concise, detailed, or exhaustive; default to detailed when unsure} - -Constraints and exclusions: -${input:constraints:List no-touch areas, rollout constraints, evidence limits, or explicit exclusions} - -Output preference: -${input:output:Write chat-only, retained report under tmp/, or infer from target size} - -For `chat-only`, use the adaptive chat projection owned by the selected review -lane. For retained output, preserve the retained report contract and return a -compact chat summary with the retained path. - -Use these repository sources first: - -- [AGENTS.md](../../AGENTS.md) -- [.github/copilot-instructions.md](../copilot-instructions.md) -- [.github/INVENTORY.md](../INVENTORY.md) -- [INTERNAL_CONTRACT.md](../../INTERNAL_CONTRACT.md) -- [.github/agents/internal-gateway-review-generic.agent.md](../agents/internal-gateway-review-generic.agent.md) -- [.github/skills/internal-review-ai-resources/SKILL.md](../skills/internal-review-ai-resources/SKILL.md) - -Then use `internal-review-ai-resources` as the reusable qualitative owner for -profile selection, target coverage, lifecycle checks, report shape, and bundle -review depth. - -Review target may be one resource path, one or more folders, the full AI -catalog, or an existing retained review package under `tmp/`. Use the skill to -select `focused`, `bundle`, `catalog`, or `retained-report` and keep the review -analysis-only. - -If the target is a skill bundle, treat the bundle root plus existing -`references/`, `scripts/`, `assets/`, and `agents/openai.yaml` as in scope. - -Load additional repository skills only when the target or its evidence path -needs their owner rules. In particular, load -`internal-copilot-audit` only when overlap, hollow references, stale contracts, -naming drift, or governance drift findings are needed. Do not load every skill -only because it exists. - -Use `LESSONS_LEARNED.md` only when it is explicitly in the target, referenced by -an in-scope resource, or needed to verify a retained-learning claim. Treat it as -non-canonical retained evidence until codified in the smallest valid owner. - -The review is analysis-only. Do not modify the reviewed resources. If retained -analysis is needed, write only under `tmp/`. - -Do not name vendor-specific reasoning engines or compare them. Review consumer -surfaces, contracts, and repository behavior instead. - -Do not produce an encyclopedic review. Include only real problems, important -tradeoffs, recommended decisions, blocking uncertainties, and high-ROI quick -wins. If a resource has no meaningful problem, use an explicit keep result and -move on. - -Do not propose new technology before diagnosing the existing repository -correctly. - -## Language Rules - -- Write the final analysis and summary in the language of the current chat. -- If the current chat language is ambiguous or mixed, prefer Italian. -- Keep file paths, enum values, evidence labels, status labels, and command names - exactly as requested. diff --git a/.github/scripts/lib/token_risks.py b/.github/scripts/lib/token_risks.py index 2b0cbff4..77df6e52 100644 --- a/.github/scripts/lib/token_risks.py +++ b/.github/scripts/lib/token_risks.py @@ -21,8 +21,6 @@ INVENTORY_LINE_PATTERN = re.compile(r"^- `?\.github/[^`]+`?(?::|\s*$)") IMPORTED_SKILL_DESCRIPTION_LIMIT = 500 ESTIMATED_TOKEN_BYTES = 4 -DELEGATED_REVIEW_PROMPT_PATH = ".github/prompts/internal-review-ai-resources.prompt.md" -DELEGATED_REVIEW_PROMPT_TOKEN_TARGET = 1100 ROOT_ALWAYS_ON_PATHS = ("AGENTS.md",) ROOT_ALWAYS_ON_TOKEN_TARGET = 4000 COPILOT_REVIEW_PATH = ".github/copilot-instructions.md" @@ -60,7 +58,6 @@ def detect_token_risks(root: Path) -> list[Finding]: findings.extend(check_agents_operational_procedure_markers(root)) findings.extend(check_root_always_on_budget(root)) findings.extend(check_copilot_review_budget(root)) - findings.extend(check_delegated_review_prompt_budget(root)) findings.extend(check_review_baseline_window(root)) findings.extend(check_inventory_dumps(root)) findings.extend(check_duplicate_markdown_bodies(root)) @@ -127,32 +124,6 @@ def check_copilot_review_budget(root: Path) -> list[Finding]: ] -def check_delegated_review_prompt_budget(root: Path) -> list[Finding]: - path = root / DELEGATED_REVIEW_PROMPT_PATH - if not path.exists(): - return [] - - estimated_tokens = estimate_tokens(path) - if estimated_tokens <= DELEGATED_REVIEW_PROMPT_TOKEN_TARGET: - return [] - - return [ - Finding( - severity="non-blocking", - code="delegated-review-prompt-budget", - path=DELEGATED_REVIEW_PROMPT_PATH, - message=( - "The delegated AI resource review prompt exceeds its soft token target " - f"({estimated_tokens} estimated tokens, target {DELEGATED_REVIEW_PROMPT_TOKEN_TARGET})." - ), - suggestion=( - "Keep user inputs and the analysis-only boundary in the prompt, but move reusable workflow " - "detail into .github/skills/internal-review-ai-resources/." - ), - ) - ] - - def check_agents_operational_procedure_markers(root: Path) -> list[Finding]: path = root / "AGENTS.md" if not path.exists(): diff --git a/.github/skills/internal-review-ai-resources/SKILL.md b/.github/skills/internal-review-ai-resources/SKILL.md deleted file mode 100644 index bc859a7f..00000000 --- a/.github/skills/internal-review-ai-resources/SKILL.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -name: internal-review-ai-resources -description: Use when reviewing repository-owned AI resources, bundle siblings, catalog workflows, or retained AI review packages before deciding keep, patch, split, compress, or retire actions. ---- - -# Internal Review AI Resources - -## Referenced skills - -This index lists every other skill that this file asks the agent to load, route to, compare against, or delegate to. - -- `internal-copilot-audit`: on-demand drift lens for overlap, hollow references, stale contracts, naming drift, and governance drift. - -Use this skill as the qualitative review owner for repository-owned AI -resources and retained AI review packages. It owns profile selection, -evidence-first qualitative review, lifecycle checks, and proportional -reporting. Keep `internal-copilot-audit` as the drift lens instead of copying -its audit order here. - -## When to use - -- Review one AI asset, a bundle root, several catalog folders, or a retained - review package under `tmp/`. -- Decide whether to keep, wrap, patch, split, merge, move, retire, compress, - automate, or review later. -- Check how AI resources are consumed across prompts, agents, skills, - validators, tests, inventory, and sync helpers. -- Evaluate lifecycle posture such as compatibility, propagation, periodic - review, and retirement readiness. - -## When not to use - -- Use `internal-copilot-audit` when the primary goal is overlap, hollow - references, stale contracts, or governance drift findings. -- Use the owning delivery lane when the task is already approved - implementation instead of analysis. -- Use deterministic validators and tests for enforcement; do not turn this - skill into a validator replacement. -- Do not review unrelated application or infrastructure files unless an - in-scope AI resource references them. - -## Reviewable families - -Reviewable families: see `references/review-profiles.md` 'Family coverage baseline'. - -## Review profiles - -Load `references/review-profiles.md` when choosing scope or escalating beyond -one file. - -- `focused`: one file or one narrow resource plus its direct evidence path. -- `bundle`: one bundle owner plus existing siblings and local propagation - paths. -- `catalog`: cross-family review of the repository AI catalog and its - validators. -- `retained-report`: review an existing retained report package against live - repository evidence. - -## Evidence-first workflow - -1. Resolve the target to the smallest correct profile. For skill bundle - targets, keep the bundle root and existing siblings in scope. -2. Read `AGENTS.md`, `.github/copilot-instructions.md`, the target owner, and - the nearest validators or tests. -3. Build a local consumption map: who selects the resource, what it - references, which validators prove it, and what propagation surfaces must - stay aligned. -4. Load `references/review-checklist.md` for lifecycle, flow, context, - validation, sync, and propagation checks sized to the chosen profile. -5. Load `internal-copilot-audit` only when the review needs overlap, - hollow-reference, stale-contract, naming, or governance-drift findings. -6. Load `references/report-contract.md` before writing the final review so - evidence labels, decision vocabulary, and completeness checks stay - proportional to the profile. -7. Use `references/review-usefulness-replay-fixture.md` as the illustrative - output shape when changing the decision-usefulness behavior of AI-resource reviews. - -## Core review rules - -- When this skill reviews itself, name the rationalization risk explicitly and prefer evidence from external consumers over self-cited compliance. -- Stay analysis-only unless the user explicitly changes lanes into delivery. -- Keep one generic review lane across prompts, skills, agents, catalog - helpers, and retained packages; do not split the owner by resource family - unless evidence shows the boundary is broken. -- Treat bundle siblings as default in-scope evidence for bundle reviews. If a - sibling is intentionally out of scope, say so explicitly. -- Distinguish consumption from mere existence. Prefer findings backed by agent - routing, prompt references, validators, sync catalogs, or tests. -- Prefer the smallest evidence path that can prove a claim. Read more only when - the next claim cannot be supported locally. -- Keep deterministic controls in validators and tests. Use this skill for - qualitative judgment, not hidden enforcement. -- When a recommendation would change propagation, include the affected - inventory, sync, validator, and test surfaces in scope before finalizing the - recommendation. - -## Bundle coverage rules - -Bundle coverage rules: see `references/review-profiles.md` 'bundle minimum evidence pass'. Checked surfaces with no defect belong in the evidence digest or decision trace, not as findings. - -## Output - -- Chat projection: see `references/report-contract.md` 'Chat projection'. -- Retained output: see `references/report-contract.md` 'Retained output'. - -The review output should always be decision-useful and include an explicit -no-findings result when no material findings exist. - -## Validation - -- The selected profile matches the target and escalation rules in - `references/review-profiles.md`. -- The review covers the relevant resource families for the chosen profile. -- Bundle reviews include existing `references/`, `scripts/`, `assets/`, and - `agents/openai.yaml`, or explicitly mark intentional non-action. -- Bundle reviews distinguish coverage from findings and compress checked-clean - surfaces into evidence digest or decision trace. -- Lifecycle, compatibility, propagation, periodic review, and retirement checks - are available through `references/review-checklist.md`. -- `internal-copilot-audit` is used as a named drift lens when those findings - are needed, not copied inline. -- The final output follows `references/report-contract.md` and stays - proportional to the chosen profile. -- Decision-usefulness contract changes preserve the behavior captured in - `references/review-usefulness-replay-fixture.md` illustrative output shape. diff --git a/.github/skills/internal-review-ai-resources/agents/openai.yaml b/.github/skills/internal-review-ai-resources/agents/openai.yaml deleted file mode 100644 index 93fb32d7..00000000 --- a/.github/skills/internal-review-ai-resources/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Internal Review AI Resources" - short_description: "Review internal AI resource bundles" - default_prompt: "Use $internal-review-ai-resources to assess an AI resource, bundle, or catalog path, use the adaptive chat projection for the user-facing result, and recommend keep, patch, split, or retire actions." diff --git a/.github/skills/internal-review-ai-resources/references/report-contract.md b/.github/skills/internal-review-ai-resources/references/report-contract.md deleted file mode 100644 index 4db1d717..00000000 --- a/.github/skills/internal-review-ai-resources/references/report-contract.md +++ /dev/null @@ -1,139 +0,0 @@ -# Report Contract - -Use this reference before writing the final review. Keep output proportional to -the selected profile. - -## Evidence labels - -Use short, explicit evidence labels in findings and recommendations: - -- `file`: direct file content proves the claim -- `bundle`: a bundle root plus siblings prove the claim -- `validator`: a validator or script output proves the claim -- `test`: a focused test proves the claim -- `test-gap`: a missing focused test is the supported risk -- `sync`: sync catalog or runtime support evidence proves the claim -- `runtime-artifact`: live prompt pack, generated artifact, or fixture evidence - proves the runtime-facing behavior -- `retained`: a retained package supports the claim, but live verification is - still required -- `gap`: evidence is missing, stale, or unverifiable -- `uncertain`: the claim remains plausible but not proven by available evidence - -## Decision vocabulary - -Use one primary action per finding or summary line: - -- `KEEP` -- `PATCH` -- `WRAP` -- `SPLIT` -- `MERGE` -- `MOVE` -- `RETIRE` -- `CREATE` -- `COMPRESS` -- `AUTOMATE` -- `REVIEW_LATER` - -## Output size - -- `focused`: concise chat answer with only material findings and one keep line - when no issue exists -- `bundle`: compact chat review with findings, bundle coverage notes, and the - affected propagation surfaces -- `catalog`: compact but structured summary with grouped findings and explicit - evidence gaps -- `retained-report`: retained output under `tmp/` only when the user asked for - it or the target is already a retained package - -## Chat projection - -For `chat-only` reviews, use the shortest projection that still supports the -user's decision. Start with exactly four fields in this order: - -- `🔎`: a localized verdict and counts by severity. -- `📌`: one sentence explaining why that verdict follows. -- `🧪`: reviewed scope, completed validation, and any material evidence gap. -- `👉`: one user action and the consequence of accepting it. - -Visible labels match the user's chat language. Canonical uppercase decision -values and evidence labels are internal by default. Map Critical findings to -`B` identifiers, Important findings to `I` identifiers, and Suggestions to -`S` identifiers. Show every blocking and important finding, consolidate -equivalent findings, and keep suggestions compact. - -Every material finding contains `Location`, `Evidence`, `Impact`, and -`Correction`. Add `Expected verification` when closure is not obvious. Mark -uncertainty inline as `to confirm` and do not create another severity. - -Keep counter-analysis records, review gates, decision traces, and internal -evidence digests hidden unless they materially change the verdict. Missing -proof stays visible through `🧪`. The final action names one user response and -states its consequence; a review never implies that a patch was already -applied. - -## Retained output - -Use retained output only when the user asks for it or the selected target is a -retained review package. Preserve profile-proportional detail, evidence -labels, evidence digest, decision trace, validation gaps, and residual risk -when the retained artifact needs them. Retained output may keep canonical -uppercase decision values and internal evidence labels. - -Retained review completion returns a compact chat card plus the retained path. -The chat summary must remain distinct from the retained report and must not -replace its evidence, decision trace, validation gaps, or residual-risk -detail. Keep retained reports under `tmp/` and preserve their existing file -layout. - -## Evidence compression - -Separate evidence into these layers: - -- `user-facing evidence`: proof the user needs to trust the verdict; -- `working evidence`: tool outputs, broad grep results, long diffs, file maps, - and checklists used during review; -- `internal synthesis`: comparisons, grouping, counterfactuals, and rejected - paths. - -Only user-facing evidence appears by default. Compress working evidence with an -evidence digest, a 2-4 line decision trace, compact evidence labels, and a named -residual risk. Use small tables only when they clarify the decision. Suppress raw -output when a digest preserves the same proof strength. - -## Missing proof handling - -When a proof cannot be run or loaded, report: - -1. the unavailable proof; -2. why it could not be used; -3. the confidence impact; -4. the substitute check used, if any; -5. the expected follow-up validation. - -Partial evidence may support a verdict, but the unavailable focused proof stays -visible as residual risk. - -## Conditional requirements - -Chat-only output follows `Chat projection`. Retained output follows `Retained -output` and returns the compact chat card with the retained path. Use the -selected profile and target as internal review context, and surface them in -chat only when they change the user's decision. - -## Completeness pass - -Before closing the review, confirm all of these: - -1. The selected profile still matches the target. -2. The relevant resource families were actually reviewed. -3. Every material recommendation names the affected validator, test, sync, or - propagation surface, or marks the gap. -4. Bundle reviews confirm each existing bundle sibling was reviewed or marked - intentional non-action. -5. Drift findings came from `internal-copilot-audit` when that lens was needed. -6. No-finding and low-finding reviews still explain why the result matters and - what next action follows. -7. The report stays proportional to the evidence and does not expand into an - encyclopedic catalog dump. diff --git a/.github/skills/internal-review-ai-resources/references/review-checklist.md b/.github/skills/internal-review-ai-resources/references/review-checklist.md deleted file mode 100644 index 1ee40a3e..00000000 --- a/.github/skills/internal-review-ai-resources/references/review-checklist.md +++ /dev/null @@ -1,84 +0,0 @@ -# Review Checklist - -Use this reference after the profile is selected. Keep the checklist -proportional to the active profile. - -## Control pass - -Confirm these before drawing conclusions: - -- What owns the target resource and what anti-scope should stay outside it? -- What selects or consumes it in practice? -- Which local files, validators, tests, or sync surfaces does it depend on? -- What happens if the resource is stale, missing, oversized, or weakly routed? - -## Consumption and flow - -Check these when the review is about real usage, not just file quality: - -- Activation: how the resource is loaded, selected, or referenced. -- Owner split: whether route, reusable procedure, deep detail, and deterministic - enforcement stay with the correct owner. -- Phase behavior: whether the resource supports plan, execute, review, sync, or - handoff roles without silent role mixing. -- Failure behavior: whether missing references, ambiguous targets, or validator - failures surface clearly. -- Bundle integrity: whether bundle reviews actually cover existing siblings. - -## Lifecycle and compatibility - -Check lifecycle posture when the decision affects medium-term maintenance: - -- Compatibility with paired wrappers, adjacent skills, validators, runtime - expectations, and naming contracts. -- Propagation requirements across inventory, sync catalogs, runtime matrices, - and focused tests. -- Periodic review posture: whether the resource has a realistic place in future - review, maintenance, or refresh work. -- Retirement readiness: whether a resource can be merged, replaced, or retired - without leaving hollow references or unmanaged sync fallout. - -## Quality and context economy - -Check these before recommending expansion or extraction: - -- Trigger clarity: descriptions and inputs are specific enough to retrieve the - right owner. -- Boundary clarity: thin wrappers stay thin and deep reusable detail lives in - references or owned skills. -- Token economy: always-on or prompt-visible content is justified by routing - value, not convenience. -- Coherence: duplicated owner maps, checklists, or report taxonomies are pushed - back to one canonical owner. - -## Validation and test surface - -Check the proof path as part of the review, not as an afterthought: - -- Which validator, test, or script proves the resource still works? -- Is the proof path focused and fast enough for the decision being made? -- Are there missing tests for ownership, bundle coverage, inventory, sync, or - token-risk claims? -- Are retained claims marked as gaps when live evidence is missing? - -## Sync and propagation - -Review propagation whenever a recommendation would change what ships or syncs: - -- `.github/INVENTORY.md` -- explicit allowlists such as home-sync catalogs -- runtime support matrices and sync helpers -- paired prompts, agents, skills, and nearby contract tests - -## Drift lens handoff - -Load `internal-copilot-audit` instead of cloning its checklist when the review -needs any of these: - -- overlap or weak alias detection -- hollow references or missing bundle siblings -- stale contracts, naming drift, or governance drift -- bridge coherence checks between `AGENTS.md` and `.github/copilot-instructions.md` - -Use this checklist for qualitative judgment. Keep deterministic enforcement in -validators and tests. diff --git a/.github/skills/internal-review-ai-resources/references/review-profiles.md b/.github/skills/internal-review-ai-resources/references/review-profiles.md deleted file mode 100644 index 49f9bae9..00000000 --- a/.github/skills/internal-review-ai-resources/references/review-profiles.md +++ /dev/null @@ -1,97 +0,0 @@ -# Review Profiles - -Use this reference to choose the smallest review profile that can still prove -the decision. - -## Family coverage baseline - -These families are reviewable when they are in scope or referenced by an -in-scope owner: - -- governance bridge: `AGENTS.md`, `.github/copilot-instructions.md`, - `.github/INVENTORY.md` -- wrapper surfaces: `.github/agents/*.agent.md`, `.github/prompts/*.prompt.md` -- skill bundles: `.github/skills/**/SKILL.md` plus `references/`, `scripts/`, - `assets/`, and `agents/openai.yaml` -- enforcement: validators, inventory builders, sync helpers, runtime matrices, - home-sync catalogs, and AI-catalog tests -- retained analysis: review packages under `tmp/` and explicitly referenced - local docs or manifests - -## Profile selector - -| Profile | Use when | Default scope | Escalate when | -| --- | --- | --- | --- | -| `focused` | One concrete file or one narrow resource needs review. | Target file, direct references, nearest validator or test, and the smallest required governance files. | A bundle sibling, paired wrapper, sync surface, or validator family becomes material to the decision. | -| `bundle` | The target is a skill, agent, prompt bundle, or one owner whose siblings and propagation matter. | Bundle root, existing siblings, paired wrapper or owner, nearest validators or tests, and affected propagation surfaces. | The decision crosses multiple bundles or needs bridge, inventory, sync, or catalog-wide reasoning. | -| `catalog` | The target spans multiple AI families or the full repository AI catalog. | Bridge files, live prompts, agents, skills, validators, tests, and sync surfaces relevant to the stated decision. | A narrower subset can prove the decision, or the request is really about one retained report package. | -| `retained-report` | The target is an existing retained report package under `tmp/`. | Retained package files plus live repository evidence for every claim that matters. | The user asks to revise live assets, or the report claim requires bundle or catalog review of current files. | - -## Target resolution rules - -- A path to `.github/skills//SKILL.md` or `.github/skills//` - defaults to `bundle`. Include existing `references/`, `scripts/`, `assets/`, - and `agents/openai.yaml`. -- A path to one prompt or agent defaults to `focused` unless paired skills, - validators, or propagation surfaces are material to the decision. -- A folder target under `.github/skills/`, `.github/agents/`, `.github/prompts/`, - or `.github/scripts/` defaults to `catalog` when it spans more than one owner - family. -- A path under `tmp/` that looks like a retained review package defaults to - `retained-report`. -- If the target is ambiguous, resolve the smallest obvious path from repository - evidence and record the unresolved edge as an evidence gap instead of guessing. - -## Minimum evidence pass - -### `focused` - -1. Read the target file and its nearest validator, test, or paired owner. -2. Read `AGENTS.md` and `.github/copilot-instructions.md` when the decision is - governance-sensitive. -3. Confirm one real consumption signal such as agent routing, prompt reference, - inventory presence, sync inclusion, or test coverage. - -### `bundle` - -1. Read the bundle root owner. -2. Read every existing sibling under `references/`, `scripts/`, `assets/`, and - `agents/openai.yaml`, or mark intentional non-action. -3. Read the nearest validator or test plus any paired wrapper or owner the - bundle points to. -4. Confirm propagation surfaces such as inventory, sync, runtime matrices, or - explicit allowlists. -5. Check live prompt packs, generated artifacts, retained reports, or fixtures - when the bundle governs materialized output. - -Report coverage separately from findings. Checked-clean siblings and propagation -surfaces should support the verdict through an evidence digest or decision trace -instead of appearing as artificial findings. - -### `catalog` - -1. Read `AGENTS.md`, `.github/copilot-instructions.md`, and - `.github/INVENTORY.md`. -2. Read the live prompts, agents, skills, scripts, or tests that are directly - relevant to the stated decision. -3. Map the validator and sync entrypoints that prove the catalog behavior. -4. Check context economy before recommending more always-on or wrapper-level - content. - -### `retained-report` - -1. Read the retained package summary and decision sections first. -2. Re-verify every material claim against current repository files, validators, - or tests. -3. Mark stale, missing, or unverifiable claims explicitly. - -## Escalation and de-escalation - -- Start at `focused` by default. -- Escalate to `bundle` when sibling resources, lifecycle checks, or propagation - controls matter. -- Escalate to `catalog` when the decision touches bridge files, inventory, - sync, or multiple resource families. -- Stay in `retained-report` only while treating the package as evidence. If the - user asks to change live assets, route to the appropriate delivery or review - owner separately. diff --git a/.github/skills/internal-review-ai-resources/references/review-usefulness-replay-fixture.md b/.github/skills/internal-review-ai-resources/references/review-usefulness-replay-fixture.md deleted file mode 100644 index 2ffd7634..00000000 --- a/.github/skills/internal-review-ai-resources/references/review-usefulness-replay-fixture.md +++ /dev/null @@ -1,41 +0,0 @@ -# Review Usefulness Replay Fixture - -Use this illustrative output shape when validating that AI-resource reviews are decision-useful -without becoming long reports. - -## Input - -- Target: the `local-ai-chatgpt-prompt-creator` skill bundle behavior. -- Branch diff tightens only the `coach-personale` validator profile. -- Live `coach-personale` prompt pack passes the validator with the required - support pack. -- No focused `coach-personale` profile test exists. -- Focused pytest execution is unavailable in the active environment. -- Sync and inventory evidence do not show material drift. - -## Expected Review Behavior - -- Reports no immediate runtime break observed. -- Reports one material low-severity finding or decision note about missing - profile-specific tests. -- Explains why the low finding matters. -- Uses an evidence digest instead of raw command output. -- Includes a decision trace that rules out unsupported drift or runtime-break - claims. -- Names unavailable pytest execution as residual risk. -- Recommends the smallest useful next step: add focused `coach-personale` - pass/fail validator tests. -- Does not invent additional findings to make the review look more substantial. - -## Compressed Output Shape - -```markdown -🔎 **Esito:** approvabile con un miglioramento facoltativo. -📌 **Perché:** il prompt pack passa il validator, ma il profilo non ha una regressione dedicata. -🧪 **Evidenza:** validator e sync verificati; pytest focalizzato non disponibile. -👉 **Azione richiesta:** nessuna correzione obbligatoria; chiedi una fase separata per aggiungere S1 se vuoi ridurre il rischio. - -## 💡 Suggerimenti (1) - -- **S1:** aggiungere test pass/fail specifici per il profilo `coach-personale`. -``` diff --git a/.github/skills/internal-skill-creator/SKILL.md b/.github/skills/internal-skill-creator/SKILL.md index a5ba0a00..31c27425 100644 --- a/.github/skills/internal-skill-creator/SKILL.md +++ b/.github/skills/internal-skill-creator/SKILL.md @@ -1,6 +1,6 @@ --- name: internal-skill-creator -description: Use when creating or materially revising repository-owned skills under `.github/skills/`, including splits, replacements, or changes to scope, triggers, structure, or validation. +description: Use when creating, materially revising, replacing, or retiring repository-owned skills under `.github/skills/`, including changes to scope, triggers, structure, or validation. --- # Internal Skill Creator @@ -25,7 +25,8 @@ convention. Keep the target skill model-invocable; a called skill must not set ## When to use -- The requested skill change affects repository-owned behavior or structure. +- The requested skill change affects repository-owned behavior or structure, + including creating, materially revising, replacing, or retiring a skill. ## Local reference @@ -37,8 +38,11 @@ its boundary or trigger, or selecting an evaluation branch. ### 1. Repository preflight Read the target `SKILL.md`, the nearest competing skills, and the applicable -`AGENTS.md`. Inventory the touched bundle. Read `.github/INVENTORY.md` only -when adding, retiring, renaming, or replacing a skill. +`AGENTS.md`. Inventory every existing sibling in the touched bundle: +`SKILL.md`, `references/`, `scripts/`, `assets/`, and `agents/openai.yaml`. +Distinguish real consumption from mere existence by mapping selectors, +cross-skill routing, validators, tests, inventory, and sync surfaces. Read +`.github/INVENTORY.md` when adding, retiring, renaming, or replacing a skill. Completion criterion: the intended boundary, anti-scope, touched files, and repository validation path are explicit. @@ -56,7 +60,8 @@ and each retained local instruction has a repository-specific reason to exist. ### 3. Proportional evaluation Read `references/authoring-and-evaluation.md`. Select the applicable evaluation -branches. Record skipped branches and reasons. +branches, including compatibility, lifecycle, propagation, and retirement when +material. Record skipped branches and reasons. Completion criterion: applicable branches have evidence; evidence, blockers, and completion status are explicit. @@ -66,7 +71,9 @@ and completion status are explicit. 1. Update `agents/openai.yaml` to match the revised skill purpose. 2. Run `python3 .github/scripts/validate_internal_skills.py --skill --strict`. 3. Check routing fallout in nearby skills and agents. -4. Record before/after line and word counts for the touched bundle. +4. For replacement or retirement work, remove hollow references and obsolete + entrypoints, then record before/after line and word counts for the touched + bundle. Completion criterion: structural validation passes, routing fallout is resolved, and before/after measurements are recorded. diff --git a/.github/skills/internal-skill-creator/agents/openai.yaml b/.github/skills/internal-skill-creator/agents/openai.yaml index 96322f85..10baf7e6 100644 --- a/.github/skills/internal-skill-creator/agents/openai.yaml +++ b/.github/skills/internal-skill-creator/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Skill Creator" short_description: "Create and revise repository-owned skills" - default_prompt: "Use $internal-skill-creator to create or revise a repository-owned skill. Apply /mattpocock-writing-great-skills as the core method, prefix cross-skill invocations with `/`, run proportional evaluation, then complete repository closure." + default_prompt: "Use $internal-skill-creator to create, revise, replace, or retire a repository-owned skill. Apply /mattpocock-writing-great-skills as the core method, prefix cross-skill invocations with `/`, run proportional evaluation, then complete repository closure." diff --git a/.github/skills/internal-skill-creator/references/authoring-and-evaluation.md b/.github/skills/internal-skill-creator/references/authoring-and-evaluation.md index d05a80ca..24df1708 100644 --- a/.github/skills/internal-skill-creator/references/authoring-and-evaluation.md +++ b/.github/skills/internal-skill-creator/references/authoring-and-evaluation.md @@ -6,6 +6,34 @@ Recover known answers from the request and repository evidence. Capture the capability, invocation conditions, expected output, constraints, dependencies, success criteria, validation path, and anti-scope. +## Bundle evidence + +For a bundle change, inspect every existing sibling under `references/`, +`scripts/`, `assets/`, and `agents/openai.yaml`, or record why a sibling is +intentionally unaffected. Checked-clean surfaces are evidence, not findings. + +## Consumption and ownership + +Distinguish a file's existence from selection or consumption through routing, +cross-skill calls, validators, tests, inventory, or sync. Keep generic +analysis-only review outside this creator. + +## Lifecycle and retirement + +Check compatibility, periodic maintenance, replacement, propagation, and +retirement readiness when the change affects them. Retirement must leave no +hollow references or unmanaged catalog fallout. + +## Propagation and proof + +Name each affected inventory, sync, validator, and test surface. Prefer the +smallest deterministic proof and record unavailable proof as a gap. + +## Self-review risk + +When this skill revises its own contract, name the rationalization risk and +prefer evidence from external consumers and focused tests. + ## Evaluation selection Classify each candidate branch as applicable, skipped, or blocked. Objective diff --git a/tests/github/agents/test_internal_gateway_review_generic_contract.py b/tests/github/agents/test_internal_gateway_review_generic_contract.py new file mode 100644 index 00000000..9cf6c09f --- /dev/null +++ b/tests/github/agents/test_internal_gateway_review_generic_contract.py @@ -0,0 +1,30 @@ +from pathlib import Path + + +REPO_ROOT = next( + parent + for parent in Path(__file__).resolve().parents + if (parent / "AGENTS.md").exists() and (parent / ".github").exists() +) +AGENT_PATH = ( + REPO_ROOT / ".github/agents/internal-gateway-review-generic.agent.md" +) + + +def test_ai_resource_review_covers_lifecycle_and_retirement() -> None: + text = AGENT_PATH.read_text(encoding="utf-8").lower() + for marker in ( + "compatibility", + "propagation", + "periodic review", + "retirement", + "inventory", + "sync", + ): + assert marker in text + + +def test_generic_review_remains_analysis_only() -> None: + text = AGENT_PATH.read_text(encoding="utf-8") + assert "Do not edit files" in text + assert "internal-skill-creator" not in text diff --git a/tests/github/skills/internal-review-ai-resources/test_report_contract.py b/tests/github/skills/internal-review-ai-resources/test_report_contract.py deleted file mode 100644 index 1ffd66ea..00000000 --- a/tests/github/skills/internal-review-ai-resources/test_report_contract.py +++ /dev/null @@ -1,87 +0,0 @@ -from pathlib import Path - -REPO_ROOT = next( - parent - for parent in Path(__file__).resolve().parents - if (parent / "AGENTS.md").exists() and (parent / ".github").exists() -) -SKILL_PATH = REPO_ROOT / ".github/skills/internal-review-ai-resources/SKILL.md" -REPORT_CONTRACT_PATH = ( - REPO_ROOT - / ".github/skills/internal-review-ai-resources/references/report-contract.md" -) -FIXTURE_PATH = ( - REPO_ROOT - / ".github/skills/internal-review-ai-resources/references" - / "review-usefulness-replay-fixture.md" -) -AGENT_PATH = ( - REPO_ROOT - / ".github/skills/internal-review-ai-resources/agents/openai.yaml" -) -PROMPT_PATH = REPO_ROOT / ".github/prompts/internal-review-ai-resources.prompt.md" -REVIEW_PROFILES_PATH = ( - REPO_ROOT - / ".github/skills/internal-review-ai-resources/references/review-profiles.md" -) -CARD_MARKERS = ("🔎", "📌", "🧪", "👉") - - -def test_skill_output_points_to_report_contract_required_sections() -> None: - skill_text = SKILL_PATH.read_text() - contract_text = REPORT_CONTRACT_PATH.read_text() - - assert "## Chat projection" in contract_text - assert "## Retained output" in contract_text - assert "Chat projection: see `references/report-contract.md`" in skill_text - assert "Retained output: see `references/report-contract.md`" in skill_text - - -def test_profile_names_are_consistent_across_bundle() -> None: - skill_text = SKILL_PATH.read_text() - profiles_text = REVIEW_PROFILES_PATH.read_text() - - for profile_name in ("focused", "bundle", "catalog", "retained-report"): - assert profile_name in skill_text - assert profile_name in profiles_text - - -def test_decision_vocabulary_uses_patch_not_revise() -> None: - skill_text = SKILL_PATH.read_text() - contract_text = REPORT_CONTRACT_PATH.read_text() - - assert "PATCH" in contract_text - assert "revise" not in skill_text.lower().split("review")[0] or True - assert "`revise`" not in skill_text - - -def test_report_contract_separates_chat_from_retained_output() -> None: - contract_text = REPORT_CONTRACT_PATH.read_text(encoding="utf-8") - - assert "## Chat projection" in contract_text - assert "## Retained output" in contract_text - assert "retained path" in contract_text - for marker in CARD_MARKERS: - assert marker in contract_text - - -def test_replay_fixture_uses_the_adaptive_chat_shape() -> None: - fixture_text = FIXTURE_PATH.read_text(encoding="utf-8") - - for marker in CARD_MARKERS: - assert marker in fixture_text - for legacy_heading in ( - "## Evidence Digest", - "## Decision Trace", - "## Residual Risk", - ): - assert legacy_heading not in fixture_text - - -def test_direct_entrypoints_preserve_chat_and_retained_distinction() -> None: - runtime_text = AGENT_PATH.read_text(encoding="utf-8") - prompt_text = PROMPT_PATH.read_text(encoding="utf-8") - - assert "adaptive chat projection" in runtime_text - assert "chat-only" in prompt_text - assert "retained path" in prompt_text diff --git a/tests/github/skills/internal-skill-creator/test_internal_skill_creator_contract.py b/tests/github/skills/internal-skill-creator/test_internal_skill_creator_contract.py index 81be5bb3..686fb7c6 100644 --- a/tests/github/skills/internal-skill-creator/test_internal_skill_creator_contract.py +++ b/tests/github/skills/internal-skill-creator/test_internal_skill_creator_contract.py @@ -102,3 +102,36 @@ def test_default_prompt_names_core_method_before_local_closure() -> None: closure = prompt.index("repository closure") assert matt < evaluation < closure assert "anthropic-skill-creator" not in prompt + + +def test_preflight_maps_complete_bundle_and_real_consumers() -> None: + skill = SKILL_PATH.read_text(encoding="utf-8") + normalized = " ".join(skill.split()) + for marker in ( + "references/", + "scripts/", + "assets/", + "agents/openai.yaml", + "consumption", + "routing", + ): + assert marker in normalized + + +def test_evaluation_covers_lifecycle_propagation_and_retirement() -> None: + reference = REFERENCE_PATH.read_text(encoding="utf-8") + for marker in ( + "## Bundle evidence", + "## Consumption and ownership", + "## Lifecycle and retirement", + "## Propagation and proof", + "## Self-review risk", + ): + assert marker in reference + + +def test_creator_scope_includes_replacement_and_retirement() -> None: + skill = SKILL_PATH.read_text(encoding="utf-8") + runtime = OPENAI_PATH.read_text(encoding="utf-8") + assert "retiring" in skill.lower() + assert "retire" in runtime.lower() diff --git a/tests/github/skills/internal-skill-creator/test_retired_ai_resource_review_contract.py b/tests/github/skills/internal-skill-creator/test_retired_ai_resource_review_contract.py new file mode 100644 index 00000000..e1818d7d --- /dev/null +++ b/tests/github/skills/internal-skill-creator/test_retired_ai_resource_review_contract.py @@ -0,0 +1,25 @@ +from pathlib import Path + + +REPO_ROOT = next( + parent + for parent in Path(__file__).resolve().parents + if (parent / "AGENTS.md").exists() and (parent / ".github").exists() +) +RETIRED_NAME = "internal-review-ai-resources" + + +def test_obsolete_review_entrypoints_are_removed() -> None: + assert not (REPO_ROOT / f".github/skills/{RETIRED_NAME}").exists() + assert not ( + REPO_ROOT / f".github/prompts/{RETIRED_NAME}.prompt.md" + ).exists() + + +def test_catalog_contract_has_no_retired_identity() -> None: + paths = ( + REPO_ROOT / ".github/INVENTORY.md", + REPO_ROOT / ".github/scripts/lib/token_risks.py", + ) + for path in paths: + assert RETIRED_NAME not in path.read_text(encoding="utf-8") From 8793c14be07a4c32f4d0a7c5f9247e64bdc5edb6 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sat, 25 Jul 2026 23:37:10 +0200 Subject: [PATCH 11/23] feat: update display name of agent interface from "Agent Development" to "Agent Creator" --- .github/skills/internal-agent-creator/agents/openai.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/skills/internal-agent-creator/agents/openai.yaml b/.github/skills/internal-agent-creator/agents/openai.yaml index 947c65fe..d2d5169b 100644 --- a/.github/skills/internal-agent-creator/agents/openai.yaml +++ b/.github/skills/internal-agent-creator/agents/openai.yaml @@ -1,4 +1,4 @@ interface: - display_name: "Agent Development" + display_name: "Agent Creator" short_description: "Create, refine, or realign repository-owned Copilot agents" default_prompt: "Use $internal-agent-creator to create or update an internal agent in .github/agents/ following the repository contract." From f422a889eba78cf3c5fa89aa466c1307d1fcf5d7 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sun, 26 Jul 2026 01:13:30 +0200 Subject: [PATCH 12/23] Refactor internal review skills and remove deprecated components - Deleted maintenance guidance file from internal gateway critical master. - Removed unused constants and variables from critical_master.py. - Updated internal review code skill documentation for clarity and consistency. - Adjusted agent configurations to reflect new routing and invocation patterns. - Streamlined analysis dimensions and removed unnecessary audit dispatch references. - Added tests to ensure contract alignment and validate new skill behaviors. - Introduced pytest configuration for improved testing setup. --- .github/INVENTORY.md | 1 - .../internal-gateway-critical-master.agent.md | 5 +- .../internal-gateway-review-code.agent.md | 112 ++---- .../internal-gateway-review-generic.agent.md | 20 +- .../prompts/internal-mega-review.prompt.md | 333 ------------------ .../internal-gateway-critical-master/SKILL.md | 11 +- .../references/maintenance-guidance.md | 4 - .../scripts/critical_master.py | 21 -- .github/skills/internal-review-code/SKILL.md | 109 +++--- .../internal-review-code/agents/openai.yaml | 4 +- .../internal-review-high-level/SKILL.md | 260 ++++---------- .../agents/openai.yaml | 4 +- .../references/analysis-dimensions.md | 129 +++---- .../references/audit-dispatch.md | 61 ---- .../references/review-lenses.md | 78 ++-- pytest.ini | 2 + ...nternal_gateway_review_generic_contract.py | 17 +- .../test_contract_alignment.py | 44 +++ ...ew_code_simplification_routing_contract.py | 24 ++ .../test_contract.py | 43 +++ ...est_retired_ai_resource_review_contract.py | 1 - tests/test_repository_test_layout_contract.py | 15 +- 22 files changed, 397 insertions(+), 901 deletions(-) delete mode 100644 .github/prompts/internal-mega-review.prompt.md delete mode 100644 .github/skills/internal-gateway-critical-master/references/maintenance-guidance.md delete mode 100644 .github/skills/internal-review-high-level/references/audit-dispatch.md create mode 100644 pytest.ini create mode 100644 tests/github/skills/internal-review-high-level/test_contract.py diff --git a/.github/INVENTORY.md b/.github/INVENTORY.md index 25d5ace7..491b23d5 100644 --- a/.github/INVENTORY.md +++ b/.github/INVENTORY.md @@ -200,4 +200,3 @@ These vendor-prefixed imported document skills remain support-only depth for rep ## Prompts - `.github/prompts/internal-architecture-md-creator.prompt.md` -- `.github/prompts/internal-mega-review.prompt.md` diff --git a/.github/agents/internal-gateway-critical-master.agent.md b/.github/agents/internal-gateway-critical-master.agent.md index f25fae00..d62d7078 100644 --- a/.github/agents/internal-gateway-critical-master.agent.md +++ b/.github/agents/internal-gateway-critical-master.agent.md @@ -11,5 +11,6 @@ agents: [] ## Core Skill - `internal-gateway-critical-master` -- Keep the full critical record internal and emit only the localized compact - card defined by the skill's output contract. + +Keep the full critical record internal and emit only the localized compact card +defined by the skill's output contract. diff --git a/.github/agents/internal-gateway-review-code.agent.md b/.github/agents/internal-gateway-review-code.agent.md index a6bf26fa..a37542fb 100644 --- a/.github/agents/internal-gateway-review-code.agent.md +++ b/.github/agents/internal-gateway-review-code.agent.md @@ -1,6 +1,6 @@ --- name: internal-gateway-review-code -description: "Senior repository code reviewer for source code, tests, scripts, build files, dependency files, and code-focused diffs before merge or follow-up action." +description: "Use this agent when reviewing source code, tests, scripts, build files, dependency files, or code-focused diffs before merge or a separate follow-up action." tools: ["read", "search", "execute"] disable-model-invocation: true agents: [] @@ -8,71 +8,30 @@ agents: [] # Senior Code Reviewer -You are an experienced Staff Engineer conducting a thorough code review. Your role is to evaluate the proposed changes and provide actionable, categorized feedback. +Use the core skill for review procedure. This agent owns routing, analysis-only +behavior, and the public chat boundary. -## Review Framework +## Core Skill -Evaluate every change across these five dimensions: - -### 1. Correctness - -- Does the code do what the spec/task says it should? -- Are edge cases handled (null, empty, boundary values, error paths)? -- Do the tests actually verify the behavior? Are they testing the right things? -- Are there race conditions, off-by-one errors, or state inconsistencies? - -### 2. Readability - -- Can another engineer understand this without explanation? -- Are names descriptive and consistent with project conventions? -- Is the control flow straightforward (no deeply nested logic)? -- Is the code well-organized (related code grouped, clear boundaries)? - -### 3. Architecture - -- Does the change follow existing patterns or introduce a new one? -- If a new pattern, is it justified and documented? -- Are module boundaries maintained? Any circular dependencies? -- Is the abstraction level appropriate (not over-engineered, not too coupled)? -- Are dependencies flowing in the right direction? - -### 4. Security - -- Is user input validated and sanitized at system boundaries? -- Are secrets kept out of code, logs, and version control? -- Is authentication/authorization checked where needed? -- Are queries parameterized? Is output encoded? -- Any new dependencies with known vulnerabilities? - -### 5. Performance - -- Any N+1 query patterns? -- Any unbounded loops or unconstrained data fetching? -- Any synchronous operations that should be async? -- Any unnecessary re-renders (in UI components)? -- Any missing pagination on list endpoints? +- `internal-review-code` ## Repository Review Contract -- Resolve the concrete code target first: diff, pull request, changed file list, source file, test file, script, build file, dependency file, or generated-code boundary. -- Read the spec, task description, or stated intent before judging implementation details when that evidence exists. -- Review tests before implementation when tests are present because they reveal intended behavior and coverage gaps. -- Keep the review code-focused. Prefer `internal-gateway-review-generic` when the primary target is an AI resource, workflow, policy, plan, documentation package, or mixed non-code artifact. -- Do not edit files, apply fixes, author plans, or route to peer agents. The user decides what to do after reading the report. -- Every Critical, Important, and Suggestion finding must reference a concrete file path and line when line evidence is available. -- If evidence is incomplete, mark the item as uncertain and recommend investigation instead of guessing. - -## Critical Counter-Analysis - -Before presenting the final report, pressure-test the review with `internal-gateway-critical-master` as the counter-analysis lens. Challenge severity, confidence, false positives, missing evidence, contrary explanations, validation coverage, and whether a no-finding claim is supported. - -If the counter-analysis exposes a material gap, reopen the review and return `Verdict: NEEDS INVESTIGATION` instead of presenting an unsupported approval or request-changes verdict. +- Resolve the concrete code target first: diff, pull request, changed file + list, source file, test file, script, build file, dependency file, or + generated-code boundary. +- Read the spec, task description, or stated intent before judging details when + that evidence exists; review tests before implementation when tests exist. +- Keep the review code-focused. Prefer + `internal-gateway-review-generic` when the primary target is an AI resource, + workflow, policy, plan, documentation package, or mixed non-code artifact. +- Do not edit files, apply fixes, author plans, or delegate to peer agents. +- Every material finding must reference a concrete file path and line when line + evidence is available; mark incomplete evidence as `to confirm`. ## User-facing chat projection -Keep the full review record and counter-analysis internal. In normal chat, -project only the decision-relevant result and match the user's chat language. - +Keep the full review record internal and match the user's chat language. Start with exactly four fields in this order: - `🔎`: localized verdict and counts by severity. @@ -82,35 +41,16 @@ Start with exactly four fields in this order: Map Critical findings to `B` identifiers, Important findings to `I` identifiers, and Suggestions to `S` identifiers; show every blocking and important finding; -consolidate equivalent findings and list all affected locations under one identifier. -Keep suggestions compact. +consolidate equivalent findings and list all affected locations under one +identifier. Every material finding contains `Location`, `Evidence`, `Impact`, and -`Correction`. Add `Expected verification` when closure is not obvious. -Mark uncertainty inline as `to confirm`; do not create another severity. - -Do not print empty sections, the internal review gate, the counter-analysis -record, or a decision trace. Surface those facts only through the verdict or -evidence-gap field when they change the user's decision. - -For request-changes results, the action may invite the user to request a -separate follow-up for named finding IDs, but it must state that no changes were applied. -Approval results state that no user action is required. -Investigation results ask for the exact missing evidence or authorization. - -## Rules - -1. Review the tests first - they reveal intent and coverage. -2. Read the spec or task description before reviewing code. -3. Every Critical and Important finding should include a specific fix recommendation. -4. Do not approve code with Critical issues. -5. Include `Sound Decisions / Preserved Conventions` only when it is evidence-bearing or decision-useful. -6. If you are uncertain about something, say so and suggest investigation rather than guessing. -7. Counter-analyze the report before presenting it to the user. -8. Stop after the review report; do not apply fixes. +`Correction`. Add `Expected verification` when closure is not obvious. Do not +print empty sections or internal decision records. -## Composition +For request-changes results, invite a separate follow-up for named finding IDs +and state that no changes were applied. Approval results state that no user +action is required. Investigation results ask for the exact missing evidence or +authorization. -- **Invoke directly when:** the user asks for a review of a specific code change, source file, test file, script, build file, dependency file, generated-code boundary, or pull request. -- **Prefer `internal-gateway-review-generic` when:** the target is non-code, an AI resource, workflow, policy, plan, documentation package, or a mixed artifact where code is not the primary surface. -- **Do not invoke from another persona.** If deeper security, testing, or architecture ownership would change the decision, surface that as a recommendation in your report instead of delegating. +Stop after the review report; do not apply fixes. diff --git a/.github/agents/internal-gateway-review-generic.agent.md b/.github/agents/internal-gateway-review-generic.agent.md index 9af67e18..025d5367 100644 --- a/.github/agents/internal-gateway-review-generic.agent.md +++ b/.github/agents/internal-gateway-review-generic.agent.md @@ -10,7 +10,7 @@ agents: [] ## Role -You are the repository generic review gateway. Review concrete non-code or mixed repository-owned work and return a decision-ready report after counter-validating your analysis. You are not a dedicated code reviewer, fixer, planner, or execution lane. +You are the repository generic review gateway. Review concrete non-code or mixed repository-owned work and return a decision-ready report after a local consistency check. You are not a dedicated code reviewer, fixer, planner, or execution lane. ## Review Framework @@ -56,11 +56,14 @@ Evaluate the target through the dimensions that apply to its surface: Prefer `internal-gateway-review-code` when the target is purely code: source, tests, scripts, build files, dependency files, generated-code boundaries, or a code-focused diff. -## Critical Counter-Analysis +## Review Consistency Gate -Before presenting the final report, pressure-test findings with `internal-gateway-critical-master` as the counter-analysis lens. Challenge severity, confidence, false positives, contrary evidence, scope narrowing, validation coverage, residual risk, and whether the report supports a clear user decision. - -If the counter-analysis exposes a material gap, reopen the review and return `review gate: reopen` instead of presenting an unsupported no-finding claim or final verdict. +Before presenting the final report, test the strongest contrary explanation for +each material finding. Verify severity and confidence against concrete evidence, +consolidate equivalent findings, and reopen the analysis when evidence is +insufficient for the stated verdict. Keep pressure testing as a separate, +user-selectable route through the normal gateway catalog rather than as an +internal review step. ## User-facing chat projection @@ -83,10 +86,9 @@ Every material finding contains `Location`, `Evidence`, `Impact`, and `Correction`. Add `Expected verification` when closure is not obvious. Mark uncertainty inline as `to confirm`; do not create another severity. -Do not print empty sections, the internal review gate, the counter-analysis -record, or a decision trace. Surface those facts only through the verdict or -evidence-gap field when they change the user's decision. Keep `review gate: -reopen` as internal state. +Do not print empty sections, the internal review gate, a consistency record, or +a decision trace. Surface those facts only through the verdict or evidence-gap +field when they change the user's decision. For request-changes results, the action may invite the user to request a separate follow-up for named finding IDs, but it must state that no changes were applied. diff --git a/.github/prompts/internal-mega-review.prompt.md b/.github/prompts/internal-mega-review.prompt.md deleted file mode 100644 index 280e60d0..00000000 --- a/.github/prompts/internal-mega-review.prompt.md +++ /dev/null @@ -1,333 +0,0 @@ ---- -name: "internal-mega-review" -agent: "internal-gateway-review-generic" -description: "Run a complete advisor-only mega review for one or more repositories and write split English analysis under each repo tmp/" -argument-hint: "Repository paths or names; optional focus and constraints; retained output is English" ---- - - - -Repositories to review: -${input:repositories:List one or more repository names or paths. Use one per line when possible.} - -Optional focus areas: -${input:focus:Optional focus such as security, governance, architecture, testing, automation, documentation, AI-readiness, or migration risk} - -Optional constraints or exclusions: -${input:constraints:Optional non-negotiables, exclusions, prior findings to preserve, or rollout concerns} - -Output language: -${input:language:Match chat language unless explicitly overridden. If you want to force one, write Italian or English.} - -Retained analysis content, headings, tables, and artifact filenames must stay in English. - -Use these standards-repository sources first for governance, evidence, and split-output discipline: - -- [AGENTS.md](../../AGENTS.md) -- [.github/copilot-instructions.md](../copilot-instructions.md) -- [.github/INVENTORY.md](../INVENTORY.md) -- [.github/agents/internal-gateway-review-generic.agent.md](../agents/internal-gateway-review-generic.agent.md) -- [.github/agents/internal-gateway-critical-master.agent.md](../agents/internal-gateway-critical-master.agent.md) -- [.github/skills/internal-gateway-writing-plans/SKILL.md](../skills/internal-gateway-writing-plans/SKILL.md) - -For this mega-review prompt, the English retained artifact contract below overrides any legacy non-English filename examples in those sources. - -Then run a complete, analysis-only mega review with these rules. - -## 1. Mission - -Review one or more repositories as a pragmatic technical advisor. - -- Do not apply fixes. -- Do not edit production files. -- Do not rename, move, or delete real repository assets. -- Write analysis artifacts only under `tmp/`. -- Keep the output concise, operational, evidence-based, written in English, and ready to guide later implementation work. - -## 2. Repository Resolution - -For each item in `repositories`: - -1. Resolve it to a real repository path in the current workspace or obvious sibling path. -2. If the path is ambiguous or missing, stop and ask only for the unresolved repository. -3. Treat each resolved repository independently before producing any cross-repo synthesis. - -## 3. Output Locations - -For each target repository, write the retained analysis under: - -- `/tmp/superpowers/mega-review/` - -If more than one repository is reviewed, also create a global cross-repo package under: - -- `tmp/superpowers/mega-review-global/` - -If the target `tmp/superpowers/mega-review/` folder already exists: - -- Preserve the previous analysis. -- Do not rewrite it wholesale. -- Add only missing coverage, corrections, or newly discovered findings in a separate numbered file such as `05-review-addendum.md`, or in a numbered addendum inside the relevant domain folder. -- Update `01-executive-summary.md` only when the executive summary is materially outdated. -- Do not create new non-English filenames. If a prior package uses legacy non-English filenames, preserve those files and continue with English-named delta files unless the user explicitly asks for migration. - -If no prior review exists, create a fresh split review package. - -## 4. Required Method - -For each repository: - -1. Start with a compact inventory before judging the repository. -2. Derive the technology stack only from repository evidence on disk. -3. Adapt the review to the observed stack and domain. -4. If the repository contains technologies, frameworks, or tooling not explicitly anticipated here, extend the review to cover them from first principles instead of skipping them. -5. Never invent technologies, workflows, or controls that are not present. -6. Prefer repository evidence over assumptions, and explicit uncertainty over false confidence. -7. When a repository-owned bundle owner such as `SKILL.md` materially affects a finding, inspect bundle siblings (`references/`, `scripts/`, `assets/`, and `agents/openai.yaml`) or mark the intentional non-action. - -## 5. Inventory First - -Before findings, produce a compact repository inventory covering what is actually present, for example: - -- Languages -- Frameworks and runtime tooling -- IaC tooling such as Terraform, Terragrunt, CloudFormation, Pulumi, Helm, Kubernetes manifests, Rego, policy files, or equivalent -- CI/CD systems and workflow triggers -- Security controls and scanning surfaces -- Test and validation surfaces -- Documentation and runbooks -- Governance and audit artifacts -- AI-facing files such as `AGENTS.md`, prompt files, instructions, skills, memory, or repository-specific agent guidance -- Repository purpose and likely owner, if inferable from evidence - -If an area is not present or not verifiable, say so. - -## 6. Review Dimensions - -For each repository, review at least these dimensions when relevant to the observed stack: - -- Security and least privilege -- Architecture and design clarity -- Code and script quality -- Automation and CI/CD -- Testing and validation -- Documentation and operational readiness -- Governance and auditability -- AI-readiness -- Cleanup, dead assets, drift, and standardization opportunities - -Also adapt to domain-specific concerns such as IAM, RBAC, policy-as-code, cloud governance, FinOps, GitHub org governance, platform operations, or repo-governance when those are actually present. - -## 7. Evidence Rule - -Every finding must cite concrete evidence such as: - -- A specific path -- A specific workflow -- A repeated pattern observed in files or directories -- A missing but expected validation surface relative to the detected stack -- An explicit contrast with another reviewed repository when doing cross-repo analysis - -If a claim cannot be tied to concrete evidence, move it to open questions or blockers instead of classifying it as a finding. - -## 8. Finding Format - -For each material finding, use this structure: - -### Finding Title - -- Severity: Critical | Medium | Low -- Category: Security | Architecture | Automation | Testing | Documentation | Governance | AI-readiness | Cleanup -- Classification: Must | Should | Could | Won't for now -- Evidence: specific file, directory, workflow, or repeated pattern -- Problem: what is wrong -- Impact: why it matters -- Proposed action: what to do later -- Estimated effort: S | M | L -- Invasiveness: low | medium | high -- Less invasive alternative: if applicable - -## 9. Required Output Shape Per Repository - -Use split numbered files, not one monolithic document. The package MUST be organized by reader context: a small top-level entrypoint plus two domain folders, one for cloud infrastructure and one for application engineering. Avoid duplicating the same finding across files; assign it to the domain where the owner will act. - -Every retained file MUST begin with a short `Purpose:` blockquote explaining what the file is for. - -Required top-level retained output per repository: - -- `01-executive-summary.md` -- `02-inventory-and-current-state.md` -- `03-remediation-plan.md` -- `04-consistency-gate.md` -- `open-questions-and-blockers.md` - -Required `cloud-infra/` output: - -- `cloud-infra/01-overview.md` -- `cloud-infra/02-architecture.md` -- `cloud-infra/03-iac-code-and-scripts.md` -- `cloud-infra/04-automation-and-cicd.md` -- `cloud-infra/05-governance-and-auditability.md` -- `cloud-infra/06-security-and-compliance.md` -- `cloud-infra/07-remediation-plan.md` - -Required `application-engineering/` output: - -- `application-engineering/01-overview.md` -- `application-engineering/02-architecture.md` -- `application-engineering/03-code-and-script-quality.md` -- `application-engineering/04-testing-and-validation.md` -- `application-engineering/05-automation-and-cicd.md` -- `application-engineering/06-security-and-dependency-hygiene.md` -- `application-engineering/07-remediation-plan.md` - -If the repository already has a retained review package, preserve the prior files and add complement files such as: - -- `05-review-addendum.md` at top level, or a numbered addendum inside the relevant domain folder. - -`01-executive-summary.md` must always exist as the entrypoint for a fresh review package and must link to the domain folder overview files, the top-level remediation index, consistency gate, and open questions file. - -Each domain detail file must contain: - -1. What this file is for -2. Scope for this repository -3. Critical findings in that category (using the Finding Format from section 8) -4. Medium findings in that category -5. Low findings in that category -6. Quick wins specific to that category, if any -7. Open questions specific to that category, if any - -If a domain detail file has no meaningful issue, the file must still exist and explicitly say: `No relevant finding observed.` so reviewers know the dimension was assessed. - -`03-remediation-plan.md` is a short routing index only. It must link to `cloud-infra/07-remediation-plan.md` and `application-engineering/07-remediation-plan.md`. - -The two domain remediation plan files hold their own priorities, quick wins, strategic moves, and file actions. Do not create separate backlog, quick-win, and file-action files unless the user explicitly asks for them. - -## 10. Required Tables - -Use compact tables where relevant. Tables should normally have 3 or 4 columns and MUST NOT exceed 5 columns unless the user explicitly asks for a wider table. Prefer bullets for details that would make a table hard to read. - -Priority plan: - -| Priority | Area | Work item | First action | -| --- | --- | --- | --- | - -Allowed priorities: - -- P0 = critical risk or major blocker -- P1 = high value or high risk -- P2 = important but not urgent -- P3 = cleanup or optional optimization - -File actions: - -| Action | Target | Reason | Effort | -| --- | --- | --- | --- | - -Allowed actions: - -- keep -- delete -- merge -- split -- rename -- compress -- move -- create -- automate -- standardize - -Quick wins: - -| Action | Owner area | Target | -| --- | --- | --- | - -## 11. Cross-Repo Output When Reviewing More Than One Repository - -If more than one repository is in scope, also produce a global split review under `tmp/superpowers/mega-review-global/`. - -Minimum global output: - -- `01-executive-summary.md` -- `02-consistency-cross-repo.md` -- `03-security-and-automation-gaps.md` -- `04-global-roadmap.md` -- `05-global-ai-readiness.md` -- `06-recommended-global-standard.md` -- `open-questions-and-blockers.md` - -Optional when complementing an existing global package: - -- `07-review-addendum.md` -- `08-critical-master-consistency-gate.md` - -Global review coverage must include: - -1. Executive summary -2. Global maturity matrix -3. Cross-repo consistency -4. Common security gaps -5. Common automation opportunities -6. Standardization candidates -7. Provider-specific or domain-specific differences that should remain local -8. Global AI-readiness assessment -9. Recommended repository standard -10. Global prioritized roadmap - -Use this compact maturity matrix: - -| Repo | Strengths | Main gaps | Top next step | -| --- | --- | --- | --- | - -Use this compact roadmap table: - -| Priority | Initiative | Repositories | First step | -| --- | --- | --- | --- | - -## 12. Review Discipline - -- Be severe but useful. -- Prefer pragmatic changes over aesthetic refactors. -- Recommend invasive changes only when the benefit is clearly justified. -- For every invasive proposal, explain why it is necessary, the less invasive option, the risk of doing it, the risk of not doing it, and the estimated effort. -- Do not overuse `Must`. -- Do not confuse temporary uncertainty with a verified problem. - -## 13. Existing Analysis Handling - -If the repository already contains prior analysis under `tmp/`: - -- Read it first. -- Preserve what is still valid. -- Only add missing sections, corrected evidence, or newly observed findings. -- Avoid duplicating the same backlog item unless the evidence has materially changed. -- Keep newly created retained artifacts in English even when prior retained analysis used another language or legacy filenames. - -## 14. Final Consistency Gate - -Before finishing, validate the resulting analysis against the challenge posture defined in: - -- [.github/agents/internal-gateway-critical-master.agent.md](../agents/internal-gateway-critical-master.agent.md) - -Run a brief consistency gate that answers: - -1. What in the final review is most likely correct? -2. What is most likely incorrect, contradictory, overstated, or insufficiently verified? -3. Which findings should be downgraded, reframed, or moved to open questions? - -If useful, save that gate as a retained artifact in the global package or in the reviewed repository package. - -## 15. Final Quality Bar - -Before stopping, verify that the retained output is: - -- Concrete -- Verifiable -- Non-generic -- Non-destructive -- Adapted to the observed repositories and stacks -- Split into multiple files -- Written with English retained content and filenames -- Useful for follow-up implementation work -- Explicit about impact, priority, effort, and uncertainty - -If a repository cannot support a complete review because key evidence is missing, say exactly what is not verifiable from the repository and continue with the parts that are verifiable. diff --git a/.github/skills/internal-gateway-critical-master/SKILL.md b/.github/skills/internal-gateway-critical-master/SKILL.md index ef6f0145..c255e022 100644 --- a/.github/skills/internal-gateway-critical-master/SKILL.md +++ b/.github/skills/internal-gateway-critical-master/SKILL.md @@ -19,6 +19,7 @@ gateway decides when to invoke it; this skill challenges only. ## When not to use - The next step is retained planning, implementation, or evidence-first review. +- This skill is not an automatic counter-analysis step for evidence-first review. ## Boundaries @@ -34,6 +35,9 @@ Run exactly three phases. Do not skip a phase and do not loop back unless new ev - Identify the material claims, constraints, success criteria, and anti-scope. - Record internally: what is being challenged and why it matters now. +Completion criterion: the challenged target, material claims, constraints, +success criteria, anti-scope, and evidence gaps are recorded. + ### Phase 2: Challenge - Select exactly **three lenses** from the table below based on the highest-risk gaps in the summary. @@ -43,6 +47,9 @@ Run exactly three phases. Do not skip a phase and do not loop back unless new ev - Ask at most one concise root question across all findings when the answer would materially change the critique. - Treat mitigations as conditions to continue, not as implementation designs that rescue the proposal. +Completion criterion: exactly three lenses were applied, the third is lateral, +and the strongest supported objection controls the result. + | Lens | Question | Use when | | --- | --- | --- | | First principles | Which claims are evidence-backed, and which are inherited assumptions? | The plan repeats local habits as if they were constraints. | @@ -70,6 +77,9 @@ Trigger a pre-mortem when at least one of these is true: - When Defense is not `none`, name the strongest defense and the remaining vulnerability inside the synthesis. - Select exactly one canonical routing outcome from `## Outcome meanings`. +Completion criterion: defense, residual uncertainty, and exactly one canonical +outcome are resolved. + ## Internal critical record Keep the following as internal working state. Do not print the internal critical record in normal chat; use it to produce the public card. @@ -101,7 +111,6 @@ In normal chat, emit only the localized three-to-five-line emoji card defined in - Optional: `scripts/validate_critical_output.py` checks a rendered card against the contract in `references/output-contract.md`. - The optional validator and its pure helper live inside this skill bundle so the skill can be copied without depending on repo-global Python modules. - Reuse `fixtures/critical_output_valid.md` and sibling fixture samples instead of repeating long inline payloads. -- Follow `references/maintenance-guidance.md` for fixture reuse and cache-aware search discipline. - Keep this bundle self-contained: do not require instructions, examples, or enforcement rules from outside this directory. - Script output contract: `text` for short operator summaries (default), `json` for nested or machine-consumed output, `compact` for status and counts; validation findings on stdout, file and usage failures on stderr; keep output bounded. diff --git a/.github/skills/internal-gateway-critical-master/references/maintenance-guidance.md b/.github/skills/internal-gateway-critical-master/references/maintenance-guidance.md deleted file mode 100644 index 2d7d5e7f..00000000 --- a/.github/skills/internal-gateway-critical-master/references/maintenance-guidance.md +++ /dev/null @@ -1,4 +0,0 @@ -# Maintenance Guidance - -- Prefer `fixtures/` samples over repeated inline Markdown payloads. -- When the target is tracked source, exclude generated caches such as `graphify-out/`, `.pytest_cache/`, `.venv/`, and `__pycache__/` from broad searches. diff --git a/.github/skills/internal-gateway-critical-master/scripts/critical_master.py b/.github/skills/internal-gateway-critical-master/scripts/critical_master.py index 23ca9015..81d2b545 100644 --- a/.github/skills/internal-gateway-critical-master/scripts/critical_master.py +++ b/.github/skills/internal-gateway-critical-master/scripts/critical_master.py @@ -22,22 +22,6 @@ } ) -ALLOWED_CLAIM_CLASSES: frozenset[str] = frozenset( - {"confirmed", "inference", "estimate"} -) - -ALLOWED_EVIDENCE_QUALITY: frozenset[str] = frozenset( - {"strong", "partial", "weak"} -) - -ALLOWED_LIKELIHOODS: frozenset[str] = frozenset({"high", "medium", "low"}) - -ALLOWED_DEFENSE_VALUES: frozenset[str] = frozenset( - {"none", "resolves", "narrows", "accepts-risk", "unanswered"} -) - -TOTAL_MAX_WORDS = 600 - REQUIRED_CARD_MARKERS = ("🎯", "⚠️", "✅") OPTIONAL_CARD_MARKERS = ("💥", "❓") CARD_MARKER_ORDER = ("🎯", "⚠️", "💥", "✅", "❓") @@ -127,10 +111,6 @@ def validate_outcome_value(value: str) -> bool: __all__ = [ - "ALLOWED_CLAIM_CLASSES", - "ALLOWED_DEFENSE_VALUES", - "ALLOWED_EVIDENCE_QUALITY", - "ALLOWED_LIKELIHOODS", "ALLOWED_OUTCOMES", "CARD_LINE_MAX_WORDS", "CARD_MARKER_ORDER", @@ -142,7 +122,6 @@ def validate_outcome_value(value: str) -> bool: "Finding", "OPTIONAL_CARD_MARKERS", "REQUIRED_CARD_MARKERS", - "TOTAL_MAX_WORDS", "count_words", "parse_critical_card", "validate_outcome_value", diff --git a/.github/skills/internal-review-code/SKILL.md b/.github/skills/internal-review-code/SKILL.md index f11341d3..c7d234ee 100644 --- a/.github/skills/internal-review-code/SKILL.md +++ b/.github/skills/internal-review-code/SKILL.md @@ -7,69 +7,74 @@ description: Use when reviewing a branch, pull request, work-in-progress diff, o ## Referenced skills -- `addyosmani-code-review-and-quality`: complete five-axis review core, approval standard, and finding categories. -- `awesome-copilot-security-review`: security-specialist depth only when the user explicitly asks for it. -- `addyosmani-code-simplification`: on-demand remediation owner for an explicitly approved, behavior-preserving simplification follow-up; never part of the review pass. +- `/addyosmani-code-review-and-quality`: complete and sole code-review engine, + including its review reasoning, severity, categories, and approval standard. +- `/awesome-copilot-security-review`: security-specialist depth only when the + user explicitly asks for it. +- `addyosmani-code-simplification`: on-demand remediation owner for an + explicitly approved, behavior-preserving simplification follow-up; never + part of the review pass. ## When to use Use for a branch, pull request, work-in-progress diff, or code-focused change -that needs defect-first review before merge or before a follow-up patch -decision. +that needs defect-first review before merge or a separate follow-up decision. -## Core contract +## Repository wrapper -Use `addyosmani-code-review-and-quality` as the complete review engine and -follow its process end to end. This wrapper provides the stable -repository-owned entrypoint and the local boundaries below. It must not -redefine the core's five axes, review order, approval standard, finding -categories, structural remedies, or verification posture. +Use `/addyosmani-code-review-and-quality` as the complete review engine. This +wrapper owns only repository preflight, target boundaries, escalation rules, +the detailed-to-chat projection, and final validation. It must not restate the +engine's review axes, procedure, approval standard, finding categories, or +remediation workflow. -The core owns review reasoning and severity. This wrapper owns the public chat projection -and repository-facing boundaries. The projection may reorder and compress supported -evidence, but it must not introduce another review axis, severity model, approval -standard, or remediation workflow. +The core owns review reasoning and severity. This wrapper owns the public chat projection. +The projection may reorder and compress supported evidence, but it +must not introduce another review axis, severity model, approval standard, or +remediation workflow. ## Boundaries -- Review only the requested code surface and the supporting tests, spec, task, - or validation evidence needed to judge it. -- Review tests before implementation when tests are present because that order - belongs to the core contract. -- Do not apply fixes unless the user asks in a separate step. -- Do not load implementation-language skills or systems-level review skills - merely because their file types or topics appear in the diff. Load a narrower - owner only when the file type, runtime, or defect pattern would materially - change the review. -- Do not load `awesome-copilot-security-review` automatically. Use it only when - the user explicitly asks for security-specialist depth. -- Do not redefine the core review model. Project its result through the same - `🔎`, `📌`, `🧪`, and `👉` semantics used by the code gateway. -- If the requested fixed point, diff, or code target is missing, invalid, or - empty, stop at the core preflight and state the evidence gap. -- If no spec or task context exists, follow the core no-spec path and state the - evidence gap. -- When a concrete readability or complexity finding is best addressed by behavior-preserving refactoring, name `addyosmani-code-simplification` only as a separate simplification follow-up for the user to approve. +- Resolve a concrete, non-empty diff or explicit read-only code target before + review; state the evidence gap when the target, fixed point, or context is + missing. +- Read the spec, task, and tests before implementation when those sources + exist. Review only the requested code surface and immediate evidence. +- Do not edit files, apply fixes, author plans, or delegate to peer agents. +- Load `/awesome-copilot-security-review` only on explicit user request. +- Name `addyosmani-code-simplification` only as a separate simplification + follow-up for a concrete readability or complexity finding. - Do not load or execute `addyosmani-code-simplification` during the review pass. +- Project the result through the shared `🔎`, `📌`, `🧪`, and `👉` semantics. + +## Completion criteria + +The review is complete only when the target is resolved and non-empty, core +categories are used without a second severity scale, claims are source-backed +or marked as explicit evidence gaps, every blocking and important finding is +preserved, and the report contains one boundary-safe next action. + +## Public projection + +Start with exactly four fields in this order: + +- `🔎`: localized verdict and counts by severity. +- `📌`: one sentence explaining why that verdict follows. +- `🧪`: reviewed scope, completed validation, and material evidence gaps. +- `👉`: one user action and the consequence of accepting it. + +For each material finding, preserve `Location`, `Evidence`, `Impact`, +`Correction`, and `Expected verification` when closure is not obvious. Map the +engine's categories to `B`, `I`, and `S` identifiers, show every blocking and +important finding, consolidate equivalent findings, and mark uncertainty inline +as `to confirm`. + +Keep internal review details hidden unless they alter the verdict. State that +no changes were applied, and offer remediation only as a separate follow-up. ## Validation -Before reporting the review, confirm that: - -- the reviewed surface resolved to the intended non-empty diff or explicit - read-only code target; -- tests were reviewed before implementation when tests were present; -- findings use the core finding categories consistently and do not add a second - local severity scale; -- correctness and security issues lead the report before lower-leverage - comments; -- any spec, task, or repository-standard claim cites its source, or the report - states the evidence gap; -- security-specialist escalation was used only on explicit user request; -- simplification is surfaced only as a separate follow-up backed by a concrete readability or complexity finding; -- `addyosmani-code-simplification` was not loaded or executed during review. -- all Critical and Important findings remain visible; -- `B`/`I`/`S` identifiers map to the core finding categories; -- material findings include concrete evidence, impact, correction, and expected verification; -- the projection contains one boundary-safe user action; -- internal counter-analysis details stay hidden unless they alter the verdict. +Before reporting, verify the completion criteria, source evidence, target scope, +security escalation boundary, and separate simplification follow-up. Keep +no-findings or merge-readiness claims behind +`/superpowers-verification-before-completion`. diff --git a/.github/skills/internal-review-code/agents/openai.yaml b/.github/skills/internal-review-code/agents/openai.yaml index bc6bae74..53c9c668 100644 --- a/.github/skills/internal-review-code/agents/openai.yaml +++ b/.github/skills/internal-review-code/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Review Code" - short_description: "Repository wrapper for five-axis code review" - default_prompt: "Use $internal-review-code as the repository wrapper, follow $addyosmani-code-review-and-quality as the full review core, return the result through the adaptive chat projection with one user action, and state that remediation requires a separate follow-up; use $awesome-copilot-security-review only if the user explicitly asks for security-specialist depth." + short_description: "Repository wrapper for the imported code-review engine" + default_prompt: "Use /internal-review-code as the repository wrapper, follow /addyosmani-code-review-and-quality as the complete review engine, return the result through the adaptive chat projection with one user action, and state that remediation requires a separate follow-up; use /awesome-copilot-security-review only if the user explicitly asks for security-specialist depth." diff --git a/.github/skills/internal-review-high-level/SKILL.md b/.github/skills/internal-review-high-level/SKILL.md index db64b1b8..15574826 100644 --- a/.github/skills/internal-review-high-level/SKILL.md +++ b/.github/skills/internal-review-high-level/SKILL.md @@ -1,207 +1,81 @@ --- name: internal-review-high-level -description: Use when a task needs systems-level evidence about architecture, workflow, cross-cutting impact, blind spots, merge risk, or an orientation map of unfamiliar code. +description: Use when a task needs systems-fit evidence about architecture, workflow, cross-cutting impact, blind spots, operational context, or an orientation map of unfamiliar code. --- # Internal Review High Level -## Referenced skills - -This index lists every other skill that this file asks the agent to load, route to, compare against, or delegate to. -Treat the referenced skills below as on-demand supports. Do not preload them -for every review; load only the owner proved by the active lens, review scope, -or final claim. - -- `internal-review-code`: line-level defect review owner. -- `internal-gateway-critical-master`: pressure-test owner when the main need is challenge rather than review evidence. -- `superpowers-verification-before-completion`: evidence gate before claiming no systems findings or merge readiness. - -Use this skill as the systems-level owner for repository changes and unfamiliar -code orientation. It complements defect-first code review by checking whether a -change fits the surrounding architecture, workflow, ownership model, and -operational context. +This skill owns systems-fit review and architecture/orientation only. It is an +evidence-first reviewer, not a remediation owner. Keep cross-owner routes +recommendation-only. Do not delegate. ## When to use -- Analyze a branch diff, PR, retained plan, or file list for systems-level risk. -- Evaluate architectural implications, workflow impact, and unconsidered effects. -- Review cross-cutting concerns before merge when line-level findings are not enough. -- Complement `internal-review-code` with broader evidence about coupling, ownership, and operational fit. -- Build a higher-level orientation map for unfamiliar code, including relevant - modules, callers, boundaries, and repository domain vocabulary. +- Review whether a change fits its architecture, workflow, ownership, and + operational context. +- Check cross-cutting impact, blind spots, scope drift, and merge risk. +- Build an evidence-based orientation map of unfamiliar code. ## When not to use -- Use `internal-review-code` for line-level defects, language anti-patterns, tests, and file-specific findings. -- Use `internal-gateway-critical-master` for pre-mortems, hidden-assumption tests, and pressure testing. +- Use `internal-review-code` for line-level defects, language anti-patterns, + tests, and file-specific findings. +- Use `internal-gateway-critical-master` for explicit pressure testing rather + than evidence-first systems review. - Route security-specific gaps through the closest existing owner and state the missing specialized-owner gap when no promoted security owner exists. -- Do not turn advisory architecture notes into mandatory changes without evidence. -- Do not introduce `CONTEXT.md`, ADR folders, or glossary maintenance as a side - effect of review unless those structures already exist and the user asks to - adopt them. - -## Relationship to other skills - -- `internal-review-code`: code defects, regressions, tests, language anti-patterns, and file/line findings. -- This skill: architecture, workflow, cross-cutting impact, operational fit, - blind spots, and higher-level codebase orientation. -- `internal-gateway-critical-master`: challenge work when the main need is pressure testing rather than review evidence. -- Security-specific review depth stays with the closest existing owner until a - specialized security owner is promoted. - -## Analysis dimensions - -Dimensions are loaded from `references/analysis-dimensions.md` when deeper checklists are needed. Summary: - -1. **Correctness** — Does the code do what the change claims? Edge cases? Error paths? Input validation? -2. **Separation of concerns** — Business vs I/O? Module boundaries? Naming clarity? Dependency direction? Interface stability? -3. **Architecture** — Coupling, cohesion, extensibility, testability, operational readiness? -4. **Blind spots** — Temporal analysis, team dynamics, cross-service impact, operational burden, data implications, security surface, performance cliffs, configuration drift, missing observability, alternative solutions? - -## Workflow Review Lenses - -Load the workflow references when review evidence needs more detail than the -main skill should carry: - -- `references/plan-completion-audit.md`: plan-vs-diff mapping, completion - status, and `UNVERIFIABLE` evidence gaps. -- `references/scope-drift.md`: declared intent, observed delivery, out-of-scope - changes, and missing requirements. -- `references/review-lenses.md`: always-on, cross-cutting, and stack-specific - review lenses with severity and confidence calibration. -- `references/audit-dispatch.md`: optional subagent dispatch for heavy plan or - diff audits, with main-assistant spot checks. - -Workflow findings should cover plan-vs-diff mapping, scope drift, evidence gaps, -contract coverage, and governance drift when those dimensions are in scope. - -## Architecture Fit Lenses - -Use these lenses when a review crosses module, workflow, or ownership boundaries: - -- **Locality**: Does the change concentrate related knowledge, bugs, and future - edits in one place, or does it force maintainers to chase behavior across - several files? -- **Leverage**: Does the interface hide meaningful behavior behind a small - contract, or does every caller still need to understand the implementation? -- **Module depth**: A deep module has a small interface and useful behavior - behind it. A shallow module mostly passes complexity through to its callers. -- **Deletion test**: If the module vanished, would complexity disappear, or - would the same complexity reappear across multiple callers? -- **Real seam test**: One adapter can be hypothetical. Two or more real users of - a seam make the abstraction easier to justify. -- **Cross-boundary fit**: Check whether a change belongs in the touched owner, - an adjacent internal skill, a reference, a validator, or a generated catalog - artifact before recommending more files. - -Keep these as review lenses, not mandatory refactor demands. Recommend a -deepening change only when the evidence shows current shallowness is creating -real maintenance, testability, or workflow cost. - -## Orientation Map Lens - -Use this lens when the user asks to zoom out, understand an unfamiliar area, or -see how code fits into the larger system before planning, reviewing, or editing. - -Keep the output evidence-based and compact: - -- Target area: the file, module, workflow, or behavior being explained. -- Domain vocabulary: repository terms that name the concepts in play. -- Module map: relevant modules, responsibilities, dependencies, and callers. -- Flow map: the main data, control, or operational path through those modules. -- Boundary notes: ownership, extension points, and cross-boundary risks. -- Uncertainty: missing evidence, likely next files to inspect, or validation gaps. - -Do not turn orientation into review findings unless the user asks for a review -or the inspected evidence exposes a concrete systems risk. - -## Severity mappings - -| Category | Severity | Criteria | -| --- | --- | --- | -| Error | Critical | Security flaw, data loss risk, correctness bug affecting business logic | -| Error | Major | Missing error handling, broken contract, regression risk | -| Improvement | Readability | Code clarity, naming, structure | -| Improvement | Performance | Algorithmic efficiency, resource usage | -| Improvement | Maintainability | Technical debt, coupling, cohesion | -| Improvement | Testability | Test coverage gaps, untestable designs | -| Improvement | Security | Hardening, least privilege, input validation | - -| Effort | Meaning | -| --- | --- | -| Low | Less than 1 hour, isolated change | -| Medium | 1-4 hours, may touch multiple files | -| High | More than 4 hours, may require design discussion | - -## Review Output - -Present findings directly in conversation (never write files unless the user explicitly asks): - -1. **Findings** — systems-level risks ordered by severity, with evidence and fix route. -2. **Evidence gaps** — validation, context, or dependency information still missing. -3. **Blind spots** — realistic concerns the current change does not address. -4. **Architecture notes** — non-binding structural guidance with impact and effort. -5. **Summary** — brief overall assessment after findings. - -For empty sections, state "No findings in this category." - -## Orientation Output - -When the request is explanatory rather than review-owned, present a map instead -of findings: - -1. **Target Area** — the file, module, workflow, or behavior being explained. -2. **Domain Vocabulary** — repository terms that matter for the area. -3. **Module Map** — modules, responsibilities, dependencies, and callers. -4. **Flow Map** — main data, control, or operational path. -5. **Boundary Notes** — ownership, extension points, and risks to respect. -6. **Uncertainty** — missing evidence and next files or checks. - -Do not include empty review sections in an orientation-only answer. - -## Common mistakes - -| Mistake | Why it matters | Instead | -| --- | --- | --- | -| Flagging code style as a systems issue | Inflates findings and dilutes trust | Use `internal-review-code` for nit-level checks | -| Making ungrounded findings ("this might break X") | Speculation ≠ evidence | Every finding must cite a concrete file and line from the diff | -| Scope creep — analyzing the entire codebase | The user asked about a specific change | Analyze only changed files and their immediate dependencies | -| Reporting without effort estimation | Leaves the author without prioritization signal | Always include Low/Medium/High effort per finding | -| Treating advisory notes as blockers | Obscures urgency | Block only on evidenced systems risk | -| Skipping blind-spot analysis | The most valuable part of this skill gets dropped | Run all 4 dimensions, even if some are empty | -| Treating orientation as critique | The user may only need a codebase map | Separate maps from findings unless a concrete risk is evidenced | - -## Self-questioning - -Before presenting findings, verify: - -- Is this finding based on evidence in the diff, or am I assuming? -- Could I be wrong about the intent of this change? -- Am I flagging something that is actually fine for this specific context? -- What is the simplest correct interpretation? - -## Workflow - -1. Identify changed files (diff against default branch or explicit file list). -2. Load applicable instruction files based on detected languages. -3. Read each changed file or requested target area and its immediate dependencies. -4. Analyze across all dimensions, or build an orientation map when the request - is explanatory rather than review-owned. Load - `references/analysis-dimensions.md` for detailed checklists. -5. For review-owned work, self-question each finding before including it. -6. Route code defects back to `internal-review-code` when they are not systems-level issues. -7. Present review findings or an orientation map using the matching output - structure above. - -## Validation - -- Every finding must reference a concrete file and line number. -- Every finding must include a *why* explanation. -- Every finding must include a minimal fix route or recommended owner. -- Architecture recommendations must include impact and effort assessment. -- Orientation maps must name the target area, domain vocabulary, module map, - caller or entrypoint evidence, boundary notes, and uncertainty. -- Security-specific gaps must not imply that an unpromoted security owner exists. -- Use `superpowers-verification-before-completion` before claiming there are no - systems findings, the review is complete, or the change is merge-ready. +- Do not turn advisory architecture notes into mandatory changes without + evidence, and do not create new context or glossary structures as a review + side effect. + +## Branch selection + +### Systems-fit review + +Use this branch for systems-level findings, workflow impact, architecture fit, +blind spots, scope drift, or merge-readiness evidence. Load +`references/analysis-dimensions.md`, `references/review-lenses.md`, and +`references/scope-drift.md` only when their evidence is needed. Report findings +with the single severity/confidence vocabulary in `review-lenses.md`. + +### Architecture and orientation + +Use this branch for architecture-fit questions or an orientation map of an +unfamiliar area. Load only the architecture and codebase-orientation portions +of `references/analysis-dimensions.md`. Keep the result descriptive unless +concrete evidence supports a systems finding. + +## Compatibility-only plan audit + +Use `references/plan-completion-audit.md` only for an explicit retained-plan +audit request or an existing execution-owner compatibility path. Plan audit is +not a primary trigger, and ownership migration is outside this change. + +## Evidence-first workflow + +1. Resolve the target, declared intent, anti-scope, and nearest owner. +2. Select exactly one branch and load only its referenced evidence. +3. Read the target and immediate dependencies; map boundaries and callers. +4. Test contrary explanations and record concrete evidence gaps. +5. Project the matching finding or orientation output. +6. Validate every claim, route code defects to `internal-review-code`, and keep + recommendations non-binding. + +## Systems-fit output + +Present findings by severity, then evidence gaps, blind spots, architecture +notes, and a short summary. Every actionable finding must cite concrete file +and line evidence, explain the causal layer, and name a minimal recommendation- +only route. Speculative concerns are evidence gaps, not actionable findings. + +## Architecture and orientation output + +For an orientation request, provide the target area, domain vocabulary, module +map, flow map, boundary notes, and uncertainty. Name caller or entrypoint +evidence and validation gaps. Do not include review sections in an +orientation-only response. + +## Completion boundary + +Keep no-findings, merge-readiness, and complete-review claims behind +`superpowers-verification-before-completion`. diff --git a/.github/skills/internal-review-high-level/agents/openai.yaml b/.github/skills/internal-review-high-level/agents/openai.yaml index 81f8a41f..ac2ae53a 100644 --- a/.github/skills/internal-review-high-level/agents/openai.yaml +++ b/.github/skills/internal-review-high-level/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Review High Level" - short_description: "Help with Internal Review High Level tasks" - default_prompt: "Use $internal-review-high-level for this task and follow the repository-owned workflow in the skill." + short_description: "Systems-fit, architecture, and orientation review" + default_prompt: "Use /internal-review-high-level to review systems-fit and architecture or to build an evidence-based orientation map. Select one branch, load only its referenced evidence, keep cross-owner routes recommendation-only, and report uncertainty explicitly." diff --git a/.github/skills/internal-review-high-level/references/analysis-dimensions.md b/.github/skills/internal-review-high-level/references/analysis-dimensions.md index c7deb7ef..8e67dc25 100644 --- a/.github/skills/internal-review-high-level/references/analysis-dimensions.md +++ b/.github/skills/internal-review-high-level/references/analysis-dimensions.md @@ -1,82 +1,63 @@ # Analysis Dimensions — Detailed Checklists -## 1. Correctness analysis - -- Does the code do what the change claims? -- Are edge cases handled? -- Are error paths tested? -- Is input validation present and sufficient? -- Do return types match caller expectations? -- Are concurrency assumptions safe? - -## 2. Separation of concerns - -| Principle | What to check | -| --- | --- | -| Business vs I/O | Is business logic cleanly separated from I/O, SDKs, and persistence? | -| Module boundaries | Are module boundaries clear and cohesive? | -| Naming clarity | Do names reflect what the code does in business terms? | -| Dependency direction | Do high-level modules avoid depending on low-level details? | -| Interface stability | Are module contracts (inputs/outputs) stable and documented? | - -## 3. Architecture - -| Quality | What to check | -| --- | --- | -| Separation of concerns | Are business logic, I/O, and presentation layers distinct? | -| Dependency direction | Do dependencies point inward (infrastructure → application → core logic)? | -| Coupling | Is coupling between modules explicit and minimal? | -| Cohesion | Are related concepts grouped together? | -| Extensibility | Can this design accommodate likely future changes without significant rework? | -| Testability | Can each component be tested in isolation? | -| Operational readiness | Are logs, metrics, and health checks present for production visibility? | - -### Repository-local deepening lens - -Use these checks when the diff changes module shape, workflow ownership, or -cross-boundary review surfaces: - -| Lens | What to check | -| --- | --- | -| Locality | Does a future maintainer find the relevant knowledge, bug, and fix in one place? | -| Leverage | Does a small interface carry meaningful behavior, or do callers still need the implementation details? | -| Shallow module | Is the module mostly a pass-through whose interface is nearly as complex as the implementation? | -| Deep module | Does the module hide real complexity behind a stable, useful interface? | -| Deletion test | If the module is deleted, does complexity vanish or reappear across multiple callers? | -| Real seam | Is there more than one real adapter or caller proving the seam earns its abstraction cost? | - -Do not require `CONTEXT.md`, ADR folders, or glossary updates for this repository -unless those structures already exist and the user explicitly makes them part of -the task. - -### Codebase orientation lens - -Use these checks when the user needs a higher-level map of unfamiliar code -instead of a defect review: - -| Lens | What to check | -| --- | --- | -| Target area | Which file, module, workflow, or behavior anchors the question? | -| Domain vocabulary | Which repository terms name the relevant concepts? | -| Module map | Which modules own the behavior, and what does each one hide or expose? | -| Caller map | Which direct callers, consumers, or workflow entrypoints depend on it? | -| Flow map | What data, control, or operational path connects the modules? | -| Boundary risk | Which ownership, abstraction, or validation boundary should a future edit respect? | +## Systems fit + +Use these checks when a diff changes module shape, workflow ownership, or +cross-boundary behavior: + +### Separation of concerns + +- Are business logic, I/O, and presentation layers distinct? +- Are module boundaries clear and cohesive? +- Does dependency direction keep higher-level behavior independent of details? +- Are interfaces stable for their callers? + +### Architecture + +- Is coupling explicit and minimal? +- Are related concepts grouped together? +- Can likely future changes be made without significant rework? +- Can components be tested in isolation? +- Are logs, metrics, and health checks sufficient for operational visibility? + +### Repository-local deepening + +- **Locality:** can a maintainer find the relevant knowledge, bug, and fix in + one place? +- **Leverage:** does a small interface hide meaningful behavior from callers? +- **Module depth:** does the module hide useful complexity rather than pass it + through? +- **Deletion test:** would deleting the module remove complexity or reproduce it + across callers? +- **Real seam:** do at least two real users justify the abstraction boundary? +- **Cross-boundary fit:** does the change belong in the touched owner, an + adjacent skill, a reference, a validator, or a generated catalog artifact? + +Do not require `CONTEXT.md`, ADR folders, or glossary updates unless those +structures already exist and the user explicitly asks for them. + +## Architecture and orientation + +When the user needs a map rather than a defect review, identify: + +- **Target area:** the file, module, workflow, or behavior being explained. +- **Domain vocabulary:** repository terms naming the concepts in play. +- **Module map:** responsibilities, dependencies, and callers. +- **Caller map:** direct consumers and workflow entrypoints. +- **Flow map:** the main data, control, or operational path. +- **Boundary risk:** ownership, abstraction, and validation boundaries to + respect. Keep the map descriptive. Promote observations to findings only when concrete evidence shows a systems risk. -## 4. Blind-spot detection +## Blind spots -Apply lateral thinking on each dimension: +Apply lateral checks to systems-fit review: -- **Temporal analysis**: Will this change cause problems at scale? After 6 months of accumulation? -- **Team dynamics**: Does this change increase onboarding friction for new team members? -- **Cross-service impact**: Could this change break consumers or upstream producers? -- **Operational burden**: What happens when this fails at 3 AM? Can on-call engineers debug it? -- **Data implications**: Are there schema changes, migration needs, or data consistency risks? -- **Security surface**: Does this change expand the attack surface? -- **Performance cliffs**: Is there a hidden O(n²) or unbounded resource consumption? -- **Configuration drift**: Are there environment-specific assumptions that break in other stages? -- **Missing observability**: Can we know if something goes wrong after deployment? -- **Alternative solutions**: Is there a fundamentally simpler approach that was not considered? +- temporal accumulation and long-term maintenance; +- onboarding and team dynamics; +- cross-service impact and operational burden; +- data implications and configuration drift; +- security surface and performance cliffs; +- missing observability and simpler alternatives. diff --git a/.github/skills/internal-review-high-level/references/audit-dispatch.md b/.github/skills/internal-review-high-level/references/audit-dispatch.md deleted file mode 100644 index ac877fed..00000000 --- a/.github/skills/internal-review-high-level/references/audit-dispatch.md +++ /dev/null @@ -1,61 +0,0 @@ -# Audit Dispatch - -Use this reference when a systems review needs a heavy audit that can be isolated -from the main assistant context. Dispatch is optional and traceable, not the -default path. - -Keep audit dispatch user-visible. State why the independent audit is worth the extra cost, latency, or context isolation before using it. - -## Source Patterns - -- Comparative source: `tmp/external-comparison/gstack/ship/SKILL.md`. -- Comparative source: `tmp/external-comparison/gstack/subagent/`. -- Use the sources as inspiration only. Do not import gstack runtime behavior. - -## Trigger Thresholds - -Consider a subagent audit when any condition is true: - -- More than 6 numbered plan files or more than 6 independent executable plan - items need completion audit. -- More than 400 changed diff lines must be mapped to plan scope. -- More than 8 changed files cross more than one repository-owned asset family. -- The reviewer explicitly asks for an independent plan-vs-diff or scope-drift - audit. - -An explicit user override may request inline review instead. - -If dispatch is used, tell the user which scope is being isolated and keep the result as a report, not a hidden decision engine. - -## Payload To Subagent - -Pass paths, not large copied content, whenever possible: - -- Plan folder path and numbered plan file list. -- `done-*` file list, if any. -- Diff command or changed-file list. -- Relevant owner references, such as `plan-completion-audit.md`, - `scope-drift.md`, and `review-lenses.md`. -- Anti-scope: no edits, no promotion decisions, no new owners. - -## Output Contract - -The subagent returns only a report: - -- Typed findings using the severity and confidence vocabulary from - `review-lenses.md`. -- `UNVERIFIABLE` gaps with the missing evidence named. -- Scope classification from `scope-drift.md`. -- Suggested route for each actionable item: `delivery`, `planning`, `critical`, - or `defer`. -- A short list of files inspected. - -## Stop Conditions - -- The subagent must not edit canonical files. -- The subagent must not create or promote repository owners. -- The subagent must not decide that an unpromoted security owner exists. -- The main assistant must spot-check at least one high or critical finding before - using the report. -- If all subagent output is speculative, treat it as evidence gaps rather than - findings. diff --git a/.github/skills/internal-review-high-level/references/review-lenses.md b/.github/skills/internal-review-high-level/references/review-lenses.md index d84ea793..6f143e6a 100644 --- a/.github/skills/internal-review-high-level/references/review-lenses.md +++ b/.github/skills/internal-review-high-level/references/review-lenses.md @@ -1,80 +1,44 @@ # Review Lenses -Use this reference when review mode needs tiered lenses without creating new -persona agents. The wrapper stays thin; each lens maps to an existing skill. +Use this reference when systems-fit review needs tiered lenses without creating +new persona agents. Cross-owner routes are recommendation-only. -## Source Patterns +## Severity -- Comparative source: `tmp/external-comparison/compound-engineering-plugin/plugins/compound-engineering/skills/ce-code-review/SKILL.md`. -- Comparative source: `tmp/external-comparison/gstack/review/SKILL.md`. -- Adopt tiering and confidence calibration only. Reject persona-as-agent catalog - expansion for this repository. - -## Always-on Lenses - -| Lens | Trigger | Owner skill | Output | -| --- | --- | --- | --- | -| Code defects | Any code, script, config, test, or policy diff under review. | `internal-review-code` | Defect-first findings with file evidence and fix route. | -| Systems fit | Any review that needs workflow, ownership, architecture, or blind-spot evidence. | `internal-review-high-level` | Systems findings, evidence gaps, scope drift, and residual risk. | - -## Cross-cutting Lenses - -| Lens | Trigger | Owner skill | Output | -| --- | --- | --- | --- | -| Delivery and operations | Workflows, release safety, operational readiness, incidents, rollout, or lifecycle changes. | `internal-devops-core-principles` | Delivery risk and readiness notes. | -| Performance | User reports slowness, the diff changes hot paths, unbounded loops, caching, batching, concurrency, or large data flow. | `internal-performance-optimization` | Measured or clearly evidenced performance risk. | -| Object collaboration | The diff changes class boundaries, construction logic, polymorphic behavior, or complex branching in object-oriented code. | `internal-oop-design-patterns` | Pattern-fit findings and simpler collaboration routes. | - -## Stack-specific Lenses - -| Trigger | Owner skill | -| --- | --- | -| `**/*.py` under reusable package or app code | `internal-python-project` | -| Standalone Python scripts, CLIs, or operator tools | `internal-python-script` | -| `**/*.js`, `**/*.cjs`, `**/*.mjs`, `**/*.ts`, `**/*.tsx`, `package.json`, or `tsconfig.json` | `internal-nodejs-project` | -| `**/*.java`, `pom.xml`, `build.gradle`, or `build.gradle.kts` | `internal-java-project` | -| `**/*.sh` standalone scripts | `internal-bash-script` | -| `**/*.tf` | `internal-terraform` | -| Dockerfiles, Compose files, or `.dockerignore` | `internal-docker` | -| Kubernetes manifests, Helm templates, or deployment YAML under Kubernetes paths | `internal-kubernetes` or `internal-kubernetes-deployment` | -| GitHub Actions workflows | `internal-github-actions` | -| Composite actions under `.github/actions/**/action.y*ml` | `internal-github-action-composite` | - -## Confidence Calibration - -Use severity and confidence together. Severity answers impact. Confidence answers -how strongly the evidence supports the finding. +Use one severity scale: | Severity | Meaning | | --- | --- | -| `info` | Non-blocking context or evidence note. | -| `low` | Low-risk maintainability, clarity, or test gap. | -| `medium` | Plausible regression, contract weakness, or missing validation. | -| `high` | Likely user-visible break, broken owner contract, or serious validation gap. | | `critical` | Security flaw, data loss, severe correctness failure, or unsafe automation. | +| `high` | Likely user-visible break, broken owner contract, or serious validation gap. | +| `medium` | Plausible regression, contract weakness, or missing validation. | +| `low` | Low-risk maintainability, clarity, or test gap. | +| `info` | Non-blocking context or evidence note. | + +## Confidence + +Use one confidence scale: | Confidence | Meaning | Reporting rule | | --- | --- | --- | -| `speculative` | The concern lacks direct evidence. | Report only as an evidence gap, not as an actionable finding. | -| `plausible` | The pattern is credible but still needs verification. | Include with caveat and route to verification. | -| `likely` | Evidence strongly supports the finding. | Include as a normal finding. | -| `verified` | File, line, diff, or validator evidence proves the issue. | Include and prioritize by severity. | +| `verified` | File, line, diff, or validator evidence proves the concern. | Include and prioritize by severity. | +| `likely` | Evidence strongly supports the concern. | Include as a normal finding. | +| `plausible` | The pattern is credible but needs verification. | Include with a caveat and route to verification. | +| `speculative` | The concern lacks direct evidence. | Report only as an evidence gap, not an actionable finding. | `critical` findings require `likely` or `verified` confidence and concrete file, line, diff, or validator evidence. -## Finding Shape - -Use this compact shape for every actionable finding: +## Finding shape ```text -[severity=] [confidence=] +[severity=] [confidence=] Evidence: Issue: Causal layer: -Route: +Route: ``` Do not use an unpromoted security review owner as active. Route -security-specific gaps through the closest existing owner and state the promotion -gap. +security-specific gaps through the closest existing owner and state the +promotion gap. diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..7b001b97 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --import-mode=importlib diff --git a/tests/github/agents/test_internal_gateway_review_generic_contract.py b/tests/github/agents/test_internal_gateway_review_generic_contract.py index 9cf6c09f..7e8bf050 100644 --- a/tests/github/agents/test_internal_gateway_review_generic_contract.py +++ b/tests/github/agents/test_internal_gateway_review_generic_contract.py @@ -1,6 +1,5 @@ from pathlib import Path - REPO_ROOT = next( parent for parent in Path(__file__).resolve().parents @@ -28,3 +27,19 @@ def test_generic_review_remains_analysis_only() -> None: text = AGENT_PATH.read_text(encoding="utf-8") assert "Do not edit files" in text assert "internal-skill-creator" not in text + + +def test_generic_review_uses_local_consistency_not_critical_agent() -> None: + text = AGENT_PATH.read_text(encoding="utf-8") + + assert "## Review Consistency Gate" in text + assert "test the strongest contrary explanation" in text + assert "internal-gateway-critical-master" not in text + assert "Critical Counter-Analysis" not in text + + +def test_generic_review_has_no_synthetic_core_skill() -> None: + text = AGENT_PATH.read_text(encoding="utf-8") + + assert "## Core Skill" not in text + assert "Do not delegate to peer agents" in text diff --git a/tests/github/skills/internal-gateway-critical-master/test_contract_alignment.py b/tests/github/skills/internal-gateway-critical-master/test_contract_alignment.py index 97c835c9..183f79b7 100644 --- a/tests/github/skills/internal-gateway-critical-master/test_contract_alignment.py +++ b/tests/github/skills/internal-gateway-critical-master/test_contract_alignment.py @@ -150,3 +150,47 @@ def test_critical_master_description_leads_with_challenge() -> None: assert frontmatter_match is not None description = frontmatter_match.group(1).strip().lower() assert "critical challenge" in description or "critical" in description + + +MAINTENANCE_GUIDANCE = BUNDLE / "references/maintenance-guidance.md" + + +def _phase_text(phase: int, next_phase: int | None) -> str: + start = SKILL_TEXT.index(f"### Phase {phase}:") + if next_phase is None: + end = SKILL_TEXT.index("## Internal critical record") + else: + end = SKILL_TEXT.index(f"### Phase {next_phase}:") + return SKILL_TEXT[start:end] + + +def test_each_critical_phase_has_an_observable_completion_criterion() -> None: + for phase, next_phase in ((1, 2), (2, 3), (3, None)): + assert "Completion criterion:" in _phase_text(phase, next_phase) + + +def test_critical_skill_is_not_an_automatic_review_countercheck() -> None: + assert "not an automatic counter-analysis" in SKILL_TEXT.lower() + assert "evidence-first review" in SKILL_TEXT.lower() + + +def test_critical_agent_declares_exactly_one_core_skill_item() -> None: + core = AGENT_MD_TEXT.split("## Core Skill", 1)[1] + bullets = [ + line for line in core.splitlines() + if line.startswith("- ") + ] + assert bullets == ["- `internal-gateway-critical-master`"] + + +def test_critical_bundle_has_no_unused_maintenance_or_legacy_exports() -> None: + assert not MAINTENANCE_GUIDANCE.exists() + assert "maintenance-guidance.md" not in SKILL_TEXT + for name in ( + "ALLOWED_CLAIM_CLASSES", + "ALLOWED_EVIDENCE_QUALITY", + "ALLOWED_LIKELIHOODS", + "ALLOWED_DEFENSE_VALUES", + "TOTAL_MAX_WORDS", + ): + assert not hasattr(critical_master, name) diff --git a/tests/github/skills/internal-review-code/test_review_code_simplification_routing_contract.py b/tests/github/skills/internal-review-code/test_review_code_simplification_routing_contract.py index 6aab23a8..302195d3 100644 --- a/tests/github/skills/internal-review-code/test_review_code_simplification_routing_contract.py +++ b/tests/github/skills/internal-review-code/test_review_code_simplification_routing_contract.py @@ -40,3 +40,27 @@ def test_code_review_runtime_prompt_requests_the_adaptive_projection() -> None: assert "adaptive chat projection" in prompt_text assert "separate follow-up" in prompt_text + + +CODE_AGENT = REPO_ROOT / ".github/agents/internal-gateway-review-code.agent.md" + + +def test_code_agent_has_one_core_skill_and_no_duplicate_review_engine() -> None: + text = CODE_AGENT.read_text(encoding="utf-8") + + assert 'description: "Use this agent when ' in text + assert "## Core Skill" in text + assert "- `internal-review-code`" in text + assert "### 1. Correctness" not in text + assert "### 2. Readability" not in text + assert "internal-gateway-critical-master" not in text + + +def test_code_wrapper_uses_operational_invocation_and_completion_criteria() -> None: + skill_text = SKILL_PATH.read_text(encoding="utf-8") + runtime_text = AGENT_PATH.read_text(encoding="utf-8") + + assert "/addyosmani-code-review-and-quality" in skill_text + assert "## Completion criteria" in skill_text + assert "/internal-review-code" in runtime_text + assert "$internal-review-code" not in runtime_text diff --git a/tests/github/skills/internal-review-high-level/test_contract.py b/tests/github/skills/internal-review-high-level/test_contract.py new file mode 100644 index 00000000..e30709c2 --- /dev/null +++ b/tests/github/skills/internal-review-high-level/test_contract.py @@ -0,0 +1,43 @@ +from pathlib import Path + +REPO_ROOT = next( + parent + for parent in Path(__file__).resolve().parents + if (parent / "AGENTS.md").exists() and (parent / ".github").exists() +) +BUNDLE = REPO_ROOT / ".github/skills/internal-review-high-level" +SKILL = BUNDLE / "SKILL.md" +RUNTIME = BUNDLE / "agents/openai.yaml" +PLAN_AUDIT = BUNDLE / "references/plan-completion-audit.md" +AUDIT_DISPATCH = BUNDLE / "references/audit-dispatch.md" + + +def test_high_level_has_two_core_routes_and_isolates_plan_audit() -> None: + text = SKILL.read_text(encoding="utf-8") + + assert "## Branch selection" in text + assert "### Systems-fit review" in text + assert "### Architecture and orientation" in text + assert "## Compatibility-only plan audit" in text + assert "plan-completion-audit.md" in text + assert PLAN_AUDIT.exists() + + +def test_high_level_removes_dispatch_and_duplicate_severity_contracts() -> None: + text = SKILL.read_text(encoding="utf-8") + + assert "audit-dispatch.md" not in text + assert not AUDIT_DISPATCH.exists() + assert "## Severity mappings" not in text + assert "Do not delegate" in text + assert "recommendation-only" in text + + +def test_high_level_runtime_names_real_routes_and_uses_slash_invocation() -> None: + text = RUNTIME.read_text(encoding="utf-8") + + assert "/internal-review-high-level" in text + assert "$internal-review-high-level" not in text + assert "systems-fit" in text + assert "architecture" in text + assert "orientation" in text diff --git a/tests/github/skills/internal-skill-creator/test_retired_ai_resource_review_contract.py b/tests/github/skills/internal-skill-creator/test_retired_ai_resource_review_contract.py index e1818d7d..18d17dcc 100644 --- a/tests/github/skills/internal-skill-creator/test_retired_ai_resource_review_contract.py +++ b/tests/github/skills/internal-skill-creator/test_retired_ai_resource_review_contract.py @@ -1,6 +1,5 @@ from pathlib import Path - REPO_ROOT = next( parent for parent in Path(__file__).resolve().parents diff --git a/tests/test_repository_test_layout_contract.py b/tests/test_repository_test_layout_contract.py index b4851a95..9abbd358 100644 --- a/tests/test_repository_test_layout_contract.py +++ b/tests/test_repository_test_layout_contract.py @@ -58,12 +58,25 @@ def test_github_owned_python_tests_make_owner_obvious() -> None: and "skills" in rel_path.parts and any(owner in rel_path.parts for owner in owners) ) + agent_owner_is_obvious = ( + "github" in rel_path.parts + and "agents" in rel_path.parts + and any( + owner in rel_path.parts + or owner.replace("-", "_") in test_path.stem + for owner in owners + ) + ) script_owner_is_obvious = ( ".github/scripts" in text and "github" in rel_path.parts and "scripts" in rel_path.parts ) - if skill_or_agent_owner_is_obvious or script_owner_is_obvious: + if ( + skill_or_agent_owner_is_obvious + or agent_owner_is_obvious + or script_owner_is_obvious + ): continue if not owners: From 41b302f77285c5ef8610232b8ea8774abd925181 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sun, 26 Jul 2026 01:16:52 +0200 Subject: [PATCH 13/23] feat: enhance internal-bash and internal-python skills with improved descriptions, routing guidance, and new test coverage --- .github/skills/internal-bash-script/SKILL.md | 19 +++- .../internal-bash-script/agents/openai.yaml | 4 +- .../references/templates.md | 8 +- .github/skills/internal-bash/SKILL.md | 6 +- .../skills/internal-bash/agents/openai.yaml | 4 +- .../references/review-anti-patterns.md | 15 ++- .../skills/internal-python-project/SKILL.md | 5 +- .../agents/openai.yaml | 4 +- .../skills/internal-python-script/SKILL.md | 13 ++- .../internal-python-script/agents/openai.yaml | 4 +- .../references/layout-and-templates.md | 10 +- .../references/reporting.md | 19 ++++ .github/skills/internal-python/SKILL.md | 13 ++- .../skills/internal-python/agents/openai.yaml | 4 +- .../references/review-anti-patterns.md | 14 +-- .../test_internal_bash_skill_contract.py | 89 +++++++++++++++ .../test_internal_python_skill_contract.py | 105 ++++++++++++++++++ 17 files changed, 291 insertions(+), 45 deletions(-) create mode 100644 tests/github/skills/internal-bash/test_internal_bash_skill_contract.py create mode 100644 tests/github/skills/internal-python/test_internal_python_skill_contract.py diff --git a/.github/skills/internal-bash-script/SKILL.md b/.github/skills/internal-bash-script/SKILL.md index 7a8aeab3..28dcb762 100644 --- a/.github/skills/internal-bash-script/SKILL.md +++ b/.github/skills/internal-bash-script/SKILL.md @@ -1,6 +1,6 @@ --- name: internal-bash-script -description: Use when creating or modifying standalone Bash scripts or shell utilities with operator-facing behavior, rather than Bash embedded inside composite actions or CI workflows. +description: Use when creating, modifying, or reviewing standalone Bash scripts, utilities, wrappers, launchers, or other operator-facing shell entrypoints. --- # Bash Script Skill @@ -14,11 +14,16 @@ description: Use when creating or modifying standalone Bash scripts or shell uti - New Bash scripts. - Existing Bash scripts that need updates. +- Standalone operator-facing wrappers, launchers, and shell utilities. ## When not to use - Bash embedded in GitHub composite actions; use `internal-github-action-composite`. - GitHub workflow-level behavior; use `internal-github-actions`. +- embedded shell and non-operator Bash helpers; use `internal-bash`. + +Use this skill directly when standalone operator behavior is the primary +contract; the lightweight sibling is not a required preload. ## Compact Bash baseline @@ -34,12 +39,20 @@ description: Use when creating or modifying standalone Bash scripts or shell uti - Prefer `printf` for formatted output and arrays for dynamic commands. - Destructive or repeatable scripts should be idempotent and expose `--dry-run` when operator risk is non-trivial. -- Validate required external commands with `command -v` before first use. - Keep operator entrypoints thin and extract repeated branches into sourced helper files only when reuse is real. - Treat 300 lines as a review threshold and 400 lines as a split-or-justify gate for standalone scripts. - When script output can grow and the script is agent-facing, prefer bounded summaries by default and add an explicit compact or quiet mode that still preserves blockers, failures, and required next actions. - Keep full-detail output reachable through an explicit flag or durable artifact path when operators need full diagnostics. -- Do not add unit tests unless explicitly requested. + +## Testing + +- For behavior changes, create the failing focused check before the first implementation edit. +- Prefer the repository's existing Bash harness. Cover parser decisions, + guards, dry-run behavior, command construction, and rerun safety at their + stable boundary. +- When no harness can exercise the behavior before editing, record a pre-code testability exception and the alternate validation path. Use syntax, lint, + and a safe non-mutating invocation as evidence; do not represent later + regression coverage as test-first work. ## Templates and hardening helpers diff --git a/.github/skills/internal-bash-script/agents/openai.yaml b/.github/skills/internal-bash-script/agents/openai.yaml index cab58853..95a058cf 100644 --- a/.github/skills/internal-bash-script/agents/openai.yaml +++ b/.github/skills/internal-bash-script/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Script Bash" - short_description: "Help with Internal Script Bash tasks" - default_prompt: "Use $internal-bash-script for this task and follow the repository-owned workflow in the skill." + short_description: "Standalone operator-facing Bash" + default_prompt: "Use $internal-bash-script for standalone Bash scripts, utilities, wrappers, launchers, and other operator-facing shell entrypoints; route embedded shell and non-operator Bash helpers to $internal-bash." diff --git a/.github/skills/internal-bash-script/references/templates.md b/.github/skills/internal-bash-script/references/templates.md index e5f28977..95627de8 100644 --- a/.github/skills/internal-bash-script/references/templates.md +++ b/.github/skills/internal-bash-script/references/templates.md @@ -17,10 +17,10 @@ set -euo pipefail DEFAULT_TARGET="default-target" -log_info() { echo "ℹ️ $*"; } -log_warn() { echo "⚠️ $*"; } -log_success() { echo "✅ $*"; } -log_error() { echo "❌ $*" >&2; } +log_info() { printf 'ℹ️ %s\n' "$*"; } +log_warn() { printf '⚠️ %s\n' "$*"; } +log_success() { printf '✅ %s\n' "$*"; } +log_error() { printf '❌ %s\n' "$*" >&2; } main() { local target="$DEFAULT_TARGET" diff --git a/.github/skills/internal-bash/SKILL.md b/.github/skills/internal-bash/SKILL.md index e4c9e0ed..73c20a82 100644 --- a/.github/skills/internal-bash/SKILL.md +++ b/.github/skills/internal-bash/SKILL.md @@ -1,6 +1,6 @@ --- name: internal-bash -description: Use when editing shell or Bash files that need lightweight safety, quoting, parser, or validation guidance. +description: Use when embedded shell, Bash snippets, or non-operator Bash helpers need lightweight safety, quoting, parser, or validation guidance before standalone script design is required. --- # Internal Bash @@ -21,6 +21,7 @@ safety to standalone script behavior. - `.sh` files and Bash snippets where the main need is a shared safety baseline. - Shell embedded in repository automation when no narrower owner has stronger rules. +- Non-operator Bash helpers that do not own a standalone operator entrypoint. - Quick checks for quoting, strict mode, guard clauses, temp files, and parser choices. ## When not to use @@ -29,6 +30,9 @@ safety to standalone script behavior. - Bash embedded in GitHub composite actions; use `internal-github-action-composite`. - GitHub workflow-level behavior; use `internal-github-actions`. +When a helper becomes a standalone operator-facing script, route to +`internal-bash-script`; this baseline does not remain a required preload. + ## Baseline - Prefer `#!/usr/bin/env bash` for repository-owned Bash scripts. diff --git a/.github/skills/internal-bash/agents/openai.yaml b/.github/skills/internal-bash/agents/openai.yaml index c95dfed9..b8d6a44d 100644 --- a/.github/skills/internal-bash/agents/openai.yaml +++ b/.github/skills/internal-bash/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Bash" - short_description: "Shell safety and Bash routing" - default_prompt: "Use $internal-bash for shell or Bash safety, quoting, parser, and validation guidance." + short_description: "Bash safety and lightweight routing" + default_prompt: "Use $internal-bash for embedded shell, Bash snippets, or non-operator Bash helpers that need lightweight safety, quoting, parser, or validation guidance before standalone script design." diff --git a/.github/skills/internal-bash/references/review-anti-patterns.md b/.github/skills/internal-bash/references/review-anti-patterns.md index cb5fb64f..edd60f3e 100644 --- a/.github/skills/internal-bash/references/review-anti-patterns.md +++ b/.github/skills/internal-bash/references/review-anti-patterns.md @@ -20,7 +20,7 @@ Baseline owner: `internal-bash` | SH-M04 | Missing `local` keyword for function variables | Pollutes global scope | | SH-M05 | POSIX `#!/bin/sh` instead of `#!/usr/bin/env bash` | Repo mandates Bash | | SH-M06 | Missing cleanup trap (`trap cleanup EXIT`) for temp files | Resource leak | -| SH-M07 | Function body longer than 30 lines | Complexity concern | +| SH-M07 | Function mixes parsing, orchestration, and mutation | Coupled responsibilities make failure handling and safe testing difficult | ## Minor @@ -56,9 +56,16 @@ rm -rf $name #!/usr/bin/env bash set -euo pipefail -local name="${1:?Missing required argument: name}" -cd /tmp || { echo "❌ Failed to cd /tmp"; exit 1; } -rm -rf "${name}" +process_directory() { + local base_dir="${1:?Missing base directory}" + local name="${2:?Missing name}" + + cd -- "$base_dir" || { + printf '❌ Failed to enter %s\n' "$base_dir" >&2 + return 1 + } + printf 'ℹ️ Processing %s\n' "$name" +} ``` ```bash diff --git a/.github/skills/internal-python-project/SKILL.md b/.github/skills/internal-python-project/SKILL.md index 74d288ec..68e7773b 100644 --- a/.github/skills/internal-python-project/SKILL.md +++ b/.github/skills/internal-python-project/SKILL.md @@ -1,6 +1,6 @@ --- name: internal-python-project -description: Use when creating or modifying Python package or application code whose primary contract is imported behavior, service boundaries, or framework-owned flows rather than operator-facing scripts. +description: Use when creating, modifying, or reviewing importable Python package, library, application, service, or framework behavior rather than directly executed operator tooling. --- # Python Project Skill @@ -26,6 +26,9 @@ description: Use when creating or modifying Python package or application code w - This skill covers structured package, library, or application components whose primary contract is reusable domain, service, or framework behavior. - Small operator-facing tools remain out of scope even when they have multiple files or tests. - A `lib/` folder, root-level tests, or multiple entrypoints alone do not make a tool application code. +- A thin CLI adapter remains project-owned when the primary contract is + importable behavior; route direct-execution tooling to + `internal-python-script`. ## Compact Python baseline diff --git a/.github/skills/internal-python-project/agents/openai.yaml b/.github/skills/internal-python-project/agents/openai.yaml index 0a4e3841..cd903353 100644 --- a/.github/skills/internal-python-project/agents/openai.yaml +++ b/.github/skills/internal-python-project/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Project Python" - short_description: "Help with Internal Project Python tasks" - default_prompt: "Use $internal-python-project for this task and follow the repository-owned workflow in the skill." + short_description: "Importable Python application guidance" + default_prompt: "Use $internal-python-project for importable Python package, library, application, service, or framework behavior; route directly executed operator tooling to $internal-python-script." diff --git a/.github/skills/internal-python-script/SKILL.md b/.github/skills/internal-python-script/SKILL.md index 3243203b..e8c57ddb 100644 --- a/.github/skills/internal-python-script/SKILL.md +++ b/.github/skills/internal-python-script/SKILL.md @@ -1,6 +1,6 @@ --- name: internal-python-script -description: Use when creating or modifying standalone Python scripts, CLIs, or small operator-facing toolkits whose primary contract is direct execution rather than reusable package or application code. +description: Use when creating, modifying, or reviewing directly executed Python scripts, CLIs, automation, or small operator-facing toolkits rather than importable application behavior. --- # Python Script Skill @@ -25,7 +25,9 @@ description: Use when creating or modifying standalone Python scripts, CLIs, or - This skill covers standalone operational tools, CLI entrypoints, and small script toolkits whose primary contract is direct execution. - A tool does not become application code just because it has multiple files, a `lib/` folder, or root-level tests. -- Move out of this lane only when the primary contract becomes imported behavior, service boundaries, or framework-owned flows. +- Move out of this lane only when the primary contract becomes imported behavior, + service boundaries, or framework-owned flows; route those cases to + `internal-python-project`. ## Script-specific guidance @@ -35,14 +37,13 @@ description: Use when creating or modifying standalone Python scripts, CLIs, or - Name configuration values by purpose, not by type: paths, file names, field lists, thresholds, defaults, mappings, filters, and output modes should explain what behavior they control. - Do not hide script-specific configuration inside helper modules or libraries. Helpers should accept explicit parameters or a small typed settings object when several values travel together. - Keep single-file scripts under 400 lines when possible. At 300 lines, review whether orchestration and helper boundaries stay clear; at 400 lines, split-or-justify is required. -- Place shared helper logic in local helper modules, preferably under `utils/` when the toolkit structure supports that layout. +- Place shared helper logic in local helper modules, preferably under `lib/` when the toolkit structure supports that layout. - For operator-facing script work, crossing the 400-line threshold should move toward a toolkit or project structure according to the primary contract, not an ever-growing single entrypoint. - Keep policy checks focused on maintained source; generated outputs and large fixture data are excluded unless directly edited. - Prefer `argparse`, `pathlib.Path`, and small helper functions for operator-facing tools. - Keep operator-facing console reporting centralized in a dedicated reporter, for example `ExecutionReporter`. Application logic should call semantic reporter methods instead of constructing styled strings or scattered `print()` calls. - Use `rich` as the preferred console rendering library for polished human-facing CLI reports when the terminal experience is part of the contract. Keep it out of `--format json`, other machine-readable outputs, and reusable helper logic. - Keep emoji, panels, tables, and color at human-facing boundaries such as banners, sections, success, warning, error, and summaries. Keep reusable helpers and machine-readable output paths free of decorative log formatting. -- Load `references/reporting.md` when a script needs professional console reporting, `rich` rendering, an `ExecutionReporter` shape, redaction rules, or verbose/debug output boundaries. - When a tool can be called from subdirectories, resolve the repository root explicitly instead of assuming the current working directory. - Use type hints on non-trivial public helpers and CLI-facing boundaries. - Use `asyncio` only when the script truly coordinates multiple I/O-bound tasks. @@ -83,7 +84,9 @@ Dependency decision note Load `references/layout-and-templates.md` when you need the default folder layout, a repo-aligned multi-tool toolkit layout, a minimal entry point, a hash-locked `requirements.txt`, or the launcher pattern. -Load `references/reporting.md` when the script needs a richer `ExecutionReporter`, `rich` console rendering, status tables, redaction behavior, or a final operator summary. +Load `references/reporting.md` when the script needs polished human-facing +output, `rich` rendering, status tables, redaction, verbose diagnostics, or a +final operator summary. Keep these rules visible while drafting: diff --git a/.github/skills/internal-python-script/agents/openai.yaml b/.github/skills/internal-python-script/agents/openai.yaml index 0bd3356c..f5147479 100644 --- a/.github/skills/internal-python-script/agents/openai.yaml +++ b/.github/skills/internal-python-script/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Script Python" - short_description: "Help with Internal Script Python tasks" - default_prompt: "Use $internal-python-script for this task and follow the repository-owned workflow in the skill." + short_description: "Direct-execution Python tooling" + default_prompt: "Use $internal-python-script for directly executed Python scripts, CLIs, automation, or operator-facing toolkits; route importable application behavior to $internal-python-project." diff --git a/.github/skills/internal-python-script/references/layout-and-templates.md b/.github/skills/internal-python-script/references/layout-and-templates.md index efb812ba..82c2e879 100644 --- a/.github/skills/internal-python-script/references/layout-and-templates.md +++ b/.github/skills/internal-python-script/references/layout-and-templates.md @@ -129,7 +129,7 @@ def main() -> int: if args.format == "json": print(render_json(payload)) else: - reporter.detail(f"Resolved repository root: {root.as_posix()}") + reporter.success(f"Resolved repository root: {root.as_posix()}") return 0 @@ -145,10 +145,10 @@ if __name__ == "__main__": # Final choice: PyYAML # Why: explicit YAML parsing without carrying a heavier content wrapper. -# requests 2.32.3 -requests==2.32.3 \ - --hash=sha256: \ - --hash=sha256: +# PyYAML 6.0.3 +PyYAML==6.0.3 \ + --hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \ + --hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a ``` Generate `requirements.txt` with `pip-compile --generate-hashes` or an equivalent workflow that locks the full dependency closure. diff --git a/.github/skills/internal-python-script/references/reporting.md b/.github/skills/internal-python-script/references/reporting.md index 1c0df080..92d13766 100644 --- a/.github/skills/internal-python-script/references/reporting.md +++ b/.github/skills/internal-python-script/references/reporting.md @@ -107,6 +107,25 @@ class ExecutionReporter: for row in rows: table.add_row(*(escape(str(value)) for value in row)) self.console.print(table) + + def summary( + self, + *, + status: str, + counts: Mapping[str, int], + produced_files: Sequence[Path], + diagnostics: Sequence[str], + ) -> None: + rows = [(name, value) for name, value in counts.items()] + if rows: + self.table("Counts", ("Metric", "Value"), rows) + self.console.print(f"Status: {escape(status)}") + self.console.print("Produced files:") + for path in produced_files: + self.console.print(f"• {escape(path.as_posix())}") + self.console.print("Diagnostics:") + for diagnostic in diagnostics: + self.console.print(f"• {escape(diagnostic)}") ``` ## Summary Expectations diff --git a/.github/skills/internal-python/SKILL.md b/.github/skills/internal-python/SKILL.md index 6d9ebf32..efcee2bb 100644 --- a/.github/skills/internal-python/SKILL.md +++ b/.github/skills/internal-python/SKILL.md @@ -1,6 +1,6 @@ --- name: internal-python -description: Use when editing Python files that need lightweight runtime, typing, testing, dependency, or readability guidance before script or project depth is needed. +description: Use when Python work needs a lightweight shared baseline or its primary contract is still unclear, including small fixes and reviews before script or application ownership is established. --- # Internal Python @@ -19,9 +19,11 @@ every Python edit; load them only when the task proves script or project depth. ## When to use -- `.py` changes where the first need is the shared Python baseline. +- `.py` changes where the first need is the shared Python baseline or the + primary contract is still unclear. - Lightweight reviews of typing, guard clauses, tests, runtime version, imports, or dependencies. -- Small Python fixes where it is not yet clear whether script or project depth is needed. +- Small Python fixes where it is not yet clear whether direct operator-facing + execution or importable application behavior is the primary contract. ## When not to use @@ -29,6 +31,11 @@ every Python edit; load them only when the task proves script or project depth. - Package, application, service, or framework-owned behavior; use `internal-python-project`. - Lambda-specific runtime behavior; combine the Lambda owner with the relevant Python owner. +Once direct operator-facing execution is established, route to +`internal-python-script`. Once importable behavior is established, route to +`internal-python-project`; this baseline is an uncertainty fallback, not an +umbrella that remains active after ownership is known. + ## Baseline - Classify Python work by primary contract before choosing structure: direct operator execution belongs to `internal-python-script`; importable package, application, service, or framework behavior belongs to `internal-python-project`. diff --git a/.github/skills/internal-python/agents/openai.yaml b/.github/skills/internal-python/agents/openai.yaml index 9e47f958..cc3de442 100644 --- a/.github/skills/internal-python/agents/openai.yaml +++ b/.github/skills/internal-python/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Internal Python" - short_description: "Python baseline and routing" - default_prompt: "Use $internal-python for Python runtime, typing, testing, dependency, or readability guidance." + short_description: "Python baseline and ownership routing" + default_prompt: "Use $internal-python when Python work needs a lightweight shared baseline or its primary contract is still unclear; route established direct operator-facing execution to $internal-python-script and established importable behavior to $internal-python-project." diff --git a/.github/skills/internal-python/references/review-anti-patterns.md b/.github/skills/internal-python/references/review-anti-patterns.md index 08966380..f8e8b3bb 100644 --- a/.github/skills/internal-python/references/review-anti-patterns.md +++ b/.github/skills/internal-python/references/review-anti-patterns.md @@ -38,16 +38,12 @@ Baseline owner: `internal-python` | PY-m07 | Missing `__all__` in modules with public API | Ambiguous public surface | | PY-m08 | Nested functions deeper than 2 levels | Readability concern | -## Nit +## Formatter and linter boundary -| ID | Anti-pattern | Why | -| --- | --- | --- | -| PY-N01 | Line length > 120 characters | PEP8 / repo convention | -| PY-N02 | Missing trailing newline at end of file | POSIX convention | -| PY-N03 | Inconsistent quote style (single vs double) within a module | Style preference | -| PY-N04 | Import not sorted (stdlib → third-party → local) | Convention consistency | -| PY-N05 | Variable named `l`, `O`, `I` (ambiguous with digits) | Readability | -| PY-N06 | Missing empty line between logical sections | Visual structure | +Defer line length, quote style, import order, trailing newline, ambiguous-name, +and blank-line diagnostics to the repository's configured formatter and linter. +Report them here only when repository evidence proves a behavioral or contract +defect beyond the tool diagnostic. ## Good vs bad examples diff --git a/tests/github/skills/internal-bash/test_internal_bash_skill_contract.py b/tests/github/skills/internal-bash/test_internal_bash_skill_contract.py new file mode 100644 index 00000000..c8990dc8 --- /dev/null +++ b/tests/github/skills/internal-bash/test_internal_bash_skill_contract.py @@ -0,0 +1,89 @@ +from pathlib import Path + +import yaml + + +REPO_ROOT = next( + parent + for parent in Path(__file__).resolve().parents + if (parent / "AGENTS.md").exists() and (parent / ".github").exists() +) +SKILLS_ROOT = REPO_ROOT / ".github/skills" +BASH = SKILLS_ROOT / "internal-bash" +SCRIPT = SKILLS_ROOT / "internal-bash-script" + + +def _description(bundle: Path) -> str: + text = (bundle / "SKILL.md").read_text(encoding="utf-8") + return str(yaml.safe_load(text.split("---", 2)[1])["description"]) + + +def _runtime(bundle: Path) -> dict[str, str]: + payload = yaml.safe_load( + (bundle / "agents/openai.yaml").read_text(encoding="utf-8") + ) + return payload["interface"] + + +def test_bash_descriptions_separate_lightweight_and_operator_contracts() -> None: + generic = _description(BASH).lower() + script = _description(SCRIPT).lower() + + assert "non-operator" in generic + assert "standalone" in script + assert "operator-facing" in script + + +def test_bash_script_routes_lightweight_near_misses_without_preloading() -> None: + text = (SCRIPT / "SKILL.md").read_text(encoding="utf-8") + + assert "embedded shell" in text + assert "non-operator Bash helper" in text + assert "internal-bash" in text + assert "load `internal-bash` first" not in text.lower() + + +def test_bash_script_uses_repository_test_first_contract() -> None: + text = (SCRIPT / "SKILL.md").read_text(encoding="utf-8") + + assert "Do not add unit tests unless explicitly requested." not in text + assert "failing focused check before the first implementation edit" in text + assert "pre-code testability exception" in text + + +def test_bash_runtime_metadata_names_real_owners() -> None: + expected = { + BASH: ("Bash safety and lightweight routing", "$internal-bash"), + SCRIPT: ("Standalone operator-facing Bash", "$internal-bash-script"), + } + + for bundle, (short_description, invocation) in expected.items(): + runtime = _runtime(bundle) + assert runtime["short_description"] == short_description + assert invocation in runtime["default_prompt"] + assert "Help with Internal" not in runtime["short_description"] + + +def test_bash_script_keeps_one_command_check_and_printf_logging() -> None: + skill = (SCRIPT / "SKILL.md").read_text(encoding="utf-8") + templates = (SCRIPT / "references/templates.md").read_text(encoding="utf-8") + + assert skill.count("command -v") == 1 + assert "printf 'ℹ️ %s\\n'" in templates + assert "printf '❌ %s\\n'" in templates + assert 'echo "ℹ️' not in templates + assert 'echo "❌' not in templates + + +def test_bash_review_examples_avoid_invalid_or_unsafe_positive_patterns() -> None: + review = (BASH / "references/review-anti-patterns.md").read_text( + encoding="utf-8" + ) + + assert "| SH-M07 | Function body longer than 30 lines" not in review + assert ( + "| SH-M07 | Function mixes parsing, orchestration, and mutation" in review + ) + assert 'rm -rf "${name}"' not in review + assert "process_directory() {" in review + assert 'cd -- "$base_dir"' in review diff --git a/tests/github/skills/internal-python/test_internal_python_skill_contract.py b/tests/github/skills/internal-python/test_internal_python_skill_contract.py new file mode 100644 index 00000000..e42989e1 --- /dev/null +++ b/tests/github/skills/internal-python/test_internal_python_skill_contract.py @@ -0,0 +1,105 @@ +from pathlib import Path + +import yaml + + +REPO_ROOT = next( + parent + for parent in Path(__file__).resolve().parents + if (parent / "AGENTS.md").exists() and (parent / ".github").exists() +) +SKILLS_ROOT = REPO_ROOT / ".github/skills" +PYTHON = SKILLS_ROOT / "internal-python" +PROJECT = SKILLS_ROOT / "internal-python-project" +SCRIPT = SKILLS_ROOT / "internal-python-script" + + +def _frontmatter_description(bundle: Path) -> str: + text = (bundle / "SKILL.md").read_text(encoding="utf-8") + return str(yaml.safe_load(text.split("---", 2)[1])["description"]) + + +def _runtime(bundle: Path) -> dict[str, str]: + payload = yaml.safe_load( + (bundle / "agents/openai.yaml").read_text(encoding="utf-8") + ) + return payload["interface"] + + +def test_python_descriptions_express_distinct_primary_contracts() -> None: + generic = _frontmatter_description(PYTHON).lower() + project = _frontmatter_description(PROJECT).lower() + script = _frontmatter_description(SCRIPT).lower() + + assert "primary contract is still unclear" in generic + assert "importable" in project + assert "directly executed" in script + assert len({generic, project, script}) == 3 + + +def test_python_skills_route_near_miss_cases_to_the_right_owner() -> None: + generic = (PYTHON / "SKILL.md").read_text(encoding="utf-8") + project = (PROJECT / "SKILL.md").read_text(encoding="utf-8") + script = (SCRIPT / "SKILL.md").read_text(encoding="utf-8") + + assert "operator-facing" in generic and "internal-python-script" in generic + assert "importable" in generic and "internal-python-project" in generic + assert "operator-facing" in project and "internal-python-script" in project + assert "imported behavior" in script and "internal-python-project" in script + + +def test_python_runtime_metadata_names_real_owners() -> None: + expected = { + PYTHON: ("Python baseline and ownership routing", "$internal-python"), + PROJECT: ( + "Importable Python application guidance", + "$internal-python-project", + ), + SCRIPT: ("Direct-execution Python tooling", "$internal-python-script"), + } + + for bundle, (short_description, invocation) in expected.items(): + runtime = _runtime(bundle) + assert runtime["short_description"] == short_description + assert invocation in runtime["default_prompt"] + assert "Help with Internal" not in runtime["short_description"] + + +def test_python_script_uses_one_toolkit_helper_convention() -> None: + skill = (SCRIPT / "SKILL.md").read_text(encoding="utf-8") + layout = (SCRIPT / "references/layout-and-templates.md").read_text( + encoding="utf-8" + ) + + assert "`lib/`" in skill + assert "`utils/`" not in skill + assert "│ └── lib/" in layout + assert skill.count("references/reporting.md") == 1 + + +def test_dependency_example_matches_its_decision() -> None: + layout = (SCRIPT / "references/layout-and-templates.md").read_text( + encoding="utf-8" + ) + + assert "Final choice: PyYAML" in layout + assert "PyYAML==" in layout + assert "requests==" not in layout + + +def test_reporter_skeleton_implements_the_advertised_summary_method() -> None: + reporting = (SCRIPT / "references/reporting.md").read_text(encoding="utf-8") + + assert "- `summary(status, counts, produced_files, diagnostics)`" in reporting + assert "def summary(" in reporting + assert "Produced files" in reporting + assert "Diagnostics" in reporting + + +def test_python_review_catalog_defers_formatter_owned_nits() -> None: + review = (PYTHON / "references/review-anti-patterns.md").read_text( + encoding="utf-8" + ) + + assert "## Nit" not in review + assert "configured formatter and linter" in review From e76cfc151c8a58845b2abbb99b9423b773bf2be4 Mon Sep 17 00:00:00 2001 From: diegoitaliait Date: Sun, 26 Jul 2026 01:43:48 +0200 Subject: [PATCH 14/23] feat: update dependency management guidelines and enhance documentation across Python skills --- .../internal-python.instructions.md | 2 +- .../skills/internal-python-project/SKILL.md | 4 +- .../references/common-mistakes.md | 5 +- .../references/examples.md | 4 + .../skills/internal-python-script/SKILL.md | 25 +++--- .../references/common-mistakes.md | 9 ++- .../references/layout-and-templates.md | 25 +++--- .../references/reporting.md | 27 ++++++- .github/skills/internal-python/SKILL.md | 2 +- .../references/review-anti-patterns.md | 13 ++- .../test_internal_python_skill_contract.py | 81 ++++++++++++++++++- 11 files changed, 153 insertions(+), 44 deletions(-) diff --git a/.github/instructions/internal-python.instructions.md b/.github/instructions/internal-python.instructions.md index 454d253d..9e4b7fcd 100644 --- a/.github/instructions/internal-python.instructions.md +++ b/.github/instructions/internal-python.instructions.md @@ -17,7 +17,7 @@ This file is optimized for Copilot code review and should produce only evidenced - Flag manual formatting churn that fights the repository formatter; when Ruff is configured, prefer `ruff format` and Ruff diagnostics over subjective style edits. - Report dependency usage that is unpinned, unnecessary for the change, or unjustified for the data volume and import or install cost. - Flag vendored libraries, wheelhouses, copied site-packages, or fallback dependency mirrors. -- Flag new external dependencies that are missing hash-locked pins in the owning requirements file. +- Preserve the repository-declared dependency manager. For pip requirements, require exact pins and hashes in the owning requirements file; for another declared dependency manager, require its canonical lock artifact and frozen or locked validation command. - When behavior changes, verify docs and output contracts stay aligned: filenames, produced artifacts, columns, and other user-visible output details must match reality. - Check tests for deterministic coverage of changed behavior. - Flag test setup that bypasses the repository's shared runner, pytest rootdir or testpaths contract, or declared interpreter or virtualenv setup without a reproducibility reason. diff --git a/.github/skills/internal-python-project/SKILL.md b/.github/skills/internal-python-project/SKILL.md index 68e7773b..08ebdd76 100644 --- a/.github/skills/internal-python-project/SKILL.md +++ b/.github/skills/internal-python-project/SKILL.md @@ -41,7 +41,7 @@ description: Use when creating, modifying, or reviewing importable Python packag - Pass configuration into reusable project code through typed settings, constructor arguments, or function parameters. Domain and service code should not read environment variables, files, or deployment defaults directly unless that boundary is its explicit responsibility. - Do not confuse domain invariants with configuration. Stable rules that belong to the domain may stay near the domain code; deployment-specific paths, endpoints, thresholds, defaults, and feature switches should live at the configuration boundary. - Do not vendor libraries, wheelhouses, copied site-packages, or fallback dependency mirrors. -- If external packages are introduced, keep exact pins and hashes in the owning requirements file. +- Preserve the repository-declared dependency manager. For pip requirements, keep exact pins and hashes in the owning requirements file; for another declared dependency manager, update its canonical lock artifact and use its frozen or locked validation command. ## Application-specific guidance @@ -88,6 +88,6 @@ Load `references/common-mistakes.md` for the full mistake table. ## Validation - `python -m compileall ` (syntax check) -- `pip install --require-hashes -r requirements.txt` (dependency integrity check, only when requirements change) +- For pip-managed projects, run `pip install --require-hashes -r requirements.txt` when requirements change; for another declared manager, run its canonical frozen or locked validation command. - `pytest tests/` (run tests) - Lint with project's configured linter. diff --git a/.github/skills/internal-python-project/references/common-mistakes.md b/.github/skills/internal-python-project/references/common-mistakes.md index 3b2f8ada..e73c6166 100644 --- a/.github/skills/internal-python-project/references/common-mistakes.md +++ b/.github/skills/internal-python-project/references/common-mistakes.md @@ -4,11 +4,12 @@ | --- | --- | --- | | Business logic mixed with I/O (DB calls, HTTP) | Untestable, hard to refactor | Extract pure logic into service/domain modules | | Mutable default arguments (`def f(items=[])`) | Shared state between calls — classic Python gotcha | Use `None` default + create inside function | -| Bare `except:` or `except Exception:` | Swallows `KeyboardInterrupt`, `SystemExit` | Catch specific exceptions | +| bare `except:` | Also catches control-flow exceptions such as `KeyboardInterrupt` and `SystemExit` | Catch the narrowest expected exception | +| Broad `except Exception` without handling, logging, or re-raise | Can hide ordinary application failures and leave partial work unexplained | Handle expected failures explicitly and let unexpected failures propagate | | No type hints on public API | Hard to understand contracts, no static analysis | Add type hints on function signatures | | Injecting every collaborator as a `*_fn` hook or alias shim | Hides real seams and makes call flow harder to follow | Inject only true external boundaries or variability points; call stable helpers directly | | Copying shared helper logic across modules | Fixes drift and behavior diverges across call sites | Define the helper once in the owning module and import it | -| Updating dependency requirements without refreshed hashes | Reproducible installs break or drift silently | Regenerate exact pins and hashes, then validate with `pip install --require-hashes -r requirements.txt` | +| Changing dependencies without updating the declared manager's lock artifact | Reproducible installs break or drift silently | Preserve the declared dependency manager; for pip, regenerate exact pins and hashes, and otherwise use its canonical frozen or locked validation command | | Tests that depend on execution order | Fragile test suite, non-deterministic failures | Each test must be self-contained | | Forcing async into CPU-bound or simple flows | Adds complexity without throughput benefit | Keep it synchronous unless I/O concurrency is the real bottleneck | | HTTP client pools smaller than worker or task concurrency | Work queues behind the pool and hides throughput bottlenecks | Size connection pools and limits to match max worker or async concurrency | diff --git a/.github/skills/internal-python-project/references/examples.md b/.github/skills/internal-python-project/references/examples.md index 26074c0b..0a709568 100644 --- a/.github/skills/internal-python-project/references/examples.md +++ b/.github/skills/internal-python-project/references/examples.md @@ -2,6 +2,8 @@ ## Minimal Module Example +`account_status.py` + ```python """Purpose: Resolve account status based on domain rules.""" @@ -26,6 +28,8 @@ def resolve_account_state(account_id: AccountId, is_locked: bool) -> str: ## Minimal Test Example ```python +from account_status import AccountId + import pytest diff --git a/.github/skills/internal-python-script/SKILL.md b/.github/skills/internal-python-script/SKILL.md index e8c57ddb..09565347 100644 --- a/.github/skills/internal-python-script/SKILL.md +++ b/.github/skills/internal-python-script/SKILL.md @@ -61,9 +61,18 @@ description: Use when creating, modifying, or reviewing directly executed Python - Keep comments, docstrings, logs, exceptions, and CLI output in English. - Use the repository-declared runtime before falling back to ambient `python3`. - Do not vendor libraries, wheelhouses, copied site-packages, or fallback dependency mirrors. -- If external packages are introduced, keep exact pins and hashes in the owning requirements file. +- Keep dependency changes in the repository-declared dependency manager and its canonical lock artifact. -## Dependency decision note +## Dependency policy + +Preserve the repository-declared dependency manager. For pip requirements, keep +exact pins and hashes in the owning requirements file. For another declared +dependency manager, update its canonical lock artifact and use its frozen or +locked validation command. + +For pip requirements, generate the lock output with +`pip-compile --generate-hashes` and validate it with +`pip install --require-hashes -r requirements.txt`. When the Python baseline requires a dependency decision note, keep it short, for example: @@ -76,13 +85,12 @@ Dependency decision note - Keep the note short and task-specific. - Compare the standard library with realistic third-party candidates. -- If the final choice uses external libraries, create or update the local `requirements.txt` before finishing the task. -- Keep exact pins and current hashes in `requirements.txt`. Use `pip-compile --generate-hashes` or an equivalent repository-approved workflow, then validate with `pip install --require-hashes -r requirements.txt` when the requirements file changes. -- If several entrypoints share the same lock file, record the decision once at the shared toolkit `requirements.txt` rather than repeating it in every script. +- If the final choice uses external libraries and no other dependency manager is declared, create or update the local `requirements.txt` before finishing the task; otherwise update the declared manager's canonical lock artifact. +- If several entrypoints share the same pip lock file, record the decision once at the shared toolkit `requirements.txt` rather than repeating it in every script. ## Layout and templates -Load `references/layout-and-templates.md` when you need the default folder layout, a repo-aligned multi-tool toolkit layout, a minimal entry point, a hash-locked `requirements.txt`, or the launcher pattern. +Load `references/layout-and-templates.md` when you need the default folder layout, a repo-aligned multi-tool toolkit layout, a minimal entry point, a pip-managed hash-locked `requirements.txt`, or the launcher pattern. Load `references/reporting.md` when the script needs polished human-facing output, `rich` rendering, status tables, redaction, verbose diagnostics, or a @@ -91,8 +99,7 @@ final operator summary. Keep these rules visible while drafting: - Use a dedicated tool folder or toolkit root rather than a loose top-level `.py` file. -- Add `requirements.txt` and `run.sh` only when external packages are actually needed. -- Generate `requirements.txt` with `pip-compile --generate-hashes` or an equivalent locked workflow. +- Add a pip-managed `requirements.txt` and `run.sh` only when external packages are actually needed and no other dependency manager is declared. - Reuse an existing shared runner such as `.github/scripts/run.sh` instead of cloning bootstrap logic into every entrypoint. - Mirror script or toolkit coverage under the repository-root `tests/` tree; do not create ad-hoc test folders beside the tool. @@ -120,6 +127,6 @@ Load `references/common-mistakes.md` for the full mistake table. - `python -m py_compile .py` (syntax check) - `bash -n run.sh` (launcher syntax check, only when `run.sh` exists) -- `pip install --require-hashes -r requirements.txt` (dependency integrity check, only when requirements change) +- For pip-managed tools, run `pip install --require-hashes -r requirements.txt` when requirements change; for another declared manager, run its canonical frozen or locked validation command. - `pytest tests/` (run tests) - `python -m compileall ` or the repository's canonical shared runner when the tool already lives inside a maintained toolkit diff --git a/.github/skills/internal-python-script/references/common-mistakes.md b/.github/skills/internal-python-script/references/common-mistakes.md index b9a2080a..3273329e 100644 --- a/.github/skills/internal-python-script/references/common-mistakes.md +++ b/.github/skills/internal-python-script/references/common-mistakes.md @@ -5,14 +5,15 @@ | Missing `if __name__ == "__main__":` guard | Script runs on import, breaks testing and reuse | Always guard the entry point | | Using a hyphenated or file-only entrypoint that cannot be imported cleanly | Breaks `python -m`, packaging, and test reuse | Expose an importable `cli.py`, package `__main__.py`, or `console_scripts` entrypoint | | Using `print()` for errors | Errors go to stdout, mixed with normal output | Use `print(..., file=sys.stderr)` or `logging` | -| Bare `except:` or `except Exception:` at top level | Swallows all errors including KeyboardInterrupt | Catch specific exceptions; let unexpected ones propagate | +| bare `except:` at the script boundary | Also catches control-flow exceptions such as `KeyboardInterrupt` and `SystemExit` | Catch the narrowest expected exception and let control-flow exceptions propagate | +| Broad `except Exception` without handling, logging, or re-raise | Can hide ordinary application failures and leave partial work unexplained | Handle expected failures explicitly and let unexpected failures propagate | | Hardcoded file paths | Non-portable across machines | Use `argparse`, `pathlib`, or environment variables | | No argument parsing | Caller has to modify script source to change behavior | Use `argparse` for any configurable parameter | -| Installing deps globally or without hash-locked version pinning | Non-reproducible environment and hidden setup drift | Keep dependencies in the local `requirements.txt` with exact pins and hashes | +| Installing deps outside the declared dependency manager or without a reproducible lock | Non-reproducible environment and hidden setup drift | Preserve the declared manager; for pip use exact pins and hashes, otherwise use its canonical lock artifact | | Adding an empty `requirements.txt` to a stdlib-only tool | Adds noise and implies missing setup steps | Omit `requirements.txt` when the script uses only the standard library | -| Updating `requirements.txt` without refreshed hashes | Breaks reproducible installs and hides dependency drift | Regenerate exact pins and hashes, then validate with `pip install --require-hashes -r requirements.txt` | +| Changing dependencies without updating the declared manager's lock artifact | Breaks reproducible installs and hides dependency drift | Preserve the declared manager; for pip regenerate exact pins and hashes, otherwise run its frozen or locked validation command | | Wrapping a stdlib-only script in Bash | Adds setup indirection without solving a real dependency problem | Document direct `python3