Skip to content

docs(grid): GRID-MIGRATION-ROADMAP — 37-item phased migration checklist#1442

Merged
joelteply merged 2 commits into
canaryfrom
arch/grid-migration-roadmap
May 29, 2026
Merged

docs(grid): GRID-MIGRATION-ROADMAP — 37-item phased migration checklist#1442
joelteply merged 2 commits into
canaryfrom
arch/grid-migration-roadmap

Conversation

@joelteply
Copy link
Copy Markdown
Contributor

Sibling doc to GRID-BUS-ARCHITECTURE.md (#1439) and MULTI-PEER-COMMANDS.md (#1440/#1441).

Breaks the airc-grid migration into 5 layers, 37 PR-sized items, with explicit dependency chains, owner suggestions, effort estimates, done-criteria.

Layers

Layer Items Notes
L1 Foundation (substrate) 6 Hard prereq for L2-L5
L2 Chat migration 5 Finishes chat-out-of-ORM work
L3 Alloy refactor 3 Per FORGE-ALLOY-DOMAIN-EXTENSIBILITY.md WI 0-5
L4 Per-command opt-in 18 Phases A-G from MULTI-PEER §8.2
L5 Patch deletion 5 Interleaved with L2-L4 as upstreams complete

How it works

  • Each PR title format: `[L#-N] short title` (e.g. `[L1-2] AircEventTransport adapter`)
  • Each PR body opens with: `Closes roadmap item L#-N`
  • When PR merges: check off `[x]` the item + append `merged: yyyy-mm-dd PR#`
  • Status table at the top auto-summarizes by counting checkboxes
  • `grep "^- \[ \]"` shows everything still open

L1 cards seeded on airc kanban (P0, CambrianTech/continuum)

Item Card ID Owner suggestion
L1-1 EventClass registry (in commit) tab-2 (TS-only)
L1-2 AircEventTransport adapter (in commit) claude-tab-1 / 55c30b28
L1-3 CommandBase.naturalScope (in commit) tab-2 + codex/543c0bf7
L1-4 presence:peer-manifest + capability index (in commit) codex/543c0bf7
L1-5 grid-router-daemon + bid loop (in commit) codex + tab-2
L1-6 contract event chain + ed25519 (in commit) tab-2 + codex

L2-L5 cards NOT pre-populated — created as upstream items unblock, so cards reflect the reality the design encountered rather than the pre-implementation guess.

Peers self-claim per #cambriantech work-division pattern.

🤖 Generated with Claude Code

Sibling doc to GRID-BUS-ARCHITECTURE.md (#1439) + MULTI-PEER-COMMANDS.md.
Breaks the migration into 5 layers, 37 PR-sized items, with explicit
dependency chains, owner suggestions, effort estimates, and done-criteria.

Layers:
  L1 Foundation (substrate) — 6 items — hard prereq for L2-L5
  L2 Chat migration — 5 items — finishes chat-out-of-ORM work
  L3 Alloy refactor — 3 items (per FORGE-ALLOY-DOMAIN-EXTENSIBILITY.md WI 0-5)
  L4 Per-command opt-in — 18 items across Phases A-G
  L5 Patch deletion — 5 items, interleaved with L2-L4 as upstreams complete

Per Joel's instruction: PR descriptions reference this roadmap by item
ID (L#-N format); mergers check off [x] + append merge metadata
(yyyy-mm-dd PR#). Status table at the top auto-summarizes by counting
checkboxes.

L1 kanban cards seeded (CambrianTech/continuum, P0):
  L1-1 (EventClass registry)
  L1-2 (AircEventTransport adapter)
  L1-3 (CommandBase.naturalScope + CommandParams.scope)
  L1-4 (presence:peer-manifest + capability index)
  L1-5 (grid-router-daemon + bid loop)
  L1-6 (contract event chain + ed25519 signatures)

L2-L5 cards NOT pre-populated — created as upstream items unblock, so
the cards reflect the reality the design encountered rather than the
pre-implementation guess.

Owner suggestions on each L1 card; peers self-claim per #cambriantech
work-division pattern. Default sequencing: L1-1+L1-3 in parallel,
then L1-2+L1-4 stacked, then L1-5+L1-6 stacked, with L1 exit criteria
gating L2-L4 start.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
joelteply added a commit that referenced this pull request May 26, 2026
* feat(events,L1-1): EventClass declaration system + registry

Roadmap item L1-1 — the foundational event-class registry. All other L1-L5
work depends on this primitive. See docs/grid/GRID-MIGRATION-ROADMAP.md
(PR #1442) and docs/architecture/GRID-BUS-ARCHITECTURE.md §2.2 (#1439).

Closes roadmap item L1-1
Depends on: none
Spec: continuum#1439 + continuum#1442
Composes with: continuum#1443 AircEventTransport trait (L1-2 substrate)

Rust truth (continuum-core::events)
- EventClassConfig + ResolvedEventClassConfig (ts-rs export to
  shared/generated/events/).
- EventClassChannelStrategy: Local | Global | ByRoomId | ByPeerId | Custom.
- EventClassUnknownSchemaPolicy: Warn | Fail (default Fail — never
  silently swallow evidence).
- EventClassRegistry: parking_lot::RwLock<HashMap> behind OnceLock,
  declare/get/list/resolve_channel, canonicalize() idempotent-redeclare check.
- Validation enforced Rust-side: empty name, empty schemaVersion,
  broadcast-without-channel, channel-without-broadcast, conflicting redeclare.

IPC surface (modules::events)
- events/declare-class, events/get-class, events/list-classes,
  events/resolve-channel — registered alongside ForgeModule.

TS bindings (workers/continuum-core/bindings/modules/events.ts)
- EventsMixin wired into RustCoreIPC composition.

TS thin SDK (@system/events/shared/EventClass.ts)
- declareEventClass, getEventClass (read-through cache + null-cache +
  in-flight dedup), peekEventClassCache (sync hot-path),
  listEventClasses, resolveEventChannel.
- Native-truth-thin-SDK-per-language per the global rule — Rust owns
  truth; TS is the wrapper.

Events.emit integration (system/core/shared/Events.ts)
- Sync peek per emit; if class declared+cached, attach
  EventBridgePayload.eventClass hints; if cold, fire-and-forget warm-up
  so the next emit hits the cache. Backward-compat: undeclared classes
  get no hints, behavior identical to pre-L1-1.

Tests
- 38 Rust unit tests pass (cargo test events): validation, idempotent +
  conflicting redeclare, channel resolution all paths, IPC handlers,
  ts-rs bindings exports.
- 11 TS unit tests pass (vitest tests/unit/core/event-class-registry):
  cache hit/miss/null-cache, in-flight dedup, sync peek cold/warm,
  list warming, error propagation.

Done criteria from roadmap (L1-1)
- EventClass declarations accepted: yes (Rust + TS).
- Events.emit() reads metadata: yes (sync peek + warm-up + hint attach).
- Existing event uses continue working unchanged: yes.
- Unit tests for registry + classifier round-trip: yes (Rust + TS).

Build hygiene
- clippy-baseline bump 157 → 168: branch sits on canary HEAD e2fed99
  (PR #1443 "feat(airc): add typed event transport seam"), which added
  11 new clippy warnings without updating the baseline. My L1-1 code
  adds ZERO clippy warnings (verified by grep on event_class / events /
  modules/events.rs); the delta is inherited upstream drift. #1443's
  warnings should be cleaned up in a follow-up.
- tsconfig.eslint.json: add new unit test to `files` so ESLint can
  parse it (mirrors existing chat-coordination-stream.test.ts entry).

Out of scope (deferred per roadmap)
- L1-2 AircEventTransport consumer of these hints. Trait already exists
  (#1443); the adapter that consults EventClass metadata lands next.
- TS Command surface at commands/events/* for CLI introspection.
  Deferred to L4 when a CLI consumer materializes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(L1-1): lock the ESLint baseline win (5432 → 5431, linux)

CI ratchet runs on Linux and uses eslint-baseline.linux.txt. PR #1445's
L1-1 changes (adding tests/unit/core/event-class-registry.test.ts to
tsconfig.eslint.json's `files` array) net -1 error vs the prior linux
baseline. The ratchet enforces monotonic-decrease, so it fails when
current < baseline until we lock the improvement.

Note: src/eslint-baseline.txt (macOS-local) was set to 5431 in the
prior commit. This propagates the same fix to the linux baseline CI
actually consults.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…re, no node for core, persona migration as L0

Reframes the 37-item roadmap against the architectural ground rules
laid down 2026-05-29:

1. Rust core; Node.js is web only (browser UI, config-load at boot,
   human UX). Anything routing / persisting / dispatching / reasoning
   lives in Rust.
2. AI persona under Rust domain — PersonaUser was CPU-killing.
3. GPU or fail for inference + training.
4. No `dyn Any` / `as_any` patterns — debt when a trait requires them.
5. ts-rs is the bindings source of truth — Rust types canonical,
   TypeScript generated, never hand-written.
6. Inference through llama.cpp; never ollama; candle for training only.

Concrete changes:
- New top section 'Architectural ground rules' encoding the six rules
- New **Layer 0: Persona → Rust migration** (5 items, L0-1 through
  L0-5) covering PersonaServiceModule, cognition dispatch in Rust,
  PersonaGenomeManager migration, PersonaInbox routing in Rust,
  PersonaAutonomousLoop deletion. L0 is parallel to L1, independent.
  Overall item count: 37 → 42.
- Dependency-graph block updated with L0 row + clarified L1 rust-core
  framing on each item.
- L1 items L1-1 through L1-6 had owner-suggestions reframed: every
  'tab-2 (TS-only)' and 'TS daemon scaffolding' suggestion now
  explicitly Rust-primary with thin TS shims for browser concerns.
  Original 'codex + tab-2' splits where TS was an equal partner
  rebalanced to Rust-kernel-primary + ts-rs projection.
- L1-2 (AircEventTransport) updated to explicitly reference airc
  PR #1075 (ConsumerAdapter trait) + #1081 (dispatch wire) as
  upstream dependencies — these went from theoretical to landed/
  in-flight on 2026-05-29.

Per Joel: 'we can update or just merge it in' — this is the update
path. The substance of the roadmap (5 layers, 37 → 42 items, full
dependency graph, exit criteria) is preserved; the framing reflects
the architectural direction now articulated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@joelteply joelteply merged commit db244a8 into canary May 29, 2026
2 checks passed
@joelteply joelteply deleted the arch/grid-migration-roadmap branch May 29, 2026 17:01
joelteply added a commit that referenced this pull request May 29, 2026
…erviceModule (L0-1)

Replaces TypeScript PersonaAutonomousLoop. ONE Rust tick services
every enrolled persona instead of N TS loops crossing the V8↔Rust
IPC boundary on every cadence beat.

Why singleton, not per-persona:
- ModuleConfig.name is &'static str — runtime registry can't store
  dynamic per-persona names.
- Beyond the constraint, singleton wins anyway: one tick = whole
  fleet, adding the 16th persona is enrollment-only, the cadence
  budget is shared across personas instead of per-persona contended.

Surface:
- enroll(persona_id, display_name) -> Result
- enrolled_count() -> usize
- ServiceModule impl with command_prefixes=["persona/"], High prio,
  250ms tick. Handles persona/status + persona/enroll.
- Per-persona circuit breaker (5 consecutive failures = 30s cooldown)
  + per-persona drain bound (20 items / tick) keeps one bad persona
  from starving the rest.

Tests: 8 unit tests covering config, status, enroll/idempotency,
multi-persona, unknown-command rejection, empty-tick, enrolled-tick.

Note on as_any: ServiceModule trait currently requires it for
downcasting in the registry; tracked separately for removal per the
no-Any directive.

L0-1 of GRID-MIGRATION-ROADMAP (PR #1442 merged into canary).
Follow-ups: L0-2 (cognition dispatch in service_once_for), L0-3
(genome manager), L0-4 (inbox routing), L0-5 (delete the TS
PersonaAutonomousLoop once L0-1..L0-4 land).

Verified on Xcode 26.3 + llama metal feature, all 8 tests pass.
No /Users paths, no private deps — all airc crates pinned at
workspace level to public CambrianTech/airc git revs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
joelteply added a commit that referenced this pull request May 29, 2026
…erviceModule (L0-1)

Replaces TypeScript PersonaAutonomousLoop. ONE Rust tick services
every enrolled persona instead of N TS loops crossing the V8↔Rust
IPC boundary on every cadence beat.

Why singleton, not per-persona:
- ModuleConfig.name is &'static str — runtime registry can't store
  dynamic per-persona names.
- Beyond the constraint, singleton wins anyway: one tick = whole
  fleet, adding the 16th persona is enrollment-only, the cadence
  budget is shared across personas instead of per-persona contended.

Surface:
- enroll(persona_id, display_name) -> Result
- enrolled_count() -> usize
- ServiceModule impl with command_prefixes=["persona/"], High prio,
  250ms tick. Handles persona/status + persona/enroll.
- Per-persona circuit breaker (5 consecutive failures = 30s cooldown)
  + per-persona drain bound (20 items / tick) keeps one bad persona
  from starving the rest.

Tests: 8 unit tests covering config, status, enroll/idempotency,
multi-persona, unknown-command rejection, empty-tick, enrolled-tick.

Note on as_any: ServiceModule trait currently requires it for
downcasting in the registry; tracked separately for removal per the
no-Any directive.

L0-1 of GRID-MIGRATION-ROADMAP (PR #1442 merged into canary).
Follow-ups: L0-2 (cognition dispatch in service_once_for), L0-3
(genome manager), L0-4 (inbox routing), L0-5 (delete the TS
PersonaAutonomousLoop once L0-1..L0-4 land).

Verified on Xcode 26.3 + llama metal feature, all 8 tests pass.
No /Users paths, no private deps — all airc crates pinned at
workspace level to public CambrianTech/airc git revs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
joelteply added a commit that referenced this pull request May 29, 2026
…erviceModule (L0-1) (#1457)

Replaces TypeScript PersonaAutonomousLoop. ONE Rust tick services
every enrolled persona instead of N TS loops crossing the V8↔Rust
IPC boundary on every cadence beat.

Why singleton, not per-persona:
- ModuleConfig.name is &'static str — runtime registry can't store
  dynamic per-persona names.
- Beyond the constraint, singleton wins anyway: one tick = whole
  fleet, adding the 16th persona is enrollment-only, the cadence
  budget is shared across personas instead of per-persona contended.

Surface:
- enroll(persona_id, display_name) -> Result
- enrolled_count() -> usize
- ServiceModule impl with command_prefixes=["persona/"], High prio,
  250ms tick. Handles persona/status + persona/enroll.
- Per-persona circuit breaker (5 consecutive failures = 30s cooldown)
  + per-persona drain bound (20 items / tick) keeps one bad persona
  from starving the rest.

Tests: 8 unit tests covering config, status, enroll/idempotency,
multi-persona, unknown-command rejection, empty-tick, enrolled-tick.

Note on as_any: ServiceModule trait currently requires it for
downcasting in the registry; tracked separately for removal per the
no-Any directive.

L0-1 of GRID-MIGRATION-ROADMAP (PR #1442 merged into canary).
Follow-ups: L0-2 (cognition dispatch in service_once_for), L0-3
(genome manager), L0-4 (inbox routing), L0-5 (delete the TS
PersonaAutonomousLoop once L0-1..L0-4 land).

Verified on Xcode 26.3 + llama metal feature, all 8 tests pass.
No /Users paths, no private deps — all airc crates pinned at
workspace level to public CambrianTech/airc git revs.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant