Commit graph

8 commits

Author SHA1 Message Date
Parfii-bot
2d2c9881de feat(entity-store/b5): EdgeKeyKind::TextPair + archive verb — unblock kei-sage + kei-chat-store migration
schema.rs: EdgeKeyKind enum (IntegerPair default, TextPair) + archived_field:
Option<&'static str> on EntitySchema. Backward-compat via Default impl.

engine.rs: ddl_edge_table_for() dispatches integer vs text edge DDL.
Existing ddl_edge_table() untouched; new ddl_edge_table_text() adds
src_path/dst_path TEXT columns.

verbs/link.rs (rewrite): dispatches on edge_key_kind. Input JSON
{from:int, to:int} for IntegerPair OR {from:str, to:str} for TextPair.

verbs/rank.rs (rewrite): generic pagerank<K: Hash + Eq + Clone> over
node key type. Same algorithm, polymorphic in key.

verbs/archive.rs (new, 64 LOC): soft-delete via UPDATE <tbl> SET
<archived_field>=1 + optional <archived_field>_at=now(). Schema
without archived_field declared returns VerbError.

Tests: 20/20 kei-entity-store (was 10, +10: 5 text_pair + 5 archive).
kei-task 9/9 preserved (IntegerPair still default, backward-compat
verified).

Enables: kei-sage migration (TextPair edges) + kei-chat-store
migration (archive).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:30:33 +08:00
Parfii-bot
324ad5d53e fix(p1-integration): validate.rs allows _schemas/fragments $ref + drop additionalProperties on fragment-composed atom schemas
Two P1↔E1-audit-wave integration regressions caught by kei-runtime
invoke_real_atom test.

1. LocalFileResolver (E1 SSRF hardening) rejected $ref to
   _schemas/fragments/ because the dir is OUTSIDE atom's schema parent.
   Fix: extend LocalFileResolver with `find_fragments_root()` — walks up
   from schema root looking for `_schemas/fragments/`. If found, allow
   $ref under EITHER schema root OR fragments root. Still rejects
   arbitrary filesystem $ref.

2. jsonschema injection of absolute $id now ALSO applied to fragment
   schemas loaded via LocalFileResolver.resolve(). Without this, a
   fragment declaring `$id: "_schemas/fragments/titled.json"` (relative)
   was resolved against parent schema's absolute $id, producing double
   prefix `_schemas/fragments/_schemas/fragments/titled.json`.

3. create-input.json + create-output.json had `additionalProperties:
   false` alongside `allOf: [$ref <fragment>]`. Draft-07 gotcha:
   additionalProperties at this level does NOT see properties inherited
   from $ref-ed fragment — caused 'title' unexpected rejection. Dropped
   the constraint on 2 fragment-composed schemas; kept on 4 standalone
   ones (search-input/output + add-dependency-input/output).

Tests: kei-runtime 5/5 green; integration test passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 04:53:26 +08:00
Parfii-bot
793b91bc43 feat(convergence/p1): kei-entity-store engine + schema fragments + kei-task pilot
Layer A + B of convergence wave. Extract common SQLite-CRUD + graph
logic into kei-entity-store engine; introduce JSON Schema fragments;
pilot-migrate kei-task to verify parity.

New crate _primitives/_rust/kei-entity-store/ (1151 LOC):
- src/schema.rs — EntitySchema + FieldDef + enabled_verbs + fts_columns
  + edge_table + custom_migrations
- src/engine.rs — Store::open with WAL pragma + migration runner
- src/verbs/ — 8 data-driven verb modules (create/get/list/search/
  update/delete/link/rank) uniform JSON-in/JSON-out signature
- src/error.rs — typed VerbError enum
- tests/verb_smoke.rs — 10/10 green

New _schemas/fragments/ (83 LOC JSON):
- entity-base.json, titled.json, titled-content.json, edge.json

kei-task pilot migration:
- TASK_SCHEMA: EntitySchema static (67 LOC, was 58)
- store.rs becomes thin shim over engine::Store
- atoms/create.rs + atoms/search.rs delegate to engine verbs
- atoms/schemas/*.json use $ref to _schemas/fragments/ (DRY)
- Task-specific secondary tables (milestones, task_deps) stay via
  schema.custom_migrations; cycle-detection in deps.rs stays
  hand-rolled (domain logic, not generic CRUD)
- 9/9 tests green — full behavioural parity

Convergence delta:
- kei-task touched files: 342 → 389 LOC (+47 for JSON marshalling
  boundary; net wash on pilot)
- BUT each remaining 5 sibling crate can shrink ~400-500 LOC on migration
- Expected total reduction when all 6 migrated: ~2500 LOC across the cluster

Follow-ups declared:
- Migrate kei-chat-store, kei-content-store, kei-social-store to engine
- Migrate kei-sage (needs string-id edge variant; currently generic
  link/rank assume int ids)
- Migrate kei-crossdomain
- Expose list/delete atoms in kei-task (engine supports, atoms not yet)
- Fold kei-curator as engine::hygiene module (per P4 audit)
- Fold kei-search-core entities, keep workflow as thin kei-search-pipeline

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 04:46:47 +08:00
Parfii-bot
8626e23c22 feat(stream-e): invoke wire — kei-runtime subprocess → real atoms
Replace NotImplemented stub with real atom execution per schema
§Runtime invocation contract.

Convention: JSON-in/JSON-out over subprocess. Every refactored crate
exposes `<crate> run-atom <verb>` that reads JSON from stdin (or
--input), dispatches to atoms::<verb>::run, emits Output JSON on
stdout, exits per atom-error class.

Runtime side (kei-runtime):
- InvokeError: +AtomFailed{atom,code,stderr} +SubprocessError
  +OutputParse +BinaryNotFound{crate_name}. NotImplemented kept as
  legacy escape for atoms opting out of run-atom protocol.
- Output: now {atom: String, result: Value} — carries atom's actual
  return value.
- invoke_exit_code: AtomFailed passes through child exit (0..=255),
  Subprocess/OutputParse → 1, BinaryNotFound → 127, NotImplemented → 64.
- Binary resolution: KEI_RUNTIME_BIN_DIR env → PATH fallback.

kei-task side:
- New `pub mod run_atom` in lib.rs
- atoms/mod.rs: VERBS const + DispatchError enum wrapping per-atom errors
- src/run_atom.rs: read_input (stdin/@path/literal), dispatch, exit mapping
- main.rs: Cmd::RunAtom{verb, input} subcommand; collapsed three
  classify_*_error helpers into single classify_dispatch. Legacy
  create/search/add-dependency CLIs preserved.

Tests: 5/5 runtime (+1 invoke_real_atom integration), 9/9 kei-task
(+1 atoms::tests::verbs_list_matches_submodules).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 01:21:00 +08:00
Parfii-bot
1bc6fbf4e3 fix(substrate): E3 — CLI contract compliance (exit codes + invoke Err)
Four audit findings on CLI contract violations per locked §Runtime schema:

- crit#7: invoke returned Ok with error payload — now returns
  Err(InvokeError::NotImplemented) → exit 64
- crit#5: typed errors collapsed via anyhow::anyhow!("{e}") in kei-task —
  replaced with CliError { code, msg } + classify_*_error helpers;
  validation errors exit 2, storage errors exit 1 (spec-compliant)
- crit#8: lint.rs wikilink parser accepted [[[foo]] — strict parse_wikilink
  from kei-atom-discovery used; emits finding for malformed entries
- crit#15: draft-07 detection was substring match — is_draft07_uri exact
  match against canonical URIs only

Tests: 4/4 kei-runtime (was 2; +2 invoke exit-code tests) + 8/8 kei-task
(was 7; +1 empty-title exit-2 test) = 12/12 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:49:49 +08:00
Parfii-bot
ae82bc6242 feat(stream-b): kei-task pilot — 3 atoms (create/search/add-dependency)
Pilot refactor per locked substrate schema. kei-task migrated to atom
layout:

- atoms/<verb>.md — YAML frontmatter + human body for 3 verbs
- atoms/schemas/<verb>-{input,output}.json — JSON Schema draft-07
- src/atoms/<verb>.rs — typed Input/Output/Error + pub fn run()
- src/atoms/mod.rs — module registry
- Cargo.toml [package.metadata.keisei] — crate-level substrate data
- src/main.rs — dispatcher for 3 pilot commands via atoms::

Zero behaviour change: 7/7 integration tests pass before and after
(create_and_get, update_persists, cycle_detected, milestone_linking,
dependency_chain_traversal, task_graph_edges, search_finds_task).

main.rs still has 5 non-migrated subcommands (update, graph,
dependency-chain, milestone, link-milestone) — scope discipline, they
migrate in later passes. main.rs 120 → 132 LOC.

Stream B pilot reference — other crates follow this pattern in v0.24+.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:09:55 +08:00
Parfii-bot
81462a03ef chore(rust): misc schema/main refactor in 8 crates (assorted CP splits)
kei-chat-store, kei-content-store, kei-crossdomain, kei-curator, kei-router, kei-sage, kei-search-core, kei-social-store, kei-task — small schema + main refactors for test pass parity (167 Rust tests, 20 assembler).
2026-04-22 13:36:17 +08:00
Parfii-bot
adc007b7b0 feat(primitives): 10 Rust crates extracted from LBM (Genesis-scrubbed)
- kei-router — keyword-dispatch meta-tool (CfC ML fallback removed)
- kei-sage — Obsidian-style knowledge graph, FTS5 + BFS + PageRank
- kei-task — task DAG with deps, milestones, dependency-chain queries
- kei-chat-store — Claude conversation session persistence + FTS search
- kei-crossdomain — typed-edge store + BFS cross-domain glue
- kei-search-core — 3-wave deep research with microcent budget cap
- kei-content-store — asset + prompt + campaign registry
- kei-social-store — people + interactions CRM (lite)
- kei-curator — edge-decay graph hygiene utility
- kei-auth — multi-tenant session tokens (replaces single-bearer)

Genesis-scan pre-import pass: skipped pkg/mxl1/*, pkg/inference/*, pkg/trainer/*,
pkg/nc01/*, internal/ml/* (all Genesis/CfC adjacent, sensitive IP).
Security: skipped tools_threat/radio/protocol/med/mlreg (offensive/banned).
Domain verticals skipped: hr/legal/infra/ops/api/osint/edu/geo/hw/finance.

New 'mcp' profile in MANIFEST.toml bundles all 10 for MCP server deployment.

Workspace now 24 crates, cargo check --workspace clean, 94 workspace tests pass.
2026-04-22 12:48:56 +08:00