Skip to content
Open
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
62 changes: 62 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: ci

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
name: lint & format (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dev dependencies
run: pip install -e ".[dev]"
- name: ruff check
run: ruff check .
- name: ruff format --check
run: ruff format --check .

test:
name: test (py${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install package (with dev extras)
run: pip install -e ".[dev]"
- name: Run test suite
run: pytest -q
- name: Install optional extras and re-run
run: |
pip install -e ".[dev,lsp,bench,mcp]" || echo "optional extras unavailable; skipping extra run"
pytest -q

consistency:
name: cross-repo consistency (non-blocking)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install package
run: pip install -e ".[dev]"
- name: Check consistency
run: python scripts/check_consistency.py
46 changes: 41 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,57 @@ on:
tags: ["v*"]

permissions:
contents: read
id-token: write # required for PyPI Trusted Publishing (no API token needed)
contents: write # required to create the GitHub Release + upload assets
id-token: write # required for PyPI Trusted Publishing (no API token needed)

jobs:
build-and-publish:
build:
name: build sdist + wheel
runs-on: ubuntu-latest
environment: pypi
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Build distribution
run: |
python -m pip install --upgrade build hatchling
python -m pip install --upgrade build
python -m build
- name: Verify wheel installs in a clean env
run: |
python -m venv /tmp/clean
/tmp/clean/bin/pip install dist/*.whl
/tmp/clean/bin/sin --help >/dev/null
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/*

github-release:
name: attach artifacts to GitHub Release
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: dist/*
generate_release_notes: true

pypi-publish:
name: publish to PyPI (Trusted Publishing)
needs: build
runs-on: ubuntu-latest
environment: pypi
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- **Operational hardening** (closes #8): production-readiness CI/release tooling.
- `.github/workflows/ci.yml`: `ruff check` + `ruff format --check` lint gate
and a `pytest` matrix across Python 3.11/3.12/3.13, plus a non-blocking
cross-repo consistency job.
- `.github/workflows/release.yml`: builds sdist+wheel on `v*` tags, verifies a
clean-env install, attaches artifacts to a GitHub Release, and publishes to
PyPI via Trusted Publishing.
- `scripts/check_consistency.py` (WS4): asserts version alignment, subsystem
import health, and that every `sin mcp-config` client points at the real
`sin serve` entry point. `--strict` mode for full multi-repo CI.
- `scripts/dev_install.sh` + `scripts/run_all_tests.sh` (WS5): two-command
editable bootstrap and aggregated test runner across all 8 sibling repos.
- Adopted a shared `ruff` config (E/F/I/W) and applied a one-shot mechanical
format; aligned `__version__` with the packaged `0.2.0`.
- **GitNexus bridge** (`sin_code_bundle.gitnexus`): integrates the upstream
[GitNexus](https://github.com/abhigyanpatwari/GitNexus) code knowledge graph
as a mandatory, always-on context source for coder agents. GitNexus is
Expand Down
2 changes: 1 addition & 1 deletion docs/plans/operational-hardening.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Plan: Operational Hardening

Status: proposed
Status: implemented (Bundle)
Owner: unassigned
Scope: all 7 SIN-Code repositories (SCKG, IBD, POC, EFSM, ADW, Verification-Oracle, Bundle)

Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,9 @@ testpaths = ["tests"]
[tool.ruff]
line-length = 100
target-version = "py311"
# CoDocs example fixtures demonstrate doc co-location, not runnable code.
extend-exclude = ["examples", "build", "dist"]

[tool.ruff.lint]
select = ["E", "F", "I", "W"]
ignore = ["E501"]
152 changes: 152 additions & 0 deletions scripts/check_consistency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""Cross-repo consistency check for the SIN-Code Bundle (WS4 of operational-hardening).

The Bundle orchestrates 8 sibling subsystems that are installed via local
``pip install -e`` of adjacent repos. This script asserts that the Bundle's
own expectations stay internally consistent and reports drift against any
subsystems that happen to be installed.

Design goals:
- Exit 0 on a clean *bundle-only* checkout (subsystems absent -> warnings, not
failures), so it is safe to wire into CI as a non-blocking job first.
- Promote ``--strict`` to make any missing subsystem or mismatch fail (exit 1),
for use once the full multi-repo environment is provisioned.

Checks performed:
1. Bundle metadata: ``pyproject`` version == ``__init__.__version__``.
2. Subsystem import specs: each subsystem the ``status`` command probes either
imports cleanly or is reported as not-installed.
3. MCP advertising: every client config emitted by ``sin mcp-config`` points at
the same ``sin serve`` entry point that the package actually registers.
"""

from __future__ import annotations

import argparse
import importlib.metadata as md
import importlib.util
import sys
import tomllib
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parent.parent

# Canonical subsystem map -- kept in sync with cli.status().
SUBSYSTEMS = {
"sin_code_sckg": "SCKG (knowledge graph)",
"sin_code_ibd": "IBD (intent diff)",
"sin_code_poc": "POC (proof of correctness)",
"sin_code_efsm": "EFSM (mock orchestration)",
"sin_code_adw": "ADW (debt watchdog)",
"sin_code_oracle": "Oracle (verification)",
"sin_code_orchestration": "Orchestration (multi-agent workflow)",
"sin_code_review_interface": "Review-Interface (semantic review UI)",
}

GREEN, YELLOW, RED, RESET = "\033[32m", "\033[33m", "\033[31m", "\033[0m"


def _ok(msg: str) -> None:
print(f"{GREEN}OK{RESET} {msg}")


def _warn(msg: str) -> None:
print(f"{YELLOW}WARN{RESET} {msg}")


def _fail(msg: str) -> None:
print(f"{RED}FAIL{RESET} {msg}")


def check_version() -> list[str]:
errors: list[str] = []
pyproject = tomllib.loads((REPO_ROOT / "pyproject.toml").read_text())
declared = pyproject["project"]["version"]
init_text = (REPO_ROOT / "src" / "sin_code_bundle" / "__init__.py").read_text()
runtime = next(
(
line.split("=", 1)[1].strip().strip('"').strip("'")
for line in init_text.splitlines()
if line.startswith("__version__")
),
None,
)
if runtime == declared:
_ok(f"version aligned: pyproject == __init__ == {declared}")
else:
_fail(f"version drift: pyproject={declared!r} but __init__={runtime!r}")
errors.append("version drift")
return errors


def check_subsystems(strict: bool) -> list[str]:
errors: list[str] = []
for module, desc in SUBSYSTEMS.items():
installed = importlib.util.find_spec(module) is not None
if installed:
try:
version = md.version(module.replace("_", "-"))
except md.PackageNotFoundError:
version = "unknown"
_ok(f"{desc}: importable (v{version})")
elif strict:
_fail(f"{desc}: module '{module}' not installed (strict)")
errors.append(f"{module} missing")
else:
_warn(f"{desc}: module '{module}' not installed (expected in bundle-only checkout)")
return errors


def check_mcp_advertising() -> list[str]:
errors: list[str] = []
from sin_code_bundle import mcp_config

expected_cmd, expected_args = mcp_config.COMMAND, mcp_config.ARGS
if (expected_cmd, expected_args) != ("sin", ["serve"]):
_fail(f"mcp entry point unexpected: {expected_cmd} {expected_args}")
errors.append("mcp entry point")
return errors

# The package must actually expose the `sin` console script the configs point at.
scripts = {ep.name: ep.value for ep in md.entry_points(group="console_scripts")}
if scripts.get("sin", "").startswith("sin_code_bundle.cli"):
_ok("'sin' console script resolves to sin_code_bundle.cli")
else:
_fail(f"'sin' console script missing or wrong: {scripts.get('sin')!r}")
errors.append("console script")

for client in mcp_config.SUPPORTED_CLIENTS:
rendered = mcp_config.generate(client)
if expected_cmd in rendered and "serve" in rendered:
_ok(f"mcp-config[{client}] advertises '{expected_cmd} serve'")
else:
_fail(f"mcp-config[{client}] does not advertise the serve entry point")
errors.append(f"mcp-config {client}")
return errors


def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--strict",
action="store_true",
help="Treat missing subsystems as failures (full multi-repo env).",
)
args = parser.parse_args()

print("== SIN-Code Bundle consistency check ==")
errors: list[str] = []
errors += check_version()
errors += check_subsystems(args.strict)
errors += check_mcp_advertising()

print()
if errors:
_fail(f"{len(errors)} consistency problem(s): {', '.join(errors)}")
return 1
_ok("all consistency checks passed")
return 0


if __name__ == "__main__":
sys.exit(main())
47 changes: 47 additions & 0 deletions scripts/dev_install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# WS5: one-command editable dev setup for the full SIN-Code stack.
#
# Clones (if missing) and `pip install -e` each sibling subsystem next to this
# repo, then installs the Bundle itself with dev extras. Run from anywhere.
#
# ./scripts/dev_install.sh # clone missing repos + editable install
# SIN_NO_CLONE=1 ./scripts/dev_install.sh # only install repos already present
set -euo pipefail

BUNDLE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
WORKSPACE="$(cd "${BUNDLE_DIR}/.." && pwd)"
ORG="https://github.com/OpenSIN-Code"

# Sibling repos in install order (dependencies before the bundle).
REPOS=(
"SIN-Code-Semantic-Codebase-Knowledge-Graphs"
"SIN-Code-Intent-Based-Diffing"
"SIN-Code-Proof-of-Correctness"
"SIN-Code-Ephemeral-Full-Stack-Mocking-Orchestration"
"SIN-Code-Architectural-Debt-Watchdogs"
"SIN-Code-Verification-Oracle"
"SIN-Code-Orchestration"
"SIN-Code-Review-Interface"
)

echo "== SIN-Code dev install =="
echo "workspace: ${WORKSPACE}"

for repo in "${REPOS[@]}"; do
path="${WORKSPACE}/${repo}"
if [[ ! -d "${path}" ]]; then
if [[ "${SIN_NO_CLONE:-0}" == "1" ]]; then
echo "SKIP ${repo} (not present; SIN_NO_CLONE=1)"
continue
fi
echo "CLONE ${repo}"
git clone --depth 1 "${ORG}/${repo}.git" "${path}"
fi
echo "INSTALL ${repo}"
pip install -e "${path}"
done

echo "INSTALL SIN-Code-Bundle [dev]"
pip install -e "${BUNDLE_DIR}[dev]"

echo "== done. run 'sin status' to verify subsystems =="
Loading
Loading