Skip to content
Closed
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 .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: Bug report
about: Report a defect in civiccore
about: Report a defect in townlight_core
title: "[bug] "
labels: ["bug"]
---
Expand All @@ -19,7 +19,7 @@ labels: ["bug"]
<!-- Include error messages, stack traces, log output. -->

**Environment**
- civiccore version (`python -c "import civiccore; print(civiccore.__version__)"`):
- townlight_core version (`python -c "import townlight_core; print(townlight_core.__version__)"`):
- Python version:
- Consuming application (records-ai, custom, evaluation):
- Postgres version (if migration-related):
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ labels: ["documentation"]
**Audience this affects**
- [ ] Module developer / IT integrator
- [ ] Consuming application (records-ai, future modules)
- [ ] Evaluator (deciding whether to use civiccore)
- [ ] Evaluator (deciding whether to use townlight_core)
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: Feature request
about: Suggest an enhancement to civiccore
about: Suggest an enhancement to townlight_core
title: "[feat] "
labels: ["enhancement"]
---
Expand All @@ -14,6 +14,6 @@ labels: ["enhancement"]
**Alternatives considered**

**Scope check**
<!-- Does this fit civiccore's role as a shared platform library, or does it belong in a consumer module? -->
<!-- Does this fit townlight_core's role as a shared platform library, or does it belong in a consumer module? -->

**Additional context**
6 changes: 3 additions & 3 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
## Test plan

- [ ] `python -m pytest -q` passes
- [ ] `python -m ruff check civiccore tests` passes
- [ ] `python -m ruff check townlight_core tests` passes
- [ ] If touching migrations: idempotency tests pass and Gate 1/2/3 logic still holds for downstream consumers
- [ ] If touching public API in `civiccore.llm`: smoke test verifies symbols still importable
- [ ] If touching public API in `townlight_core.llm`: smoke test verifies symbols still importable

## Checklist

- [ ] CHANGELOG.md updated under `[Unreleased]`
- [ ] If version bumped: pyproject.toml, civiccore/__init__.py, scripts/verify-release.sh fresh-venv asserts all aligned
- [ ] If version bumped: pyproject.toml, townlight_core/__init__.py, scripts/verify-release.sh fresh-venv asserts all aligned
- [ ] No secrets committed
- [ ] Linked issue: <!-- #N -->
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: civiccore CI
name: townlight-core CI

on:
pull_request:
Expand All @@ -25,7 +25,7 @@ jobs:
- name: Pre-pull pgvector image
run: docker pull pgvector/pgvector:pg17

- name: Install civiccore (editable, dev extras)
- name: Install townlight-core (editable, dev extras)
run: |
pip install --upgrade pip
pip install -e .[dev]
Expand Down Expand Up @@ -106,5 +106,5 @@ jobs:

- name: Accessibility gate (no browser surface)
run: |
echo "CivicCore exposes shared backend contracts and has no operator-facing browser surface in this repo."
echo "Per-PR axe gates run in CivicRecords AI, CivicClerk, CivicCode, and the CivicSuite launcher."
echo "Townlight Core exposes shared backend contracts and has no operator-facing browser surface in this repo."
echo "Per-PR axe gates run in CivicRecords AI, CivicClerk, CivicCode, and the Townlight launcher."
12 changes: 6 additions & 6 deletions .github/workflows/cleanroom.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: civiccore cleanroom
name: townlight-core cleanroom

on:
pull_request:
Expand All @@ -7,8 +7,8 @@ on:
- ".github/workflows/cleanroom.yml"
- "cleanroom/**"
- "scripts/cleanroom/**"
- "scripts/run-civiccore-cleanroom.sh"
- "civiccore/release_provenance.py"
- "scripts/run-townlight-core-cleanroom.sh"
- "townlight_core/release_provenance.py"
- "tests/fixtures/release_provenance/**"
- "tests/test_cleanroom_harness.py"
- "docs/ops/cleanroom-harness.md"
Expand Down Expand Up @@ -36,10 +36,10 @@ jobs:
fetch-depth: 0
- name: Verify Docker is available
run: docker version
- name: Run CivicCore cleanroom harness
run: bash scripts/run-civiccore-cleanroom.sh "$TARGET_COMMIT" "docs/evidence/co6-ci-${TARGET_COMMIT}"
- name: Run Townlight Core cleanroom harness
run: bash scripts/run-townlight-core-cleanroom.sh "$TARGET_COMMIT" "docs/evidence/co6-ci-${TARGET_COMMIT}"
- name: Upload cleanroom evidence
uses: actions/upload-artifact@v7
with:
name: civiccore-co6-cleanroom-${{ env.TARGET_COMMIT }}
name: townlight-core-co6-cleanroom-${{ env.TARGET_COMMIT }}
path: docs/evidence/co6-ci-${{ env.TARGET_COMMIT }}/
76 changes: 38 additions & 38 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
tags:
- "v*"
- "civiccore-*-freeze"
- "townlight-core-*-freeze"
workflow_dispatch:
inputs:
release_tag:
Expand Down Expand Up @@ -33,7 +33,7 @@ jobs:
with:
python-version: "3.13"

