Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude/skills/scripts-architecture/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ description: Architecture scripts — import analysis, violation detection, code
## Rules

- Architecture scripts must not modify code without explicit `--fix` or `--apply` flag.
- Analysis output must go to `.sisyphus/reports/` using artifact naming contract.
- Analysis output must go to `.reports/` using artifact naming contract.
- Standard quality gates run via Make verbs (`make check`, `make validate`); architecture scripts are implementation details behind Make.
- Cross-project tests run via `make test` (or `make test FAIL_FAST=1` to stop on first failure).

Expand Down Expand Up @@ -94,7 +94,7 @@ Why good: Canonical Make contract, consistent with CLAUDE.md.
Good (internal — architecture analysis scripts behind Make):

```bash
python scripts/architecture/analyze_violations.py --output .sisyphus/reports/scripts-architecture--json--violations-latest.json
python scripts/architecture/analyze_violations.py --output .reports/scripts-architecture--json--violations-latest.json
```

Why acceptable: Direct script invocation for detailed architecture analysis. Make verbs are the recommended workflow for standard gates.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/scripts-dependencies/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ make check PROJECT=flext-core # verify after dependency changes
Good (internal — dependency analysis scripts):

```bash
python scripts/dependencies/analyze_dependencies.py --output .sisyphus/reports/scripts-dependencies--json--analysis-latest.json
python scripts/dependencies/analyze_dependencies.py --output .reports/scripts-dependencies--json--analysis-latest.json
```

Why good: Make verbs for standard workflow; artifact naming and structured output for detailed analysis.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/scripts-infra/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Why good: Uses shared lib for artifact naming, deterministic path construction.
Bad:

```bash
REPORT=".sisyphus/reports/my_report.json"
REPORT=".reports/my_report.json"
```

Why bad: Hardcoded path bypasses artifact naming contract.
Expand Down
30 changes: 15 additions & 15 deletions .claude/skills/scripts-infra/validate_artifact_naming.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# Owner-Skill: .claude/skills/scripts-infra/SKILL.md
"""Validate script-generated artifact naming under .sisyphus/."""
"""Validate script-generated artifact naming under .reports/."""

from __future__ import annotations

Expand All @@ -17,8 +17,8 @@
EXIT_INFRA = 3

ARTIFACT_PATTERN = re.compile(r"^[a-z][-a-z0-9]*--[a-z]+--[a-z][-a-z0-9]*\.[a-z]+$")
VALIDATED_TOP_DIRS = {"reports", "baselines"}
SKIPPED_TOP_DIRS = {"evidence", "plans", "drafts"}
VALIDATED_TOP_DIRS = {"."}
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 20, 2026

Choose a reason for hiding this comment

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

P1: VALIDATED_TOP_DIRS = {"."} can never match: Path.relative_to() never yields "." as a path component, so return top_dir in VALIDATED_TOP_DIRS is always False for files in subdirectories. Any artifact in a non-skipped subdirectory of .reports/ will be silently excluded from validation.

If the intent is to validate all non-skipped subdirectories, the final return should be return True. If only root-level files should be validated, the VALIDATED_TOP_DIRS constant and final return are dead code and should be removed for clarity.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .claude/skills/scripts-infra/validate_artifact_naming.py, line 20:

<comment>`VALIDATED_TOP_DIRS = {"."}` can never match: `Path.relative_to()` never yields `"."` as a path component, so `return top_dir in VALIDATED_TOP_DIRS` is always `False` for files in subdirectories. Any artifact in a non-skipped subdirectory of `.reports/` will be silently excluded from validation.

If the intent is to validate all non-skipped subdirectories, the final return should be `return True`. If only root-level files should be validated, the `VALIDATED_TOP_DIRS` constant and final `return` are dead code and should be removed for clarity.</comment>

<file context>
@@ -17,8 +17,8 @@
 ARTIFACT_PATTERN = re.compile(r"^[a-z][-a-z0-9]*--[a-z]+--[a-z][-a-z0-9]*\.[a-z]+$")
