|
| 1 | +# Plan 338: katgpt-sense Cross-Module Decoupling (Issue 007 Phase E Tier 2 #7) |
| 2 | + |
| 3 | +> **Origin:** [Issue 007](../../../riir-ai/.issues/007_katgpt_runtime_ip_exfiltration_from_public_mit_repo.md) Phase E Tier 2 #7 |
| 4 | +> **Status:** Active — options analysis done, awaiting decision |
| 5 | +> **Branch:** `develop` |
| 6 | +> **Created:** 2026-06-28 |
| 7 | +> **Cross-repo:** katgpt-rs only (sense has no riir-ai consumers per grep) |
| 8 | +
|
| 9 | +--- |
| 10 | + |
| 11 | +## TL;DR |
| 12 | + |
| 13 | +The remaining `katgpt-core::sense` substrate (5,232 LOC across 10 files) is the |
| 14 | +last blocked Tier 2 promotion. The blocker is **three internal-to-katgpt-core |
| 15 | +dependencies** that no prior plan anticipated: |
| 16 | + |
| 17 | +| Sense File | External katgpt-core dep | Source | |
| 18 | +|---|---|---| |
| 19 | +| `sense/lod.rs` | `crate::slod::ScaleBoundary` | `katgpt-core/src/slod.rs` (1,047 LOC) | |
| 20 | +| `sense/reconstruction.rs` | `crate::temporal_deriv::TemporalDerivativeKernel` (gated `temporal_deriv`) | `katgpt-core/src/temporal_deriv.rs` (424 LOC) | |
| 21 | +| `sense/spectral_threat.rs` | `crate::linoss::{LinOSSCell, LinOSSState}` | `katgpt-core/src/linoss.rs` (938 LOC) | |
| 22 | +| All sense files | `crate::types::{SenseKind, SenseModule, TernaryDir}` | `katgpt-types` ✅ already extracted | |
| 23 | + |
| 24 | +**Recommended strategy: C — Hybrid co-extraction.** |
| 25 | +Co-extract the two generic primitives (`ScaleBoundary`, `TemporalDerivativeKernel`) |
| 26 | +to `katgpt-types`; promote `katgpt-sense` as a new crate with cross-crate deps on |
| 27 | +`katgpt-types` only; keep `linoss` in `katgpt-core` (it has exactly one consumer |
| 28 | +— `sense/spectral_threat.rs` — which stays in `katgpt-core` as a composition |
| 29 | +module, not promoted with the generic substrate). |
| 30 | + |
| 31 | +**Why not the alternatives:** |
| 32 | +- **A (minimal co-extract)**: only unblocks `lod.rs`, leaves `temporal_deriv` + |
| 33 | + `linoss` cycles unresolved. |
| 34 | +- **B (4 sibling crates)**: over-engineered for the LOC budget. `katgpt-linoss` |
| 35 | + would ship with exactly 1 consumer (itself a 623 LOC file). Three new crates |
| 36 | + for ~2,400 LOC of primitives. |
| 37 | +- **D (defer indefinitely)**: leaves 5,232 LOC of clearly publishable octree / |
| 38 | + reconstruction / bake / sector machinery stranded in the mega-crate. |
| 39 | + |
| 40 | +Strategy C extracts one new crate (~4,600 LOC after splitting out |
| 41 | +`spectral_threat`), promotes two generic primitives to the leaf, and leaves |
| 42 | +one tightly-coupled pair (`linoss` + `spectral_threat`) inside katgpt-core |
| 43 | +where they belong as composition-layer code. |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +## Detailed Options Analysis |
| 48 | + |
| 49 | +### Option A — Co-extract `ScaleBoundary` to katgpt-types only |
| 50 | + |
| 51 | +Move just the `ScaleBoundary` struct (small POD: `sigma`, `lambda`, etc.) to |
| 52 | +`katgpt-types/src/enums.rs` or a new `spectral.rs` submodule. |
| 53 | + |
| 54 | +- `sense/lod.rs` then depends only on `katgpt-types` — promoted cleanly. |
| 55 | +- `sense/reconstruction.rs` still depends on `temporal_deriv` — **stays blocked**. |
| 56 | +- `sense/spectral_threat.rs` still depends on `linoss` — **stays blocked**. |
| 57 | + |
| 58 | +**Verdict:** Unblocks 1 of 3 problem files. The remaining 2 keep `katgpt-sense` |
| 59 | +dependent on katgpt-core. **Reject** — doesn't achieve the goal. |
| 60 | + |
| 61 | +### Option B — Extract 4 sibling crates |
| 62 | + |
| 63 | +Promote `katgpt-slod`, `katgpt-temporal-deriv`, `katgpt-linoss`, `katgpt-sense` |
| 64 | +as four new public crates. |
| 65 | + |
| 66 | +- Each is independently publishable. |
| 67 | +- katgpt-sense depends on the other three. |
| 68 | + |
| 69 | +**Math:** |
| 70 | + |
| 71 | +| Crate | LOC | External consumers (outside katgpt-core) | |
| 72 | +|---|---|---| |
| 73 | +| katgpt-slod | 1,047 | 0 (only `rtdc.rs` + `sense/lod.rs` use it, both internal) | |
| 74 | +| katgpt-temporal-deriv | 424 | 0 (only `cgsp/derivative_curiosity.rs`, `delta_mem/state.rs`, `sense/reconstruction.rs` — all internal) | |
| 75 | +| katgpt-linoss | 938 | 0 (only `sense/spectral_threat.rs` — 1 internal consumer) | |
| 76 | +| katgpt-sense | 5,232 | downstream via re-export (TBD) | |
| 77 | + |
| 78 | +**Verdict:** Three crates with **zero external consumers** violates the |
| 79 | +"publishable-leaf" criterion established in Plan 008. The whole point of |
| 80 | +promotion is to surface public substrate; these are private katgpt-core |
| 81 | +internals. **Reject** — over-engineered, leaks internal layering decisions. |
| 82 | + |
| 83 | +### Option C — Hybrid co-extraction ✅ RECOMMENDED |
| 84 | + |
| 85 | +**Three moves:** |
| 86 | + |
| 87 | +1. **`ScaleBoundary` → katgpt-types.** The struct is a small POD |
| 88 | + (`sigma: f32`, `lambda: f32`, etc.) — fits naturally alongside other |
| 89 | + generic spectral primitives. Co-extract ~50 LOC. |
| 90 | + |
| 91 | +2. **`TemporalDerivativeKernel` → katgpt-types.** This is a generic |
| 92 | + temporal-primitive (424 LOC file, but the public surface is one struct + |
| 93 | + one free fn `sigmoid_surprise_gate`). Co-extract the kernel struct + gate |
| 94 | + fn; tests stay in katgpt-core. |
| 95 | + |
| 96 | +3. **`linoss` stays in katgpt-core.** It has exactly one consumer |
| 97 | + (`sense/spectral_threat.rs`). Co-promoting them would be more correct than |
| 98 | + splitting. The 623 LOC `spectral_threat.rs` file stays in katgpt-core as a |
| 99 | + **composition module** (mirrors how `forward_hla` stayed in katgpt-core |
| 100 | + while the HLA substrate got promoted in Tier 2 #4). |
| 101 | + |
| 102 | +**Net result:** |
| 103 | +- New crate `katgpt-sense` (10 → 9 files after `spectral_threat.rs` stays): |
| 104 | + ~4,609 LOC. |
| 105 | +- katgpt-types grows by ~470 LOC (ScaleBoundary + TemporalDerivativeKernel). |
| 106 | +- katgpt-core keeps `linoss.rs` (938 LOC) + `sense/spectral_threat.rs` (623 |
| 107 | + LOC) = 1,561 LOC of composition code. |
| 108 | +- Re-export shim: `#[cfg(feature = "sense_composition")] pub use katgpt_sense as sense;` |
| 109 | + in `katgpt-core/src/lib.rs`. |
| 110 | +- `sense/spectral_threat.rs` becomes `katgpt_core::sense_threat` (or similar) |
| 111 | + and is re-exported alongside the substrate via a second shim. |
| 112 | + |
| 113 | +**Why this is the GOAT:** |
| 114 | +- Matches the established Tier 1/Tier 2 pattern (substrate out, composition stays). |
| 115 | +- Only 1 new crate (not 4). |
| 116 | +- Generic primitives go to the leaf where they get widest reuse. |
| 117 | +- Tightly-coupled `linoss + spectral_threat` stay together in katgpt-core as |
| 118 | + composition code — exactly where they belong. |
| 119 | + |
| 120 | +### Option D — Defer indefinitely |
| 121 | + |
| 122 | +Document that `katgpt-sense` is too entangled to extract and accept it as |
| 123 | +part of katgpt-core's integrated substrate. |
| 124 | + |
| 125 | +**Verdict:** Leaves 5,232 LOC of clearly publishable machinery (octree, |
| 126 | +reconstruction, bake, sector) inside the mega-crate. The octree and |
| 127 | +reconstruction files alone (`octree.rs` + `reconstruction.rs` + `serialize.rs` |
| 128 | += 2,421 LOC) are pure substrate with zero deps outside `katgpt-types`. |
| 129 | +**Reject** — leaves real value stranded. |
| 130 | + |
| 131 | +--- |
| 132 | + |
| 133 | +## Phased Task Breakdown (Strategy C) |
| 134 | + |
| 135 | +### Phase 1 — Co-extract `ScaleBoundary` to katgpt-types |
| 136 | + |
| 137 | +- [ ] **T1.1** Audit `katgpt-core/src/slod.rs` — extract the `ScaleBoundary` |
| 138 | + struct definition + its derives/impls into a new katgpt-types module |
| 139 | + (`katgpt-types/src/spectral.rs` or extend `enums.rs`). |
| 140 | +- [ ] **T1.2** Update `katgpt-core/src/slod.rs` to re-export |
| 141 | + `katgpt_types::ScaleBoundary` (mirror the leaky_core / depth_invariance |
| 142 | + pattern from Tier 1 #3). |
| 143 | +- [ ] **T1.3** Run GOAT gate: |
| 144 | + - `cargo check -p katgpt-types` clean. |
| 145 | + - `cargo check -p katgpt-core --features slod` clean. |
| 146 | + - `cargo test -p katgpt-core --features slod --lib` — test count matches |
| 147 | + pre-extraction baseline. |
| 148 | + - `cargo check -p riir-engine` clean (no API surface change). |
| 149 | + |
| 150 | +### Phase 2 — Co-extract `TemporalDerivativeKernel` to katgpt-types |
| 151 | + |
| 152 | +- [ ] **T2.1** Audit `katgpt-core/src/temporal_deriv.rs` (424 LOC) — extract |
| 153 | + the public API surface (`TemporalDerivativeKernel` struct, constructor, |
| 154 | + `process`/`step` methods, `sigmoid_surprise_gate` free fn) into |
| 155 | + `katgpt-types/src/temporal.rs`. |
| 156 | +- [ ] **T2.2** Tests stay in katgpt-core (they exercise the kernel through |
| 157 | + the re-export). |
| 158 | +- [ ] **T2.3** Update `katgpt-core/src/temporal_deriv.rs` to be a re-export |
| 159 | + shim: `pub use katgpt_types::temporal::*;`. Preserve the |
| 160 | + `#[cfg(feature = "temporal_deriv")]` gate. |
| 161 | +- [ ] **T2.4** Run GOAT gate: |
| 162 | + - `cargo check -p katgpt-types --features temporal_deriv` (if feature is |
| 163 | + propagated to katgpt-types — likely yes, since the kernel is now there). |
| 164 | + - `cargo check -p katgpt-core --features temporal_deriv` clean. |
| 165 | + - `cargo test -p katgpt-core --features temporal_deriv --lib` — test count |
| 166 | + matches. |
| 167 | + - `cargo check -p katgpt-core --features delta_mem` clean (delta_mem/state.rs |
| 168 | + consumes the kernel). |
| 169 | + |
| 170 | +### Phase 3 — Promote katgpt-sense (substrate minus spectral_threat) |
| 171 | + |
| 172 | +- [ ] **T3.1** Create `crates/katgpt-sense/` with `Cargo.toml` declaring |
| 173 | + deps: `katgpt-types` only (after Phase 1+2, all external deps resolve here). |
| 174 | +- [ ] **T3.2** `git mv` 9 files from `crates/katgpt-core/src/sense/` → |
| 175 | + `crates/katgpt-sense/src/`: |
| 176 | + - `bake.rs`, `lod.rs`, `mod.rs` (→ `lib.rs`), `octree.rs`, |
| 177 | + `reconstruction.rs`, `reconstruction_depth_invariance.rs`, |
| 178 | + `schema_centroid.rs`, `sector.rs`, `serialize.rs`. |
| 179 | +- [ ] **T3.3** KEEP `spectral_threat.rs` in `katgpt-core/src/sense_threat.rs` |
| 180 | + (rename to avoid clash). It needs `crate::linoss` which stays in |
| 181 | + katgpt-core. |
| 182 | +- [ ] **T3.4** Rename `mod.rs` → `lib.rs`, update internal paths: |
| 183 | + - `crate::<module>::` → `crate::` (within the new crate). |
| 184 | + - `crate::types::` → `katgpt_types::`. |
| 185 | + - `crate::slod::` → `katgpt_types::` (after Phase 1). |
| 186 | + - `crate::temporal_deriv::` → `katgpt_types::temporal::` (after Phase 2). |
| 187 | +- [ ] **T3.5** Add re-export shims in `katgpt-core/src/lib.rs`: |
| 188 | + ```rust |
| 189 | + #[cfg(feature = "sense_composition")] |
| 190 | + pub use katgpt_sense as sense; |
| 191 | + ``` |
| 192 | + The `spectral_threat` module stays as a separate katgpt-core mod and is |
| 193 | + consumed via `katgpt_core::sense_threat::*` or re-exported through the |
| 194 | + `sense` alias if downstream compat requires. |
| 195 | +- [ ] **T3.6** Feature-forwarding: `sense_composition` Cargo feature in |
| 196 | + katgpt-core changes from `[]` to `["dep:katgpt-sense"]`. Default-on / opt-in |
| 197 | + status preserved (audit current default-on list to confirm). |
| 198 | +- [ ] **T3.7** Update katgpt-core's `sense/mod.rs` (if it survives) or remove |
| 199 | + it (likely removed — the substrate moved out). |
| 200 | + |
| 201 | +### Phase 4 — Verification (cross-cutting) |
| 202 | + |
| 203 | +- [ ] **T4.1** `cargo check -p katgpt-sense` clean. |
| 204 | +- [ ] **T4.2** `cargo test -p katgpt-sense --lib` — count matches the 9 |
| 205 | + promoted files' tests. |
| 206 | +- [ ] **T4.3** `cargo check -p katgpt-core` clean (default + all-features). |
| 207 | +- [ ] **T4.4** `cargo test -p katgpt-core --lib` — default count delta |
| 208 | + matches promoted test count; all-features count delta matches |
| 209 | + promoted-with-feature-gate test count. |
| 210 | +- [ ] **T4.5** `cargo check -p katgpt-core --features spectral_threat` clean |
| 211 | + (this feature now activates `sense_threat` mod + the `linoss` dep). |
| 212 | +- [ ] **T4.6** `cargo check --workspace --all-features` clean. |
| 213 | +- [ ] **T4.7** `cargo check -p riir-engine` clean (verifies re-export shims |
| 214 | + preserve API). **Allow 7-10 min for this step.** |
| 215 | +- [ ] **T4.8** `cargo check -p riir-neuron-db --all-features` clean. |
| 216 | +- [ ] **T4.9** `cargo check -p riir-chain --all-features` clean. |
| 217 | + |
| 218 | +### Phase 5 — Issue 007 closure |
| 219 | + |
| 220 | +- [ ] **T5.1** Mark Phase E Tier 2 #7 as `[x]` in |
| 221 | + `riir-ai/.issues/007_*.md`. |
| 222 | +- [ ] **T5.2** Update Tier 2 status summary (now 4/4 done). |
| 223 | +- [ ] **T5.3** Update the cumulative Phase E LOC count. |
| 224 | + |
| 225 | +--- |
| 226 | + |
| 227 | +## Risks |
| 228 | + |
| 229 | +| Risk | Likelihood | Mitigation | |
| 230 | +|---|---|---| |
| 231 | +| `ScaleBoundary` has hidden impls / trait bounds that don't fit katgpt-types | Low | It's a POD with derives only; audit in T1.1 | |
| 232 | +| `TemporalDerivativeKernel` constructor depends on katgpt-core internals | Medium | T2.1 audit; if so, the constructor stays in katgpt-core and the struct moves | |
| 233 | +| `sense/spectral_threat.rs` is consumed externally via `katgpt_core::sense::spectral_threat` | Low | Grep `riir-ai` for the path; if found, re-export through the alias | |
| 234 | +| `spectral_threat` Cargo feature and `sense_composition` Cargo feature get tangled | Medium | Audit Cargo.toml feature deps in T3.6 before changing | |
| 235 | +| Test count delta doesn't match expected | Low | Established pattern from Tier 1/2 #4-6 works; delta tracking is mechanical | |
| 236 | + |
| 237 | +--- |
| 238 | + |
| 239 | +## GOAT Gate (Promotion Criteria) |
| 240 | + |
| 241 | +Per `katgpt-rs/AGENTS.md` Feature Flag Discipline: |
| 242 | + |
| 243 | +1. **G1 correctness**: all promoted tests pass standalone in katgpt-sense. |
| 244 | +2. **G2 perf**: not applicable (substrate move, no algorithm change). |
| 245 | +3. **G3 no-regression**: katgpt-core test count deltas match exactly; riir-engine |
| 246 | + builds unchanged. |
| 247 | +4. **G4 alloc-free**: not applicable (no hot-loop changes). |
| 248 | +5. **Modelless gain**: ✅ — this is a pure structural refactor with no training |
| 249 | + dependency. Promotes to default-on if `sense_composition` was already |
| 250 | + default-on (audit in T3.6). |
| 251 | + |
| 252 | +--- |
| 253 | + |
| 254 | +## Open Questions to Resolve Before Phase 1 |
| 255 | + |
| 256 | +- [ ] Is `sense_composition` currently in katgpt-core's `default` feature list? |
| 257 | + (Determines whether katgpt-sense gets default-on status.) |
| 258 | +- [ ] Does `sense/spectral_threat.rs` get consumed externally via the |
| 259 | + `katgpt_core::sense::spectral_threat` path? If yes, the re-export alias |
| 260 | + needs to surface it. |
| 261 | +- [ ] Are there other Cargo features that imply `sense_composition`? |
| 262 | + (Mirrors how `committed_field_blend` implies `personality_composition`.) |
| 263 | + |
| 264 | +--- |
| 265 | + |
| 266 | +## Cross-Repo Coordination |
| 267 | + |
| 268 | +Single-repo change (katgpt-rs only). Sense has no `riir-ai` consumers per |
| 269 | +grep (the NPC-runtime half moved in Phase C). Path deps unchanged. |
| 270 | + |
| 271 | +Commit prefix: `feat(katgpt-sense)!: promote sense substrate` for Phase 3, |
| 272 | +`feat(katgpt-types): co-extract ScaleBoundary + TemporalDerivativeKernel` |
| 273 | +for Phase 1+2. |
0 commit comments