- name: Cleanroom cache strip (scoped, CivicSuite-only)
- name: Cleanroom cache strip (scoped, Townlight-only)
shell: bash
run: |
python - <<'PY'
Expand All @@ -44,33 +44,33 @@ jobs:
for rel in (".npm", ".cache/pip"):
shutil.rmtree(os.path.join(runner_temp, rel), ignore_errors=True)
PY
docker builder prune --all --force --filter "label=civicsuite-cleanroom=1" || true
docker network ls --filter "label=civicsuite-cleanroom=1" -q \
docker builder prune --all --force --filter "label=townlight-cleanroom=1" || true
docker network ls --filter "label=townlight-cleanroom=1" -q \
| xargs -r docker network rm || true
docker volume ls --filter "label=civicsuite-cleanroom=1" -q \
docker volume ls --filter "label=townlight-cleanroom=1" -q \
| xargs -r docker volume rm || true

- name: Install published wheel from release URL
shell: bash
run: |
TAG="${{ inputs.release_tag }}"
VERSION="${TAG#v}"
WHEEL_URL="https://github.com/CivicSuite/civiccore/releases/download/${TAG}/civiccore-${VERSION}-py3-none-any.whl"
WHEEL_URL="https://github.com/townlight/core/releases/download/${TAG}/townlight_core-${VERSION}-py3-none-any.whl"
echo "Cleanroom wheel URL: ${WHEEL_URL}"
python -m venv .cleanroom-venv
. .cleanroom-venv/bin/activate
python -m pip install --upgrade pip
python -m pip install --no-cache-dir --force-reinstall "${WHEEL_URL}"
TESTING=1 python - <<PY
import civiccore
from civiccore.ingest import Document, DocumentChunk, compute_file_hash, ingest_file, ingest_bytes, register_handler
import townlight_core
from townlight_core.ingest import Document, DocumentChunk, compute_file_hash, ingest_file, ingest_bytes, register_handler

expected = "${VERSION}"
print(f"civiccore.__version__={civiccore.__version__}")
if civiccore.__version__ != expected:
raise SystemExit(f"Expected CivicCore {expected}, got {civiccore.__version__}")
print(f"townlight_core.__version__={townlight_core.__version__}")
if townlight_core.__version__ != expected:
raise SystemExit(f"Expected Townlight Core {expected}, got {townlight_core.__version__}")
print(
"civiccore ingest import ok: "
"townlight_core ingest import ok: "
f"{Document.__name__}, {DocumentChunk.__name__}, {compute_file_hash.__name__}, "
f"{ingest_file.__name__}, {ingest_bytes.__name__}, {register_handler.__name__}"
)
Expand All @@ -80,10 +80,10 @@ jobs:
if: always()
shell: bash
run: |
docker compose -p civicsuite-cleanroom-${{ github.run_id }} down -v --remove-orphans || true
docker ps -a --filter "label=civicsuite-cleanroom=1" -q \
docker compose -p townlight-cleanroom-${{ github.run_id }} down -v --remove-orphans || true
docker ps -a --filter "label=townlight-cleanroom=1" -q \
| xargs -r docker container rm --force || true
docker network ls --filter "label=civicsuite-cleanroom=1" -q \
docker network ls --filter "label=townlight-cleanroom=1" -q \
| xargs -r docker network rm || true