-VALIDATED_TOP_DIRS = {"reports", "baselines"}
-SKIPPED_TOP_DIRS = {"evidence", "plans", "drafts"}
+VALIDATED_TOP_DIRS = {"."}
+SKIPPED_TOP_DIRS = {"evidence", "plans", "drafts", "validation", "dependencies"}
 SKIPPED_FILES = {".gitkeep"}
</file context>
Fix with Cubic

SKIPPED_TOP_DIRS = {"evidence", "plans", "drafts", "validation", "dependencies"}
SKIPPED_FILES = {".gitkeep"}


Expand Down Expand Up @@ -53,7 +53,7 @@ def validate_artifact_name(filename: str) -> bool:
def parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Validate .sisyphus artifact files follow "
"Validate .reports artifact files follow "
"<skill>--<kind>--<slug>.<ext> naming contract."
),
)
Expand All @@ -74,33 +74,33 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
raise UsageError(msg) from exc


def should_validate(path: Path, sisyphus_root: Path) -> bool:
def should_validate(path: Path, reports_root: Path) -> bool:
if not path.is_file():
return False
if path.name in SKIPPED_FILES:
return False

try:
relative = path.relative_to(sisyphus_root)
relative = path.relative_to(reports_root)
except ValueError:
return False

if not relative.parts:
return False

if len(relative.parts) == 1:
return True
top_dir = relative.parts[0]
if top_dir in SKIPPED_TOP_DIRS:
return False
return top_dir in VALIDATED_TOP_DIRS


def collect_artifacts(sisyphus_root: Path) -> list[Path]:
if not sisyphus_root.exists():
def collect_artifacts(reports_root: Path) -> list[Path]:
if not reports_root.exists():
return []
return sorted(
path
for path in sisyphus_root.rglob("*")
if should_validate(path, sisyphus_root)
path for path in reports_root.rglob("*") if should_validate(path, reports_root)
)


Expand Down Expand Up @@ -130,9 +130,9 @@ def suggest_filename(filename: str) -> str:
def validate(
*,
repo_root: Path,
sisyphus_root: Path,
reports_root: Path,
) -> list[NamingViolation]:
artifacts = collect_artifacts(sisyphus_root)
artifacts = collect_artifacts(reports_root)
violations: list[NamingViolation] = []

eprint("Artifact Naming Validation")
Expand Down Expand Up @@ -200,10 +200,10 @@ def run_main(argv: list[str]) -> int:
msg = f"--root must point to an existing directory: {repo_root}"
raise UsageError(msg)

sisyphus_root = repo_root / ".sisyphus"
reports_root = repo_root / ".reports"
report_path = repo_root / ".claude" / "skills" / "scripts-infra" / "report.json"

