Add CLAUDE.md and rewrite README.md from fine-grain audit - #4
Conversation
README.md: replace stale GPT-generated draft with accurate architecture reference — exact ring specs (N, seed, weights), EDCM six-family metrics, directive names, file structure, installation notes, merge modes, status. CLAUDE.md: new developer guide for Claude Code — module summaries, key invariants (ring weights ↔ rings keys, no guardian key, canonical directive names, no pytest-asyncio), CI failure patterns, import paths, stub inventory, known issues, and a recipe for adding a new ring. https://claude.ai/code/session_018vyPzNQrgsLKq34wyyNY7W
There was a problem hiding this comment.
Pull request overview
Replaces the existing top-level documentation with a more detailed architecture reference and adds a new CLAUDE.md developer guide intended to keep future changes aligned with current PCNA implementation details.
Changes:
- Rewrite
README.mdwith architecture/inference/diagnostics overview plus setup/run instructions. - Add
CLAUDE.mdwith module summaries, invariants, CI notes, and extension recipes.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| README.md | New public-facing architecture + usage documentation for PCNA. |
| CLAUDE.md | New internal developer guide describing modules, invariants, CI expectations, and known stubs/issues. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| PCNA organizes compute and diagnostics into **53 prime-indexed seeds** arranged on a unit-circle address space with heptagram (7-site) routing. | ||
|
|
||
| GPT generated; context, prompt Erin Spencer | ||
| ### Seed Topology | ||
|
|
||
| | Layer | Count | Role | | ||
| |-------|-------|------| | ||
| | Global router | 1 | Coordination root (ID 0) | | ||
| | Sentinels | 4 | Diagnostics — observe, do not compute | | ||
| | Meta routers | 7 | Cluster aggregation | | ||
| | Compute seeds | 49 (7×7) | Primary compute units | | ||
| | **Total** | **53** | Prime — avoids harmonic aliasing | |
There was a problem hiding this comment.
The README states there are 53 seeds total (and that 53 is the prime total), but core/topology.py initializes 1 global + 4 sentinels + 7 meta routers + 49 compute seeds = 61 total seeds. Update the seed-count description/table to match the implemented topology (or clarify that 53 refers to ring size, not seed count).
| | Theta | Θ | 29 | — | Microkernel gate | | ||
| | Memory-L | — | 19 | 19 | Long-term memory | | ||
| | Memory-S | — | 17 | 17 | Short-term memory | |
There was a problem hiding this comment.
This section calls PCNAEngine a “six-ring pipeline” but the ring table includes Σ (Sigma), making it seven entries. Also, Θ’s RNG is seeded (seed=29 in core/theta.py), so listing Θ’s seed as “—” is misleading. Please reconcile the ring list (e.g., treat Sigma as an optional observer ring outside the six-ring pipeline) and correct the Θ seed field.
| | Theta | Θ | 29 | — | Microkernel gate | | |
| | Memory-L | — | 19 | 19 | Long-term memory | | |
| | Memory-S | — | 17 | 17 | Short-term memory | | |
| | Theta | Θ | 29 | 29 | Microkernel gate | | |
| | Memory-L | — | 19 | 19 | Long-term memory | | |
| | Memory-S | — | 17 | 17 | Short-term memory | | |
| Sigma (Σ) is an optional observer ring outside the six-ring pipeline: | |
| | Ring | Symbol | N | Seed | Role | | |
| |------|--------|---|------|------| |
| ``` | ||
| pcna/ | ||
| ├── core/ | ||
| │ ├── pcna.py # PCNAEngine — six-ring inference pipeline | ||
| │ ├── ptca_core.py # PTCACore — parameterized prime-ring tensor |
There was a problem hiding this comment.
The repository tree is shown under a top-level pcna/ directory, but in this repo core/, backend/, frontend/, etc. are at the repository root (there is no pcna/ directory). Please update the structure diagram to reflect the actual paths.
| N=29 microkernel gate. Ragged circle counts per node (1–12), SHA-256 blueprint sharding, gate control via `GATE_THRESHOLD=0.45`. Not a PTCACore subclass — standalone. Neighbors hardcoded to `±1, ±7 mod 29`. Imported as `from .theta import ThetaTensor`. | ||
|
|
||
| ### `core/sigma.py` — `SigmaRing` / `get_sigma()` | ||
| N=41 filesystem observer wrapping PTCACore. Tracks watched file mtimes, drains change events on `content_interval` cadence. Singleton via `get_sigma()`. All callers in pcna.py and zeta.py use `try/except ImportError` — sigma is optional but present. |
There was a problem hiding this comment.
core/pcna.py catches a broad Exception around the Sigma import/use (not just ImportError), so the guide’s claim that callers use try/except ImportError is inaccurate. Please update this to match the actual error-handling behavior in core/pcna.py/core/zeta.py.
| N=41 filesystem observer wrapping PTCACore. Tracks watched file mtimes, drains change events on `content_interval` cadence. Singleton via `get_sigma()`. All callers in pcna.py and zeta.py use `try/except ImportError` — sigma is optional but present. | |
| N=41 filesystem observer wrapping PTCACore. Tracks watched file mtimes, drains change events on `content_interval` cadence. Singleton via `get_sigma()`. In `core/pcna.py` and `core/zeta.py`, Sigma import/use is guarded with broad exception handling (not just `ImportError`), so treat Sigma as optional and potentially unavailable at runtime. |
| Parameterized long-term (N=19, seed=19) and short-term (N=17, seed=17) memory rings. Round-robin write, content-addressed query, `flush_to()` transfers short→long on positive reward. | ||
|
|
||
| ### `core/pcna.py` — `PCNAEngine` | ||
| Six-ring inference engine. Key attributes: `self.phi`, `self.psi`, `self.omega`, `self.theta`, `self.memory_l`, `self.memory_s`. `RING_WEIGHTS` dict uses keys matching `state()["rings"]` exactly: `phi, psi, omega, theta, memory_l, memory_s`. Checkpoints go in `.checkpoints/pcna_checkpoint.npz`. |
There was a problem hiding this comment.
This claims RING_WEIGHTS keys must match state()["rings"] exactly, but PCNAEngine.state() includes a sigma entry while RING_WEIGHTS does not. Please clarify the actual invariant (e.g., RING_WEIGHTS matches the scored ring set / ring_scores, while state()["rings"] may include additional optional rings like sigma).
| Six-ring inference engine. Key attributes: `self.phi`, `self.psi`, `self.omega`, `self.theta`, `self.memory_l`, `self.memory_s`. `RING_WEIGHTS` dict uses keys matching `state()["rings"]` exactly: `phi, psi, omega, theta, memory_l, memory_s`. Checkpoints go in `.checkpoints/pcna_checkpoint.npz`. | |
| Six-ring inference engine. Key attributes: `self.phi`, `self.psi`, `self.omega`, `self.theta`, `self.memory_l`, `self.memory_s`. `RING_WEIGHTS` defines the scored/core ring set — `phi, psi, omega, theta, memory_l, memory_s` — and should match the keys used for ring scoring (for example `ring_scores`), not necessarily every entry in `state()["rings"]`; `state()["rings"]` may also expose optional/diagnostic rings such as `sigma`. Checkpoints go in `.checkpoints/pcna_checkpoint.npz`. |
|
|
||
| ## Key Invariants | ||
|
|
||
| **Ring weights and ring keys must match.** `RING_WEIGHTS` in `pcna.py` and `state()["rings"]` must have identical keys. Currently: `{phi, psi, omega, theta, memory_l, memory_s}`. If you add or rename a ring, update both. |
There was a problem hiding this comment.
The “Key Invariants” section repeats that RING_WEIGHTS and state()["rings"] must have identical keys, but state()["rings"] includes sigma. Please update this invariant to reflect the real relationship between scored rings vs. all rings reported in state.
| **Ring weights and ring keys must match.** `RING_WEIGHTS` in `pcna.py` and `state()["rings"]` must have identical keys. Currently: `{phi, psi, omega, theta, memory_l, memory_s}`. If you add or rename a ring, update both. | |
| **Scored ring weights must match the scored rings in state.** `RING_WEIGHTS` in `pcna.py` must match the scored subset of `state()["rings"]`, not every ring reported there. Currently the scored rings are `{phi, psi, omega, theta, memory_l, memory_s}`, while `state()["rings"]` also includes `sigma`. If you add or rename a scored ring, update `RING_WEIGHTS` and the scored entries in `state()["rings"]`; if you add a non-scored ring such as `sigma`, do not add it to `RING_WEIGHTS` unless it becomes part of scoring. |
| ## CI | ||
|
|
||
| GitHub Actions runs two jobs on every push: | ||
|
|
||
| 1. **flake8** — `--select=E9,F63,F7,F82` (syntax errors, undefined names). Must pass clean. | ||
| 2. **pytest** — all `test_*.py` and `tests_*.py` in `tests/`. Must pass. | ||
|
|
There was a problem hiding this comment.
GitHub Actions is described as running two separate jobs, but .github/workflows/python-app.yml defines a single build job with flake8 and pytest steps. Please update this wording so it matches the workflow (still fine to describe the two steps).
…AUDE.md invariants README.md: - Fix total seed count: 61 (1+4+7+49), not 53; clarify N=53 is ring tensor size - Remove Sigma from six-ring scored table; give it a separate optional-observer section - Fix Theta seed: 29 (not "—") - Remove spurious pcna/ wrapper from repo tree (files are at repo root) CLAUDE.md: - core/sigma.py: describe actual exception handling (pcna.py uses broad except Exception; zeta.py splits ImportError from runtime exceptions) - core/pcna.py: clarify RING_WEIGHTS defines the scored ring set; state()["rings"] may include non-scored rings (sigma); they are not required to be identical - Key Invariants: rewrite ring-weights invariant to distinguish scored vs observer rings - CI: "two jobs" → "single build job with two steps" - Adding a New Ring: add scored vs observer branching in the recipe https://claude.ai/code/session_018vyPzNQrgsLKq34wyyNY7W
Summary
RING_WEIGHTS↔state()["rings"]key parity, noguardiankey, canonical directive names, nopytest-asyncio), CI failure patterns, import paths, stub inventory, known issues, recipe for adding a new ringTest plan
https://claude.ai/code/session_018vyPzNQrgsLKq34wyyNY7W