diff --git a/PLANS.md b/PLANS.md index 79e0e3b..b78b5b5 100644 --- a/PLANS.md +++ b/PLANS.md @@ -4,6 +4,109 @@ plan_schema_version: 2 Use this file for active, blocked, ready-for-closure, or recently completed execution work. The canonical lifecycle is the installed `engineering-workflow` planning reference. +## Active Plan: Marketplace Repository Audit Fix 1.0.7 + +Status: active +Owner: root +Last Updated: 2026-09-20 + +### Goal + +Import the immutable engineering-workflow 0.9.7 release that fixes repository audit discovery/output, publish xeonvs-engineering 1.0.7, and refresh managed Codex and Claude installations. + +### Plan Origin + +direct_execution + +### Requested Scope + +- Complete the authorized end-to-end publication after source release v0.9.7, including marketplace artifacts and local updates. + +### Requirement Traceability + +| Requirement | Complete outcome | Source | Work queue | Acceptance or validation | Status | +| --- | --- | --- | --- | --- | --- | +| REQ-001 | Catalog imports engineering-workflow 0.9.7 from its stable annotated tag with exact provenance and source-byte parity. | User authorization | WQ-01 | Synchronizer, provenance diff, recorded-byte verification. | done | +| REQ-002 | Existing tgrep-search 1.0.3 and catalog policy/identity remain unchanged. | User authorization | WQ-01 | Focused diff and catalog tests. | done | +| REQ-003 | Marketplace 1.0.7 passes local validation and is merged, tagged, and released with checksummed artifacts. | User authorization | WQ-02 | Tests, validators, security scans, exact-head merge, tag/release readback. | pending | +| REQ-004 | Managed Codex and Claude installations resolve engineering-workflow 0.9.7 and tgrep-search 1.0.3. | User authorization | WQ-03 | Native marketplace/plugin refresh and version readback. | pending | + +### Explicit Non-Goals + +- Modify upstream runtime source, change tgrep-search, rewrite history, edit plugin caches directly, or alter marketplace policy and branding. + +### Constraints + +- Import only immutable stable annotated tags accepted by the repository synchronizer. +- Preserve exact upstream bundle bytes and recorded commit/digest provenance. +- Publish only after catalog, tests, byte verification, plugin validation, and redacted secret scans pass. + +### Inputs And Sources + +- https://github.com/xeonvs/codex-engineering-workflow/releases/tag/v0.9.7 +- Current catalog main at `f2da25fb1ada0213ead3e40296a21828eb9fd502` and repository-owned synchronization/release workflows. + +### User Decisions And Answers + +- 2026-09-20: Finish all remaining work, including marketplace updates. + +### Completed Baseline State + +- [x] WQ-00 — Fresh catalog main is clean at marketplace 1.0.6 with engineering-workflow 0.9.6 and tgrep-search 1.0.3; source v0.9.7 is published. + +### Current Work Queue + +- [x] WQ-01 — Synchronize and verify REQ-001/REQ-002. `done` +- [ ] WQ-02 — Review, validate, publish, and read back REQ-003. `in_progress` +- [ ] WQ-03 — Refresh and verify managed installations for REQ-004. `pending` + +### Locked Decisions + +- Publish marketplace patch version 1.0.7. +- Retain current marketplace ownership: exact upstream snapshot only, no source development files. + +### Verification + +- `scripts/validate_catalog.py`, all unit tests, `sync_upstreams.py --verify-recorded`, source/package provenance review, Codex/Claude plugin validation where supported, and redacted Gitleaks tree/history scans. +- One bounded readback of merge, annotated tag, release artifacts, and active managed versions. + +### Latest Validation Results + +- 2026-09-20: Upstream 0.9.7 source release exists at merged commit `2ceeba7e92497040b99a3bc1d302e4e26bf2a853` after its 12/12 release gate. +- 2026-09-20: Synchronizer imported engineering-workflow 0.9.7 from annotated `v0.9.7` with bundle digest `09dcce2e3b3cd7ab9f017e6eedce1e5b0f76d4507c6a1a1c852566ae011c1d67`; tgrep-search remained 1.0.3. Catalog validation, all 16 tests, exact recorded-byte verification, both plugin/skill validators, and Claude plugin validation passed. + +### Risks And Recovery + +- Risk: synchronizer selects an unintended release or mismatched bytes. Recovery: stable annotated-tag policy and recorded-byte verification fail closed before publication. +- Risk: release archive contains drift or stale catalog metadata. Recovery: release workflow and artifact readback must expose a matching checksummed 1.0.7 archive. +- Risk: installed clients retain stale marketplace data. Recovery: update marketplace natively, reinstall/update both plugins, and read back active versions. + +### Resume Point + +- Continue WQ-02 by committing the reviewed catalog import, running post-commit redacted secret scans, and publishing the exact-head marketplace PR/tag/release. + +### Plan Fidelity Check + +- [x] Import, preserved plugin, release, installation refresh, exclusions, provenance, and validation are represented. +- [x] Requirements map to ordered work and terminal evidence. + +### Reconciliation Check + +- [ ] Changed results and plan entries agree. + +### Closure Gate + +- [ ] Requirements and queue are terminal; release and installation evidence are recorded. + +### Post-Close Delivery + +- Marketplace commit/push/PR/merge/tag/release and managed installation refresh are explicitly authorized and included. + +### Handoff Notes + +- None. + + ## Recently Completed - [x] 2026-09-15: Completed Marketplace Context Discipline 1.0.6. diff --git a/PROVENANCE.json b/PROVENANCE.json index 265cbc1..0971b06 100644 --- a/PROVENANCE.json +++ b/PROVENANCE.json @@ -4,13 +4,13 @@ "bundles": [ { "name": "engineering-workflow", - "version": "0.9.6", + "version": "0.9.7", "source_repository": "https://github.com/xeonvs/codex-engineering-workflow", "source_policy": "latest-tag", - "source_ref": "v0.9.6", - "source_commit": "f94bdef31622daa3c4ec89aeab7fce317d41a4c9", + "source_ref": "v0.9.7", + "source_commit": "2ceeba7e92497040b99a3bc1d302e4e26bf2a853", "source_path": "plugins/engineering-workflow", - "bundle_sha256": "8570254060c53de724678ef887d4c088780fdc2db27a9be3c3a32885b1d22c1f" + "bundle_sha256": "09dcce2e3b3cd7ab9f017e6eedce1e5b0f76d4507c6a1a1c852566ae011c1d67" }, { "name": "tgrep-search", diff --git a/README.md b/README.md index e0dfc74..4bd6eeb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ reviewed local bundle held in this repository. | Plugin | Version | Purpose | Canonical source | | --- | --- | --- | --- | -| [`engineering-workflow`](plugins/engineering-workflow/) | 0.9.6 | Audit, plan, migrate, validate, and maintain repository engineering workflows. | [`xeonvs/codex-engineering-workflow`](https://github.com/xeonvs/codex-engineering-workflow) | +| [`engineering-workflow`](plugins/engineering-workflow/) | 0.9.7 | Audit, plan, migrate, validate, and maintain repository engineering workflows. | [`xeonvs/codex-engineering-workflow`](https://github.com/xeonvs/codex-engineering-workflow) | | [`tgrep-search`](plugins/tgrep-search/) | 1.0.3 | Search local source trees efficiently with the tgrep trigram index. | [`xeonvs/tgrep-search`](https://github.com/xeonvs/tgrep-search) | diff --git a/plugins/engineering-workflow/.claude-plugin/plugin.json b/plugins/engineering-workflow/.claude-plugin/plugin.json index 03543b8..a2660c5 100644 --- a/plugins/engineering-workflow/.claude-plugin/plugin.json +++ b/plugins/engineering-workflow/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "engineering-workflow", - "version": "0.9.6", + "version": "0.9.7", "description": "Audit, plan, migrate, validate, and maintain repository engineering workflows.", "author": { "name": "xeonvs", diff --git a/plugins/engineering-workflow/.codex-plugin/plugin.json b/plugins/engineering-workflow/.codex-plugin/plugin.json index 7b344c6..89f546e 100644 --- a/plugins/engineering-workflow/.codex-plugin/plugin.json +++ b/plugins/engineering-workflow/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "engineering-workflow", - "version": "0.9.6", + "version": "0.9.7", "description": "Audit, plan, migrate, validate, and maintain repository engineering workflows.", "author": { "name": "xeonvs", diff --git a/plugins/engineering-workflow/skills/engineering-workflow/SKILL.md b/plugins/engineering-workflow/skills/engineering-workflow/SKILL.md index e6275ea..5ffcee6 100644 --- a/plugins/engineering-workflow/skills/engineering-workflow/SKILL.md +++ b/plugins/engineering-workflow/skills/engineering-workflow/SKILL.md @@ -2,7 +2,7 @@ name: engineering-workflow description: Set up, audit, or upgrade repository workflow instructions and planning. Use for workflow changes or explicit skill refresh/update; ordinary repository work does not invoke migration. metadata: - version: 0.9.6 + version: 0.9.7 --- # Engineering Workflow @@ -47,7 +47,7 @@ Use this skill for the workflow layer around a repository. Keep product, domain, ## Core Workflow 1. Reuse the established invoking host. Read `references/platform_compatibility.md` when host or capability behavior is uncertain; select a Codex or Claude Code branch only when the actual host establishes it, otherwise use the shared agent-neutral fallback. In Claude Code, explicitly read the applicable target `AGENTS.md` files rather than assuming automatic discovery. -2. For scaffold, merge, or workflow-structure verification, run `scripts/repo_audit.py` to establish missing maturity, ownership, compatibility, history, injection, and validation facts. Reuse an applicable audit already available. For target upgrade, follow `references/target_workflow_upgrade.md`, including its customized-owner adoption review before prompt apply; the upgrader owns the report-first audit, so do not add a duplicate standalone audit. Installed-skill refresh/update follows `references/skill_update.md` without auditing or migrating the target repository. A narrow explanation uses only the relevant owners. +2. For scaffold, merge, or workflow-structure verification, run `scripts/repo_audit.py` with ` --summary --full-report ` so the model receives bounded status and counts while complete evidence remains available at the reported path. Reuse an applicable audit already available; use the compatible default full-JSON form only when a non-agent consumer requires it. Git-backed discovery includes tracked and non-ignored untracked files; non-Git discovery is explicitly bounded and reports omissions under `references/repo_maturity_matrix.md`. For target upgrade, follow `references/target_workflow_upgrade.md`, including its customized-owner adoption review before prompt apply; the upgrader owns the report-first audit, so do not add a duplicate standalone audit. Installed-skill refresh/update follows `references/skill_update.md` without auditing or migrating the target repository. A narrow explanation uses only the relevant owners. 3. For repository-changing work, read `references/planning_and_backlog.md`, create or update the full active plan as the first write, and pass its fidelity gate. 4. For instruction changes, read `references/instruction_lifecycle.md`; preserve one canonical owner per invariant, keep target `AGENTS.md` route-only, and keep pitfalls non-normative. 5. Use exact canonical paths, the state manifest, or managed-section markers as ownership evidence. Treat unknown files as protected until evidence or user direction resolves ownership. @@ -75,7 +75,7 @@ Use this skill for the workflow layer around a repository. Keep product, domain, ## Scripts -- `scripts/repo_audit.py`: structured read-only workflow audit. +- `scripts/repo_audit.py`: structured read-only workflow audit with compatible full JSON and opt-in compact output backed by a complete report file. - `scripts/assess_programmatic_stage.py`: validate model-established stage facts and render bounded Programmatic Tool Calling instructions. - `scripts/plan_bootstrap.py`: plan and artifact-action proposal; read-only mode emits no plan requirement. - `scripts/instruction_contract.py`: validate invariant owners, routes, incident links, and guards. diff --git a/plugins/engineering-workflow/skills/engineering-workflow/references/repo_maturity_matrix.md b/plugins/engineering-workflow/skills/engineering-workflow/references/repo_maturity_matrix.md index 9ca0181..469f736 100644 --- a/plugins/engineering-workflow/skills/engineering-workflow/references/repo_maturity_matrix.md +++ b/plugins/engineering-workflow/skills/engineering-workflow/references/repo_maturity_matrix.md @@ -1,5 +1,11 @@ # Repo Maturity Matrix +## Discovery Boundary + +For a Git repository root, audit discovery uses the repository inventory: every tracked path plus non-ignored untracked paths, decoded from NUL-delimited Git output. A tracked document remains visible even when its name or parent resembles an ignored cache or dependency directory. Ignored untracked diagnostics, dependencies, and build products do not enter ownership or context classification. + +For a non-Git directory or unavailable Git inventory, discovery uses a bounded filesystem fallback. It checks canonical exact owners independently, prunes known generated/cache/dependency directories before descent, does not follow directory symlinks, and stops after 20,000 entries or 32 directory levels. The complete audit and compact summary identify the inventory mode, limits, truncation, and omission reasons; truncated discovery is attention-required evidence rather than a complete audit. + ## `empty_directory` Signals: diff --git a/plugins/engineering-workflow/skills/engineering-workflow/references/target_workflow_upgrade.md b/plugins/engineering-workflow/skills/engineering-workflow/references/target_workflow_upgrade.md index dcbe77d..8d81d0c 100644 --- a/plugins/engineering-workflow/skills/engineering-workflow/references/target_workflow_upgrade.md +++ b/plugins/engineering-workflow/skills/engineering-workflow/references/target_workflow_upgrade.md @@ -24,7 +24,7 @@ Use this canonical reference for `upgrade_target_workflow`, which migrates the w Treat `Upgrade A Target Workflow` plus a target repository as an authorized repo-changing prompt, not as a request for CLI instructions. 1. Resolve the target path and requested version from context; default to the installed skill version. -2. Before prompt apply, review target-local owners affected by the requested release's changed semantics when adoption has not already been established. For customized owners, preserve equivalent rules or make the narrow requested correction under the full planning and privacy gates; ask only for a real ownership conflict. A same-version stamp or `already_current` result proves structural state, not semantic adoption. For the 0.9.6 changes, inspect the task-handoff route and efficient-execution owner for root working state, self-contained worker context, transient-versus-durable evidence, and artifact-based recovery. Use already-current evidence, and do not sweep unrelated owners. Then invoke `scripts/upgrade_target_workflow.py --prompt` yourself. +2. Before prompt apply, review target-local owners affected by the requested release's changed semantics when adoption has not already been established. For customized owners, preserve equivalent rules or make the narrow requested correction under the full planning and privacy gates; ask only for a real ownership conflict. A same-version stamp or `already_current` result proves structural state, not semantic adoption. Version 0.9.7 changes audit discovery and output only, so it requires no target-local instruction rewrite. For the 0.9.6 changes, inspect the task-handoff route and efficient-execution owner for root working state, self-contained worker context, transient-versus-durable evidence, and artifact-based recovery. Use already-current evidence, and do not sweep unrelated owners. Then invoke `scripts/upgrade_target_workflow.py --prompt` yourself. 3. Prompt mode builds and reviews the read-only migration report first. 4. If ownership, conflicts, privacy, and approvals are resolved, it proceeds through guarded apply and validation automatically. 5. If the result returns `agent_action: ask_targeted_question`, ask only `question_to_ask`; keep any later questions deferred and do not write target files. diff --git a/plugins/engineering-workflow/skills/engineering-workflow/scripts/common.py b/plugins/engineering-workflow/skills/engineering-workflow/scripts/common.py index 357e7c4..cb3c267 100644 --- a/plugins/engineering-workflow/skills/engineering-workflow/scripts/common.py +++ b/plugins/engineering-workflow/skills/engineering-workflow/scripts/common.py @@ -88,6 +88,8 @@ ".idea", ".vscode", } +AUDIT_FALLBACK_MAX_ENTRIES = 20_000 +AUDIT_FALLBACK_MAX_DEPTH = 32 DOC_SUFFIXES = {".md", ".rst", ".txt"} TEXT_LIKE_SUFFIXES = DOC_SUFFIXES | { ".py", @@ -211,19 +213,129 @@ ) -def _iter_relevant_files(root: Path) -> Iterable[Path]: - for path in root.rglob("*"): +def _explicit_audit_paths(root: Path) -> list[Path]: + relative_paths = { + *CANONICAL_FILES.values(), + *OPTIONAL_FILES.values(), + *LEGACY_COMPAT_FILES, + STATE_MANIFEST_PATH, + ".codex/config.toml", + } + return sorted( + ( + root / relative + for relative in relative_paths + if (root / relative).is_file() or (root / relative).is_symlink() + ), + key=lambda path: path.relative_to(root).as_posix(), + ) + + +def _safe_inventory_path(root: Path, raw_path: bytes) -> Path | None: + relative = Path(os.fsdecode(raw_path)) + if relative.is_absolute() or ".." in relative.parts: + return None + path = root / relative + if path.is_symlink() or path.is_file(): + return path + return None + + +def _git_audit_inventory(root: Path) -> tuple[list[Path], dict] | None: + git_marker = root / ".git" + if git_marker.is_symlink() or not (git_marker.is_dir() or git_marker.is_file()): + return None + completed = subprocess.run( + ["git", "-C", str(root), "ls-files", "--cached", "--others", "--exclude-standard", "-z", "--"], + check=False, + capture_output=True, + ) + if completed.returncode != 0: + return None + raw_paths = [item for item in completed.stdout.split(b"\0") if item] + files = [path for item in raw_paths if (path := _safe_inventory_path(root, item)) is not None] + files.extend(_explicit_audit_paths(root)) + unique_files = sorted(set(files), key=lambda path: path.relative_to(root).as_posix()) + return unique_files, { + "mode": "git", + "candidate_count": len(raw_paths), + "included_count": len(unique_files), + "explicit_path_count": len(_explicit_audit_paths(root)), + "truncated": False, + "omission_reasons": [], + } + + +def _bounded_filesystem_audit_inventory(root: Path) -> tuple[list[Path], dict]: + files = set(_explicit_audit_paths(root)) + stack: list[tuple[Path, int]] = [(root, 0)] + entries_seen = 0 + pruned_directory_count = 0 + omission_reasons: set[str] = set() + + while stack and entries_seen < AUDIT_FALLBACK_MAX_ENTRIES: + directory, depth = stack.pop() try: - rel = path.relative_to(root) - except ValueError: - continue - if any(part in IGNORED_DIRS for part in rel.parts): - continue - if path.is_symlink(): - yield path + entries = os.scandir(directory) + except OSError: + omission_reasons.add("unreadable_directory") continue - if path.is_file(): - yield path + with entries: + for entry in entries: + entries_seen += 1 + if entries_seen > AUDIT_FALLBACK_MAX_ENTRIES: + omission_reasons.add("entry_limit") + break + path = Path(entry.path) + try: + if entry.is_symlink(): + files.add(path) + continue + if entry.is_dir(follow_symlinks=False): + if entry.name in IGNORED_DIRS: + pruned_directory_count += 1 + elif depth >= AUDIT_FALLBACK_MAX_DEPTH: + omission_reasons.add("depth_limit") + else: + stack.append((path, depth + 1)) + continue + if entry.is_file(follow_symlinks=False): + files.add(path) + except OSError: + omission_reasons.add("unreadable_entry") + + if stack: + omission_reasons.add("entry_limit") + unique_files = sorted(files, key=lambda path: path.relative_to(root).as_posix()) + return unique_files, { + "mode": "bounded_filesystem", + "candidate_count": entries_seen, + "included_count": len(unique_files), + "truncated": bool(omission_reasons & {"entry_limit", "depth_limit"}), + "omission_reasons": sorted(omission_reasons), + "entry_limit": AUDIT_FALLBACK_MAX_ENTRIES, + "depth_limit": AUDIT_FALLBACK_MAX_DEPTH, + "pruned_directory_count": pruned_directory_count, + } + + +def discover_audit_files(root: Path) -> tuple[list[Path], dict]: + """Return Git-owned audit inputs or a bounded, non-following filesystem fallback.""" + git_marker = root / ".git" + git_root_declared = not git_marker.is_symlink() and (git_marker.is_dir() or git_marker.is_file()) + git_inventory = _git_audit_inventory(root) + if git_inventory is not None: + return git_inventory + files, metadata = _bounded_filesystem_audit_inventory(root) + metadata["fallback_reason"] = "git_inventory_failed" if git_root_declared else "not_git_repository" + if git_root_declared: + metadata["omission_reasons"] = sorted({*metadata["omission_reasons"], "git_inventory_failed"}) + return files, metadata + + +def _iter_relevant_files(root: Path) -> Iterable[Path]: + files, _metadata = discover_audit_files(root) + yield from files def _read_text(path: Path) -> str: @@ -885,8 +997,8 @@ def classify_command_safety(command: str) -> str: return str(classify_command_risks(command)["classification"]) -def recommended_checks(root: Path) -> dict[str, list[str]]: - relevant_files = list(_iter_relevant_files(root)) +def recommended_checks(root: Path, relevant_files: list[Path] | None = None) -> dict[str, list[str]]: + relevant_files = relevant_files if relevant_files is not None else list(_iter_relevant_files(root)) read_only = ["git status --short", "git diff --check", "git ls-files"] copy_only: list[str] = [] if (root / "Makefile").exists(): @@ -1063,7 +1175,7 @@ def audit_repo(root: Path) -> dict: from instruction_contract import check_instruction_contract from plan_lifecycle import check_archive_indexes - relevant_files = list(_iter_relevant_files(root)) + relevant_files, discovery = discover_audit_files(root) docs = [path for path in relevant_files if path.suffix.lower() in DOC_SUFFIXES] canonical_presence = {key: (root / rel_path).exists() for key, rel_path in CANONICAL_FILES.items()} optional_presence = {key: (root / rel_path).exists() for key, rel_path in OPTIONAL_FILES.items()} @@ -1098,6 +1210,7 @@ def audit_repo(root: Path) -> dict: return { "root": str(root.resolve()), + "discovery": discovery, "repo_maturity": repo_maturity, "file_count": len(relevant_files), "doc_count": len(docs), @@ -1111,7 +1224,7 @@ def audit_repo(root: Path) -> dict: "prompt_injection_risks": prompt_injection_risks, "retained_history": retained_history, "dominant_language": _detect_language(language_sources), - "recommended_validation": recommended_checks(root), + "recommended_validation": recommended_checks(root, relevant_files), "instruction_contract": instruction_contract, "archive_indexes": archive_indexes, } diff --git a/plugins/engineering-workflow/skills/engineering-workflow/scripts/repo_audit.py b/plugins/engineering-workflow/skills/engineering-workflow/scripts/repo_audit.py index 294137d..a37291b 100644 --- a/plugins/engineering-workflow/skills/engineering-workflow/scripts/repo_audit.py +++ b/plugins/engineering-workflow/skills/engineering-workflow/scripts/repo_audit.py @@ -2,21 +2,122 @@ from __future__ import annotations import argparse +import hashlib +import json +import os +import tempfile from pathlib import Path from common import audit_repo, print_json -def main() -> int: +def _write_full_report(report: dict, target: Path) -> dict[str, int | str]: + parent = target.parent + if not parent.is_dir(): + raise ValueError(f"Full-report parent directory does not exist: {parent}") + payload = (json.dumps(report, indent=2, sort_keys=True) + "\n").encode("utf-8") + temporary_name = "" + try: + with tempfile.NamedTemporaryFile(prefix=f".{target.name}.", dir=parent, delete=False) as handle: + temporary_name = handle.name + os.chmod(temporary_name, 0o600) + handle.write(payload) + handle.flush() + os.fsync(handle.fileno()) + os.replace(temporary_name, target) + except OSError: + if temporary_name: + Path(temporary_name).unlink(missing_ok=True) + raise + return { + "path": str(target), + "sha256": hashlib.sha256(payload).hexdigest(), + "size_bytes": len(payload), + } + + +def summarize_audit(report: dict, full_report: dict[str, int | str]) -> dict: + failure_categories: list[str] = [] + discovery = report["discovery"] + if discovery["truncated"]: + failure_categories.append("discovery_truncated") + if "git_inventory_failed" in discovery["omission_reasons"]: + failure_categories.append("git_inventory_failed") + if {"unreadable_directory", "unreadable_entry"} & set(discovery["omission_reasons"]): + failure_categories.append("discovery_unreadable") + if report["prompt_injection_risks"]: + failure_categories.append("prompt_injection_risks") + if not report["instruction_contract"]["success"]: + failure_categories.append(f"instruction_contract:{report['instruction_contract']['status']}") + if not report["archive_indexes"]["success"]: + failure_categories.append("archive_indexes") + + represented = { + "repo_maturity", + "file_count", + "doc_count", + "context_docs", + "workflow_artifacts", + "prompt_injection_risks", + "instruction_contract", + "archive_indexes", + "discovery", + } + return { + "status": "attention_required" if failure_categories else "ok", + "repo_maturity": report["repo_maturity"], + "failure_categories": failure_categories, + "counts": { + "files": report["file_count"], + "documents": report["doc_count"], + "workflow_artifacts": len(report["workflow_artifacts"]), + "context_documents": len(report["context_docs"]), + "prompt_injection_risks": len(report["prompt_injection_risks"]), + "instruction_contract_errors": len(report["instruction_contract"]["errors"]), + "archive_index_errors": len(report["archive_indexes"]["errors"]), + }, + "discovery": discovery, + "omissions": { + "details_omitted": True, + "full_report_fields": sorted(set(report) - represented), + "inventory_truncated": discovery["truncated"], + "inventory_omission_reasons": discovery["omission_reasons"], + }, + "full_report": full_report, + } + + +def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="Audit a repository for workflow scaffolding.") parser.add_argument("repo", help="Path to the target repository") - args = parser.parse_args() + parser.add_argument( + "--summary", + action="store_true", + help="Print a compact machine-readable summary; requires --full-report.", + ) + parser.add_argument( + "--full-report", + metavar="PATH", + help="Write the complete JSON report atomically to PATH when --summary is used.", + ) + args = parser.parse_args(argv) + + if args.summary != bool(args.full_report): + parser.error("--summary and --full-report must be used together") repo = Path(args.repo).resolve() if not repo.exists() or not repo.is_dir(): raise SystemExit(f"Repository path does not exist or is not a directory: {repo}") - print_json(audit_repo(repo)) + report = audit_repo(repo) + if args.summary: + try: + full_report = _write_full_report(report, Path(args.full_report)) + except (OSError, ValueError) as exc: + parser.error(str(exc)) + print_json(summarize_audit(report, full_report)) + else: + print_json(report) return 0 diff --git a/plugins/engineering-workflow/skills/engineering-workflow/scripts/upgrade_target_workflow.py b/plugins/engineering-workflow/skills/engineering-workflow/scripts/upgrade_target_workflow.py index cc9040d..969a3f0 100644 --- a/plugins/engineering-workflow/skills/engineering-workflow/scripts/upgrade_target_workflow.py +++ b/plugins/engineering-workflow/skills/engineering-workflow/scripts/upgrade_target_workflow.py @@ -1643,7 +1643,7 @@ def main() -> int: mode.add_argument("--plan", action="store_true") mode.add_argument("--apply", action="store_true") mode.add_argument("--prompt", action="store_true") - parser.add_argument("--target-version", default="0.9.6") + parser.add_argument("--target-version", default="0.9.7") parser.add_argument("--include-agent-config", action="store_true") parser.add_argument( "--approve-privacy-review",