violations = validate(repo_root=repo_root, sisyphus_root=sisyphus_root)
violations = validate(repo_root=repo_root, reports_root=reports_root)
violation_count = len(violations)
write_report(report_path, violations)
eprint(f"Violations report: {report_path}")
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/scripts-infra/validate_gate_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
r"^# Owner-Skill:\s+(.claude/skills/[a-z0-9][-a-z0-9]*/SKILL\.md)\s*$"
)
ARTIFACT_NAME_RE = re.compile(r"[a-z][-a-z0-9]*--[a-z]+--[a-z][-a-z0-9]*\.[a-z]+")
SISYPHUS_PATH_RE = re.compile(r"\.sisyphus/(?:reports|baselines|evidence)/([^\s\"']+)")
REPORTS_PATH_RE = re.compile(r"\.reports/([^\s\"']+)")
BASH_EXIT_RE = re.compile(r"^\s*exit\s+(\d+)")
INTERACTIVE_PY_RE = re.compile(r"\binput\s*\(")
INTERACTIVE_SH_RE = re.compile(
Expand Down Expand Up @@ -259,7 +259,7 @@ def check_interactive(
def check_artifact_naming(content: str) -> list[Violation]:
violations: list[Violation] = []
for i, line in enumerate(content.splitlines(), 1):
for match in SISYPHUS_PATH_RE.finditer(line):
for match in REPORTS_PATH_RE.finditer(line):
filename = Path(match.group(1)).name
if "$" in filename or "*" in filename or "{" in filename:
continue
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/scripts-security/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ description: Security scripts — secrets management, vault operations, and secu
- Security scripts must never log or print secrets to stdout/stderr.
- All scripts must be non-interactive by default; interactive prompts require `--interactive` flag.
- Secrets must be read from environment variables or encrypted vaults, never hardcoded.
- Security audit output must go to `.sisyphus/reports/` using artifact naming contract.
- Security audit output must go to `.reports/` using artifact naming contract.

## Instructions

Expand Down Expand Up @@ -65,7 +65,7 @@ make check PROJECT=flext-core # all 4 gates including sec
Good (internal — security audit scripts):

```bash
python scripts/security/security_audit.py --output .sisyphus/reports/scripts-security--json--audit-latest.json
python scripts/security/security_audit.py --output .reports/scripts-security--json--audit-latest.json
```

Why good: Make verbs for standard security gates; artifact naming for detailed audits.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/scripts-testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ description: Testing scripts — pytest runners, test analysis, quality gates, s
## Rules

- Test runners must support `--help` and be runnable from repo root.
- Test output must go to stdout; structured reports to `.sisyphus/reports/` via artifact naming.
- Test output must go to stdout; structured reports to `.reports/` via artifact naming.
- Stress tests and distributed tests must be explicitly opt-in (not part of quick validation).

## Instructions
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/workspace-maintenance/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ description: Workspace-wide maintenance automation — hygiene checks, dependabo
- All checks must be idempotent and safe by default (read-only unless `--apply`).
- Mutations (cleanup, lock updates) require explicit `--apply` flag.
- Scripts must discover `flext-*` projects with `pyproject.toml` for workspace iteration.
- Reports output to `.sisyphus/reports/workspace-maintenance--json--<slug>.json`.
- Reports output to `.reports/workspace-maintenance--json--<slug>.json`.
- Exit 0 = all checks pass, exit 1 = violations found.
- Each script must be standalone (stdlib + PyYAML only, no flext_core imports).

Expand All @@ -49,7 +49,7 @@ description: Workspace-wide maintenance automation — hygiene checks, dependabo
1. Identify the maintenance concern (hygiene, dependabot, poetry, security).
2. Run standard gates first: `make check` and `make validate`.
3. Run specific maintenance checker with `--help` first, then default (dry-run) mode.
4. Review the JSON report in `.sisyphus/reports/` or the ANSI terminal output.
4. Review the JSON report in `.reports/` or the ANSI terminal output.
5. If fixes are needed, re-run with `--apply` to mutate state.
6. Verify: `make validate VALIDATE_SCOPE=workspace` for workspace-level inventory.

Expand Down
60 changes: 60 additions & 0 deletions .github/ci-template/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: CI

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
ci:
name: ci
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.24"

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: false
installer-parallel: true

- name: Install workflow tools
shell: bash
run: |
set -euo pipefail
npm install -g markdownlint-cli
go install github.com/securego/gosec/v2/cmd/gosec@latest
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

- name: Setup
run: make setup

- name: Check
run: make check

- name: Test
run: make test
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
ci:
name: ci
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5

- name: Setup Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: "3.13"

- name: Install Poetry
uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a
with:
virtualenvs-create: false
installer-parallel: true

- name: Setup (advisory)
continue-on-error: true
run: make setup

- name: Check (advisory)
continue-on-error: true
run: make check

- name: Test (advisory)
continue-on-error: true
run: make test

- name: Validate (advisory)
continue-on-error: true
run: make validate
Loading
Loading