preflight:
Expand Down Expand Up @@ -193,7 +193,7 @@ jobs:
- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
name: civiccore-dist
name: townlight-core-dist
path: |
dist/*
release-attestation.json
Expand All @@ -207,7 +207,7 @@ jobs:
steps:
- uses: actions/download-artifact@v8
with:
name: civiccore-dist
name: townlight-core-dist
path: release-assets/

- name: Create draft GitHub release with wheel + sdist
Expand All @@ -217,16 +217,16 @@ jobs:
run: |
latest_flag=()
case "${{ github.ref_name }}" in
civiccore-*-freeze) latest_flag=(--latest=false) ;;
townlight-core-*-freeze) latest_flag=(--latest=false) ;;
esac
export VERSION="${GITHUB_REF_NAME#v}"
export REPO="${GITHUB_REPOSITORY}"
export TAG="${GITHUB_REF_NAME}"
export WORKFLOW_RUN_ID="${GITHUB_RUN_ID}"
export WHEEL_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/civiccore-${VERSION}-py3-none-any.whl"
export WHEEL_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/townlight_core-${VERSION}-py3-none-any.whl"
export CLEANROOM_TIMESTAMP="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
cat > release-notes.md <<EOF
CivicCore ${TAG} release.
Townlight Core ${TAG} release.

Cleanroom rehearsal: PASSED in workflow run ${WORKFLOW_RUN_ID}.
Verified clean install of ${WHEEL_URL} from cold caches at ${CLEANROOM_TIMESTAMP}.
Expand Down Expand Up @@ -260,7 +260,7 @@ jobs:
release-assets/release-attestation.json \
release-assets/release-attestation.json.bundle \
--repo "$GH_REPO" \
--title "civiccore ${{ github.ref_name }}" \
--title "townlight-core ${{ github.ref_name }}" \
"${latest_flag[@]}" \
--notes-file release-notes.md

Expand All @@ -281,7 +281,7 @@ jobs:
with:
python-version: "3.13"

- name: Cleanroom cache strip (scoped, CivicSuite-only)
- name: Cleanroom cache strip (scoped, Townlight-only)
shell: bash
run: |
python - <<'PY'
Expand All @@ -292,10 +292,10 @@ jobs:
for rel in (".npm", ".cache/pip"):
shutil.rmtree(os.path.join(runner_temp, rel), ignore_errors=True)
PY
docker builder prune --all --force --filter "label=civicsuite-cleanroom=1" || true
docker network ls --filter "label=civicsuite-cleanroom=1" -q \
docker builder prune --all --force --filter "label=townlight-cleanroom=1" || true
docker network ls --filter "label=townlight-cleanroom=1" -q \
| xargs -r docker network rm || true
docker volume ls --filter "label=civicsuite-cleanroom=1" -q \
docker volume ls --filter "label=townlight-cleanroom=1" -q \
| xargs -r docker volume rm || true

- name: Download uploaded wheel from draft release
Expand All @@ -306,17 +306,17 @@ jobs:
mkdir -p .cleanroom-assets
gh release download "${{ github.ref_name }}" \
--repo "${{ github.repository }}" \
--pattern 'civiccore-*-py3-none-any.whl' \
--pattern 'townlight_core-*-py3-none-any.whl' \
--dir .cleanroom-assets
find .cleanroom-assets -maxdepth 1 -type f -print

- name: Install uploaded wheel in cleanroom venv
shell: bash
run: |
VERSION="${GITHUB_REF_NAME#v}"
WHEEL="$(find .cleanroom-assets -name 'civiccore-*-py3-none-any.whl' -type f | head -1)"
WHEEL="$(find .cleanroom-assets -name 'townlight_core-*-py3-none-any.whl' -type f | head -1)"
if [ -z "$WHEEL" ]; then
echo "::error::No CivicCore wheel downloaded from draft release."
echo "::error::No Townlight Core wheel downloaded from draft release."
exit 1
fi
echo "Cleanroom wheel asset: ${WHEEL}"
Expand All @@ -325,15 +325,15 @@ jobs:
python -m pip install --upgrade pip
python -m pip install --no-cache-dir --force-reinstall "${WHEEL}"
TESTING=1 python - <<PY
import civiccore
from civiccore.ingest import Document, DocumentChunk, compute_file_hash, ingest_file, ingest_bytes, register_handler
import townlight_core
from townlight_core.ingest import Document, DocumentChunk, compute_file_hash, ingest_file, ingest_bytes, register_handler

expected = "${VERSION}"
print(f"civiccore.__version__={civiccore.__version__}")
if civiccore.__version__ != expected:
raise SystemExit(f"Expected CivicCore {expected}, got {civiccore.__version__}")
print(f"townlight_core.__version__={townlight_core.__version__}")
if townlight_core.__version__ != expected:
raise SystemExit(f"Expected Townlight Core {expected}, got {townlight_core.__version__}")
print(
"civiccore ingest import ok: "
"townlight_core ingest import ok: "
f"{Document.__name__}, {DocumentChunk.__name__}, {compute_file_hash.__name__}, "
f"{ingest_file.__name__}, {ingest_bytes.__name__}, {register_handler.__name__}"
)
Expand All @@ -343,10 +343,10 @@ jobs:
if: always()
shell: bash
run: |
docker compose -p civicsuite-cleanroom-${{ github.run_id }} down -v --remove-orphans || true
docker ps -a --filter "label=civicsuite-cleanroom=1" -q \
docker compose -p townlight-cleanroom-${{ github.run_id }} down -v --remove-orphans || true
docker ps -a --filter "label=townlight-cleanroom=1" -q \
| xargs -r docker container rm --force || true
docker network ls --filter "label=civicsuite-cleanroom=1" -q \
docker network ls --filter "label=townlight-cleanroom=1" -q \
| xargs -r docker network rm || true

publish-release:
Expand All @@ -362,7 +362,7 @@ jobs:
run: |
latest_flag=()
case "${{ github.ref_name }}" in
civiccore-*-freeze) latest_flag=(--latest=false) ;;
townlight-core-*-freeze) latest_flag=(--latest=false) ;;
esac
gh release edit "${{ github.ref_name }}" \
--repo "$GH_REPO" \
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ env/
ENV/
.python-version

# Node (for civiccore-ui/)
# Node (for townlight-core-ui/)
node_modules/
npm-debug.log*
yarn-debug.log*
Expand Down
2 changes: 1 addition & 1 deletion .pipelines/module-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# Use when:
# - Bumping a module to a new version
# - Releasing a downstream-dependency change (e.g. civiccore pin sweep)
# - Releasing a downstream-dependency change (e.g. townlight_core pin sweep)
# - Any work whose end-state is a published release artifact
#
# DO NOT use for:
Expand Down
6 changes: 3 additions & 3 deletions .pipelines/self-classification-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Every line returned by a release-sweep grep gets exactly ONE classification:
- `.github/workflows/*.yml` lines that pip-install a versioned URL
- `README.md`, `USER-MANUAL.md`, install-instruction snippets describing current state
- Test files asserting current pin URL or current version constant
- Test fixture dicts like `{"civiccore": "1.0.0"}` (update value to new version)
- Test fixture dicts like `{"townlight_core": "1.0.0"}` (update value to new version)
- Compatibility matrix entries describing current pin
- Source files with `EXPECTED_<DEP>_VERSION = "X.Y.Z"` constants

Expand All @@ -34,7 +34,7 @@ A grep hit is SHAPE-GUARD when ALL of these hold:
- Updating X to the new version would pass trivially with no real coverage

Examples:
- `assert "civiccore==1.0.0" not in dependencies` - asserts no `==` pinning, version-independent
- `assert "townlight_core==1.0.0" not in dependencies` - asserts no `==` pinning, version-independent
- `assert "1.0.0.dev0" not in text` - asserts no stale dev marker, version-unrelated

### OWN-MODULE-VERSION - SKIP (do not edit during a dependency-bump sweep)
Expand Down Expand Up @@ -72,7 +72,7 @@ The fix-forward bound is: changes must touch only `.github/workflows/`, `scripts
### CONTRACT-CHANGE - HALT AND REPORT

- Any source code change required
- Any test asserting on dependency-removed behavior (e.g., civicclerk tests asserting on civiccore-removed `token_roles` field) - the auditor must approve the test update before the agent applies it
- Any test asserting on dependency-removed behavior (e.g., civicclerk tests asserting on townlight_core-removed `token_roles` field) - the auditor must approve the test update before the agent applies it
- Any cross-module dependency conflict
- Any failure whose root cause requires a design decision

Expand Down
Loading
Loading