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
9 changes: 9 additions & 0 deletions .claude/context/gemini_rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,17 @@ Claude reads the git diff and generates the PR title, commit message, and body
* **Logging Mandate:** Every architecture MD file must contain a `## Logs` section at the bottom. Claude appends a dated entry to this section after completing implementation, recording what was built and any non-obvious decisions made.
* **Framework Session Isolation Flag:** Any section that introduces a framework-level component that manages its own database session internally (e.g., auth backends, admin panels, seed functions, middleware) must include an explicit note in its Testing subsection. The note must flag that this component bypasses the standard transactional rollback fixture in `conftest.py` and that integration tests must use explicit row cleanup or full mocking. Omitting this flag is a common source of test pollution across the test session.
* **Package Versioning:** Gemini should describe new packages/tools by the desired capability or behavior they provide, not exact pinned versions — Claude resolves and verifies exact versions at `runPrompt` time (via `uv lock`, `pre-commit` hook installation, or equivalent), since only the implementer has live tooling access to confirm compatibility. A guessed pin from an architect with no live verification is a real failure mode, not a theoretical one — doc 23's `opentelemetry-instrumentation` pin broke against `setuptools` in exactly this way. Exception: if Gemini is aware of a specific cross-package compatibility constraint (e.g., two packages must be from the same release line), state that constraint explicitly rather than expressing it as a literal version string.
* **Spatial Indexing (Q3C):** Any table with its own RA/Dec columns representing a queryable sky coordinate must declare a real Q3C functional index in its SQLAlchemy model (`Index("ix_<table>_q3c", text("q3c_ang2ipix(ra, decl)"))` in `__table_args__`), not just create it via raw migration SQL. Only the `CREATE EXTENSION IF NOT EXISTS q3c` step has no ORM equivalent and must stay as hand-authored SQL in the migration, ordered before the index. Doing the whole thing as raw SQL (index included) creates a permanent mismatch between the model and the live schema that autogenerate can't resolve without a standing exclusion hack.
* **Spatial Footprint (MOC) Placement:** Any entity with a real spatial footprint (not just a point) must carry a MOC-representable field (`moc_str` today; migrating toward a native HealpixAlchemy range type is tracked separately). For an entity with a raw/derived split — an immutable ingest record vs. our processed reference to it — the footprint field belongs on the derived side, both to protect the raw record's immutability (footprint computation can be revisited; the raw ingest shouldn't be) and because the derived entity is what actually participates in downstream spatial joins/associations.
* **Backlog-Sourced Revisions:** A revision prompt item may sometimes originate from Claude's `assessPrompt` cross-referencing the open tech-debt/enhancement backlog against a draft's scope, rather than from a gap in the draft itself. These are explicitly labeled in the prompt (e.g., "per backlog issue #N"). Treat these as intentional, pre-existing concerns being folded in now — not as feedback on drafting quality — since the change may otherwise look discontinuous with the rest of a normal refinement pass.

## Logs
###### 2026-07-22 — Backlog cross-reference added to assessPrompt
Added a Backlog Cross-Reference step to `assess_arch.md`: before running the §A–§G checklist, Claude now does a best-effort pass over open `tech-debt`/`enhancement` GitHub Issues to flag any that touch what the doc under review is actually creating or modifying, surfacing them as Decision Required items rather than folding them in silently. Explicitly scoped as best-effort, not exhaustive, since the backlog grows monotonically and the user separately reviews it directly as a backstop. Added the corresponding Backlog-Sourced Revisions guiding principle here so Gemini has context when a revision prompt item traces back to a pre-existing backlog issue instead of a gap in its own draft.

###### 2026-07-22 — Spatial modeling conventions added
Added Spatial Indexing (Q3C) and Spatial Footprint (MOC) Placement guiding principles, surfaced during a stratSesh review of doc 26 (Domain Models). The Q3C principle corrects a pattern in that doc where the index existed only in raw migration SQL, requiring a permanent `include_object` exclusion in `env.py` to keep `alembic check` clean — declaring the index on the model instead removes that workaround entirely. The MOC placement principle generalizes the Level2Image/Level2Calibration split (footprint lives on the derived Level2Calibration, not the immutable Level2Image) into a standing rule for any future raw/derived entity pair.

###### 2026-07-09 — Claude-Authored Docs exception added
Added an exception to Roles & Responsibilities: for narrow, low-blast-radius, genuinely co-designed changes (docs/tooling/config, not application logic), Claude may draft the architecture doc directly instead of routing through Gemini, provided Claude still self-runs the full `assessPrompt` checklist. Avoids wasted motion re-briefing Gemini on a conversation it wasn't part of, while keeping the checklist's mechanical safeguards intact.

Expand Down
15 changes: 10 additions & 5 deletions .claude/skills/assess_arch.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Read `docs/architecture/[filename.md]`. Do NOT write any implementation code. Ru

For each failing item, produce: (a) a plain-language description of what is missing, and (b) a revision prompt the user can paste into Gemini. Revision prompts must convey the *what* and *why* of the required change clearly enough that Gemini can implement it without ambiguity — but must not ghostwrite the solution. State the problem, the location, and the recommended direction; leave the prose to Gemini. Do not dictate exact sentences or replacement text. If a choice must be made, flag it as **Decision Required** for the user before formulating the prompt.

**Deterministic fixes exception:** If a failing item has no open design judgment — the exact field, value, constraint, or test requirement is already fully specified and there's nothing left for Gemini to interpret — propose the literal edit inline and ask for confirmation before applying it directly to the architecture doc with the Edit tool, skipping the Gemini round-trip. Only route a finding through Gemini when real architectural/design judgment is still required.

