RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/jleist-clemson-acheron-cursor-rules-background-tasks ↔ jleist-clemson-acheron-agents

Comparison

A · Cursor rules · jleist-clemson/acheronB · AGENTS.md · jleist-clemson/acheron
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections0660%
Commands000—
Section tags0160%

What each file covers

Sections

0 shared · 6 only in A · 6 only in B
  • − Background Task Lifecycle
  • − Drain vs. cancel on `stop()` (a correctness decision)
  • − Loop invariants
  • − ✅ wakes immediately on stop
  • − ❌ asyncio.sleep(self._interval) # ignores the stop signal
  • − Shutdown ordering in `app/main.py` lifespan
  • + Acheron — AI agent & contributor guide
  • + What this is
  • + Layering (keep these boundaries)
  • + Store roles (do not blur)
  • + Conventions in brief (see the scoped rules for detail)
  • + Docs are a first-class deliverable

Commands

neither file has any

Section tags

0 shared · 1 only in A · 6 only in B
  • − monorepo
  • + test
  • + lint-format
  • + code-style
  • + do-not
  • + agent-behaviour
  • + docs

Line diff

+36 added−34 removed12 unchanged25.0% identical
jleist-clemson/acheron · .cursor/rules/background-tasks.mdc
@@ −1 @@
1---
2description: Background task lifecycle, shutdown ordering, and loop invariants
3globs: app/worker/**/*.py,app/main.py
4alwaysApply: false
5---
6 
7# Background Task Lifecycle
 
 
 
 
 
8 
9Background tasks (`WorkerPool`, `EsIndexer`, `RollupScheduler`) follow a
10`start()` / `stop()` shape with an `asyncio.Event` stop signal and a single
11`asyncio.create_task(..., name=...)`. The skeleton matters less than the
12decisions below — get these wrong and you lose data or hang a deploy.
13 
14## Drain vs. cancel on `stop()` (a correctness decision)
 
 
 
 
15 
16- If the task holds **un-acked, un-persisted work**, drain it before cancelling.
17 `WorkerPool.stop()` does `await queue.join()` with a timeout, *then* cancels.
18- If the task's work is **idempotent / replayable** (the outbox re-indexes, the
19 next tick re-aggregates), set the stop event and cancel directly —
20 `EsIndexer` / `RollupScheduler`.
21 
22When adding a task, ask: would cancelling mid-flight lose anything? That answer
23picks the variant.
 
24 
25## Loop invariants
26 
27- Idle interruptibly — never block shutdown for a full interval:
28 
29```python
30# ✅ wakes immediately on stop
31try:
32 await asyncio.wait_for(self._stop_event.wait(), timeout=self._interval)
33except asyncio.TimeoutError:
34 pass # interval elapsed
35# ❌ asyncio.sleep(self._interval) # ignores the stop signal
36```
37 
38- The loop body **catches and logs**, never lets an exception kill the task.
39- Consumers must call `task_done()` for every `get()`, even on error.
40 
41## Shutdown ordering in `app/main.py` lifespan
 
 
 
 
 
 
42 
43`ingestion.stop_accepting()` → `worker.stop()` (drain) → `es_indexer.stop()` →
44`rollup.stop()` → **then** close Mongo/ES/Redis clients. Never close a client a
45running task still uses.
 
46 
jleist-clemson/acheron · AGENTS.md
@@ +1 @@
1# Acheron — AI agent & contributor guide
 
 
 
 
2 
3Vendor-neutral project context, shared across AI coding tools. Cursor reads this
4file natively; Claude Code reads it via the `@AGENTS.md` import in `CLAUDE.md`.
5Tool-specific rules live in `.cursor/rules/` (Cursor, glob-scoped via `globs:`)
6and `.claude/rules/` (Claude Code, imported from `CLAUDE.md` so they load every
7session) — keep those mirrors in sync with each other and with this file.
8`ARCHITECTURE.md` is the authoritative design document.
9 
10## What this is
 
 
 
11 
12`acheron` is a Distributed Event Processing Platform. Write path:
13`POST /events` → bounded in-process `asyncio.Queue` → async worker →
14**MongoDB (source of truth)**. Elasticsearch is a **derived mirror**, populated
15strictly downstream from a Mongo outbox (`es_indexed` marker) by the `EsIndexer`.
16Redis caches the realtime stats summary.
17 
18## Layering (keep these boundaries)
 
 
 
 
19 
20- `app/api/` — HTTP only: translate request ↔ domain, map errors to status codes.
21- `app/ingestion/`, `app/worker/` — pipeline logic (enqueue, consume, index, rollup).
22- `app/storage/`, `app/cache/`, `app/queue/` — one backend per module.
23 
24Business logic lives in services/stores, never in route handlers.
25 
26## Store roles (do not blur)
27 
28- **Mongo is authoritative.** If Mongo and ES disagree, Mongo wins.
29- **ES is best-effort and rebuildable** — never fail an authoritative write on it.
30- **Redis is a cache** — a Redis outage must degrade, never lose data.
31- The queue is **in-process and non-durable**; that constraint drives most
32 failure-mode and scaling reasoning. Don't design as if it were durable.
 
 
 
33 
34## Conventions in brief (see the scoped rules for detail)
 
