RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

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

Comparison

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

What each file covers

Sections

0 shared · 6 only in A · 6 only in B
  • − 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
  • + 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

Commands

neither file has any

Section tags

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

Line diff

+34 added−36 removed12 unchanged25.0% identical
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 
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 
@@ −1 +1 @@
1−# Acheron — AI agent & contributor guide
1+---
2+description: Background task lifecycle, shutdown ordering, and loop invariants
3+globs: app/worker/**/*.py,app/main.py
4+alwaysApply: false
5+---
26  
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.
7+# Background Task Lifecycle
98  
10−## What this is
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.
1113  
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.
14+## Drain vs. cancel on `stop()` (a correctness decision)
1715  
18−## Layering (keep these boundaries)
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`.
1921  
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.
22+When adding a task, ask: would cancelling mid-flight lose anything? That answer
23+picks the variant.
2324  
24−Business logic lives in services/stores, never in route handlers.
25+## Loop invariants
2526  
26−## Store roles (do not blur)
27+- Idle interruptibly — never block shutdown for a full interval:
2728  
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.
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+```
3337  
34−## Conventions in brief (see the scoped rules for detail)
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.
3540  
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.
41+## Shutdown ordering in `app/main.py` lifespan
4342  
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.
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.
4846  
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