**Backlog cross-reference:** Before running the checklist, fetch every open GitHub Issue labeled `tech-debt` or `enhancement` (via `gh issue list`). Cross-reference each against this doc's actual scope — the specific models, fields, or behaviors it creates or modifies right now, not just thematically related work. Flag an issue only if it touches something the doc is materially creating or changing in this pass. This is a best-effort pass over the currently open backlog, not an exhaustive audit — the user separately reviews the backlog directly as a backstop, so don't over-invest in this check as the backlog grows.

---

**§A — Scope & Decomposition**
Expand Down Expand Up @@ -50,8 +54,9 @@ For each failing item, produce: (a) a plain-language description of what is miss

**Output format:**
1. **Summary table first** — a markdown table with columns `Section | Result`, one row per §A–§G, `✅ PASS` / `❌ FAIL` / `✅ PASS (N/A)` / `⚠️ Decision needed`. No elaboration in the table itself.
2. **"What fixed cleanly" bullet list** — on re-assessment passes, briefly note which prior failing items are now resolved, before detailing anything still open.
3. **Failing items, each under its own subheading** — what's missing + a plain-language explanation. Use a comparison table instead of prose wherever a side-by-side (e.g. option A vs. option B, old behavior vs. new) would be clearer. If a failing item represents a genuine design decision (not a gap with an obvious fill), flag it as **Decision Required**, present the options with a recommendation and rationale, and wait for the user to confirm before including it in the Gemini prompt block.
4. **Decomposition recommendation** — only if §A fails.
5. **Consolidated Gemini revision prompt** — a single copyable fenced code block combining all confirmed revision instructions. Label it clearly so the user can paste it directly. Only include items where the fix is confirmed (i.e., no open Decision Required items remain unresolved).
6. **Exit condition** — when all items pass or are explicitly N/A: *"This document is ready for `runPrompt`."*
2. **Backlog Cross-Reference** — list every open `tech-debt`/`enhancement` issue relevant to what this doc creates or modifies, one line each: issue number, title, and a one-sentence reason naming the specific field/model/behavior it touches. If none apply, state that explicitly with a one-line reason. Relevant issues are never folded in automatically — flag each as **Decision Required** and wait for confirmation. If confirmed, label the corresponding item in the consolidated Gemini prompt as sourced from the backlog (e.g., "per backlog issue #N") so Gemini understands it's a pre-existing tracked concern being folded in now, not a gap found in its draft.
3. **"What fixed cleanly" bullet list** — on re-assessment passes, briefly note which prior failing items are now resolved, before detailing anything still open.
4. **Failing items, each under its own subheading** — what's missing + a plain-language explanation. Use a comparison table instead of prose wherever a side-by-side (e.g. option A vs. option B, old behavior vs. new) would be clearer. If a failing item represents a genuine design decision (not a gap with an obvious fill), flag it as **Decision Required**, present the options with a recommendation and rationale, and wait for the user to confirm before including it in the Gemini prompt block.
5. **Decomposition recommendation** — only if §A fails.
6. **Consolidated Gemini revision prompt** — a single copyable fenced code block combining all confirmed revision instructions that still require Gemini's judgment. Purely mechanical fixes are applied directly instead (per the deterministic-fixes exception above) and listed under "Applied directly," not included here. Label it clearly so the user can paste it directly. Only include items where the fix is confirmed (i.e., no open Decision Required items remain unresolved).
7. **Exit condition** — when all checklist items pass or are explicitly N/A, and any Backlog Cross-Reference items are resolved (folded in or explicitly deferred): *"This document is ready for `runPrompt`."*
48 changes: 34 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,10 @@ jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:16
env:
POSTGRES_USER: diffpype_ci
POSTGRES_PASSWORD: diffpype_ci
POSTGRES_DB: diffpype_ci
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 10
# NOTE: Postgres is built from docker/db.Dockerfile and run manually below
# rather than declared as a `services:` container, because the migrations in
# this repo require the Q3C spatial extension, which only exists in the
# project's custom db image — the stock postgres:16 image does not have it.

env:
DATABASE_URL: postgresql+psycopg2://diffpype_ci:diffpype_ci@localhost:5432/diffpype_ci
Expand All @@ -43,6 +33,36 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Build Q3C-enabled Postgres image
uses: nick-invision/retry@v3
with:
timeout_minutes: 10
max_attempts: 3
command: docker build -f docker/db.Dockerfile -t diffpype-db:ci .

- name: Start Postgres
run: |
docker run -d --name diffpype-db \
-e POSTGRES_USER=diffpype_ci \
-e POSTGRES_PASSWORD=diffpype_ci \
-e POSTGRES_DB=diffpype_ci \
-p 5432:5432 \
diffpype-db:ci

- name: Wait for Postgres to accept connections
run: |
for i in $(seq 1 30); do
if docker exec diffpype-db pg_isready -U diffpype_ci -d diffpype_ci; then
echo "Postgres is ready"
exit 0
fi
echo "Waiting for Postgres... ($i)"
sleep 2
done
echo "Postgres did not become ready in time"
docker logs diffpype-db
exit 1

- uses: actions/setup-python@v5
with:
python-version: "3.12"
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ services:
- "${API_PORT:-8000}:8000"
volumes:
- ./src:/app/src
- ./migrations:/app/migrations
depends_on:
db:
condition: service_healthy
Expand Down
4 changes: 2 additions & 2 deletions docker/worker.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ RUN uv sync --frozen --no-install-project --no-group test

# Layer 2: copy source then install the project so hatchling can build it
# correctly and register the diffpype-manage entry-point script.
COPY alembic.ini ./
COPY migrations/ ./migrations/
# Note: no alembic.ini/migrations/ here — the worker never runs alembic;
# only the api container does (docker compose exec api alembic upgrade head).
COPY src ./src
RUN uv sync --frozen --no-group test

Expand Down
Loading
Loading