35 
36- `from __future__ import annotations` atop every module; Google-style docstrings
37 (ruff `D`, pydocstyle google). Tunables live in `Settings`, not magic numbers.
38- Routes are thin; the events routes declare a Pydantic `response_model`
39 (`/health` and `/metrics` are intentionally exempt). Errors map to status
40 codes (Mongo→503, ES→502, queue full→429, shutdown→503).
41- Tests: pytest with `asyncio_mode=auto`; unit tests are hermetic, Docker-backed
42 tests are marked `integration` and deselected by default.
43 
44## Docs are a first-class deliverable
45 
46When you change behavior, update `ARCHITECTURE.md` and `README.md` in the same
47change. Code and docs must not drift — the architecture doc is graded.
48 
@@ −1 +1 @@
1−---
2−description: Background task lifecycle, shutdown ordering, and loop invariants
3−globs: app/worker/**/*.py,app/main.py
4−alwaysApply: false
5−---
1+# Acheron — AI agent & contributor guide
62  
7−# Background Task Lifecycle
3+Vendor-neutral project context, shared across AI coding tools. Cursor reads this
4+file natively; Claude Code reads it via the `@AGENTS.md` import in `CLAUDE.md`.
5+Tool-specific rules live in `.cursor/rules/` (Cursor, glob-scoped via `globs:`)
6+and `.claude/rules/` (Claude Code, imported from `CLAUDE.md` so they load every
7+session) — keep those mirrors in sync with each other and with this file.
8+`ARCHITECTURE.md` is the authoritative design document.
89  
9−Background tasks (`WorkerPool`, `EsIndexer`, `RollupScheduler`) follow a
10−`start()` / `stop()` shape with an `asyncio.Event` stop signal and a single
11−`asyncio.create_task(..., name=...)`. The skeleton matters less than the
12−decisions below — get these wrong and you lose data or hang a deploy.
10+## What this is
1311  
14−## Drain vs. cancel on `stop()` (a correctness decision)
12+`acheron` is a Distributed Event Processing Platform. Write path:
13+`POST /events` → bounded in-process `asyncio.Queue` → async worker →
14+**MongoDB (source of truth)**. Elasticsearch is a **derived mirror**, populated
15+strictly downstream from a Mongo outbox (`es_indexed` marker) by the `EsIndexer`.
16+Redis caches the realtime stats summary.
1517  
16−- If the task holds **un-acked, un-persisted work**, drain it before cancelling.
17− `WorkerPool.stop()` does `await queue.join()` with a timeout, *then* cancels.
18−- If the task's work is **idempotent / replayable** (the outbox re-indexes, the
19− next tick re-aggregates), set the stop event and cancel directly —
20− `EsIndexer` / `RollupScheduler`.
18+## Layering (keep these boundaries)
2119  
22−When adding a task, ask: would cancelling mid-flight lose anything? That answer
23−picks the variant.
20+- `app/api/` — HTTP only: translate request ↔ domain, map errors to status codes.
21+- `app/ingestion/`, `app/worker/` — pipeline logic (enqueue, consume, index, rollup).
22+- `app/storage/`, `app/cache/`, `app/queue/` — one backend per module.
2423  
25−## Loop invariants
24+Business logic lives in services/stores, never in route handlers.
2625  
27−- Idle interruptibly — never block shutdown for a full interval:
26+## Store roles (do not blur)
2827  
29−```python
30−# ✅ wakes immediately on stop
31−try:
32− await asyncio.wait_for(self._stop_event.wait(), timeout=self._interval)
33−except asyncio.TimeoutError:
34− pass # interval elapsed
35−# ❌ asyncio.sleep(self._interval) # ignores the stop signal
36−```
28+- **Mongo is authoritative.** If Mongo and ES disagree, Mongo wins.
29+- **ES is best-effort and rebuildable** — never fail an authoritative write on it.
30+- **Redis is a cache** — a Redis outage must degrade, never lose data.
31+- The queue is **in-process and non-durable**; that constraint drives most
32+ failure-mode and scaling reasoning. Don't design as if it were durable.
3733  
38−- The loop body **catches and logs**, never lets an exception kill the task.
39−- Consumers must call `task_done()` for every `get()`, even on error.
34+## Conventions in brief (see the scoped rules for detail)
4035  
41−## Shutdown ordering in `app/main.py` lifespan
36+- `from __future__ import annotations` atop every module; Google-style docstrings
37+ (ruff `D`, pydocstyle google). Tunables live in `Settings`, not magic numbers.
38+- Routes are thin; the events routes declare a Pydantic `response_model`
39+ (`/health` and `/metrics` are intentionally exempt). Errors map to status
40+ codes (Mongo→503, ES→502, queue full→429, shutdown→503).
41+- Tests: pytest with `asyncio_mode=auto`; unit tests are hermetic, Docker-backed
42+ tests are marked `integration` and deselected by default.
4243  
43−`ingestion.stop_accepting()` → `worker.stop()` (drain) → `es_indexer.stop()` →
44−`rollup.stop()` → **then** close Mongo/ES/Redis clients. Never close a client a
45−running task still uses.
44+## Docs are a first-class deliverable
45+ 
46+When you change behavior, update `ARCHITECTURE.md` and `README.md` in the same
47+change. Code and docs must not drift — the architecture doc is graded.
4648  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack