Parfii-bot
38ceab0913
feat(w9e): NEW kei-replay crate — reconstruct spawn from DNA
...
kei-replay <dna> parses DNA, looks up ledger row, loads task.toml
from worktree, re-runs compose_prompt, recomputes body hash, reports
match/drift.
kei-replay diff <dna-1> <dna-2> flags every changed facet between
two DNAs.
6 cubes (main/lib/replay/diff/ledger_lookup), all ≤114 LOC.
Direct SQLite access in ledger_lookup.rs (kei-ledger has no lib.rs).
v4 schema-compatible (reads id/dna/worktree_path/spec_sha).
Tests: 6/6 (≥4 required): happy path, missing DNA, drift detection,
diff differing bodies, diff identical, explicit --task override.
Workspace Cargo.toml: +kei-replay member.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 13:34:16 +08:00
Parfii-bot
e0e6e1720d
docs: HANDOFF-WAKE summary of autonomous Wave 8
...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 12:19:07 +08:00
Parfii-bot
26e74cfa15
Merge SP1 — kei-spawn automation envelope
2026-04-23 10:22:38 +08:00
Parfii-bot
948f07bfa8
Merge E2 — kei-capability fork subcommand
2026-04-23 10:22:38 +08:00
Parfii-bot
11b85c2a61
Merge TX3 — ledger creator/fork columns
2026-04-23 10:22:38 +08:00
Parfii-bot
3b549988ea
Merge TX2 — kei-sage facet-query + lineage
2026-04-23 10:22:38 +08:00
Parfii-bot
355f01b929
Merge E1 — engine improvements (TextPk/Real/TextArchiveEnum/TextPairWithMetadata)
2026-04-23 10:22:38 +08:00
Parfii-bot
36b7941ad2
Merge TX1 — taxonomy schema extension
2026-04-23 10:22:38 +08:00
Parfii-bot
eac09a6354
feat(e1): engine improvements — TextPk + Real + TextArchiveEnum + TextPairWithMetadata
...
4 additive FieldKind/EdgeKeyKind variants addressing M1 dogfood +
M4/M5 flags. Backward-compat — existing schemas unchanged.
FieldKind::TextPk — TEXT PRIMARY KEY (kei-chat-store UUID sessions)
FieldKind::Real + RealDefault(f64) — REAL columns (kei-chat-store cost)
FieldKind::TextArchiveEnum — archive verb writes string sentinel instead of 1
EdgeKeyKind::TextPairWithMetadata — src_path/dst_path + id/weight/created_at/extra
Archive verb now dispatches: IntegerFlag writes 1, TextArchiveEnum writes sentinel.
Link/rank handle TextPairWithMetadata via generic weight+id propagation.
PK helpers in verbs/pk.rs abstract integer vs text primary key.
Engine decomposed to stay under 200 LOC:
- schema.rs (149) + field.rs (94, new) + ddl.rs (157, new)
- verbs/pk.rs + create_defaults.rs split from create.rs
Tests: 40/40 (was 32, +8 real_text_pk_smoke).
Sister crates verified backward-compat:
- kei-task 9/9, kei-chat-store 5/5, kei-content-store 4/4
- kei-social-store 5/5, kei-crossdomain 5/5, kei-sage 28/28
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:22:22 +08:00
Parfii-bot
02451f5f49
feat(sp1): NEW kei-spawn crate — automation envelope
...
spawn <task.toml> internally calls prepare + ledger fork, emits
JSON ready for Agent tool invocation. verify wraps post-return
check+ledger update. list-pending shows running forks.
kei-ledger invoked via subprocess (no lib.rs in kei-ledger).
KEI_SPAWN_LEDGER_NOOP=1 test escape hatch for CI without binary.
spec_sha = SHA-256 of task.toml bytes (workspace sha2 dep).
Tests: 6/6 integration (happy, explicit-id, unknown-role, non-spawnable,
verify-missing, end-to-end roundtrip).
Step 3 (Anthropic API) stays with orchestrator — next iteration adds
kei-spawn drive <task.toml> for HTTP automation.
Workspace Cargo.toml: +kei-spawn member.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:21:45 +08:00
Parfii-bot
6e7e517f83
feat(e2): kei-capability fork subcommand + lineage stamping
...
New 'fork' subcommand copies capability dir + rewrites capability.toml
with [lineage].fork_from + parents + creator + created. Refuses
clobber, validates slug regex.
Tests: 4 integration + 2 unit (epoch_to_iso, split_cap_name) = 6/6.
Doc update in AGENT-SUBSTRATE-SCHEMA.md §Orchestrator ergonomics.
Zero-chrono ISO-8601 via Hinnant's algorithm (single-file).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:21:45 +08:00
Parfii-bot
55606b176f
feat(tx3): kei-ledger v4 migration — creator_id + fork_parent_id + descendants
...
Schema v4 adds creator_id TEXT + fork_parent_id TEXT columns with
indexes. Migration one-txn matches v2/v3 pattern.
fork() gains --creator + --fork-parent flags. New Descendants
subcommand walks fork_parent_id OR creator_id chain.
Extracted row.rs (AgentRow + SELECT_COLS) + descendants.rs +
dispatch.rs to stay ≤200 LOC.
Tests: 18/18 (was 13, +5: creator roundtrip, fork-parent lineage,
descendants chain, pre-v4 NULL backward-compat, v4 idempotent).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:21:45 +08:00
Parfii-bot
5a34c35311
feat(tx2): kei-sage facet query + lineage traversal
...
3 new subcommands:
- facet-query <key=value> [<k2=v2>...] — AND-filter walks primitives
- lineage <primitive-id> [--depth N] — BFS ancestors/descendants/forks
- author <creator-id> [--limit N] — all primitives by creator
facet_query.rs walks _capabilities/*/*/capability.toml + _manifests/*.toml
via toml parser. Handles missing sections correctly (None != specific).
lineage.rs BFS over parents[] wikilinks + fork-from + created-by edges.
Tests: 34/34 (was 28, +6: 3 facet_smoke + 3 lineage_smoke).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:21:45 +08:00
Parfii-bot
e418f1247c
feat(tx1): taxonomy + lineage facets schema extension
...
Optional [taxonomy] + [lineage] TOML sections on capability.toml and
atom .md frontmatter. Backward-compat — all fields optional, existing
files parse unchanged.
TaxonomyFacets struct (7 facets): kingdom, mechanism, domain, layer,
stage, stability, language.
Lineage struct: parents[], creator, created, fork_from.
AtomMeta extended with taxonomy: Option<TaxonomyFacets> + lineage:
Option<Lineage>.
docs/TAXONOMY.md — canonical vocabulary. Graph-based (DAG with typed
edges), not tree. Multi-faceted nodes allowed.
3 pilot primitives tagged: policy::no-git-ops, quality::cargo-check-green,
tools::bash-allowlist.
Tests: 16/16 (was 12, +4: full/partial/no-facets/parents-array).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 06:10:58 +08:00
Parfii-bot
010def05ad
Merge R2 — kei-cache
...
# Conflicts:
# _primitives/_rust/Cargo.toml
2026-04-23 05:56:12 +08:00
Parfii-bot
b823a99812
Merge R1 — kei-pipe DAG runtime
2026-04-23 05:55:35 +08:00
Parfii-bot
41eec8d5b1
Merge M5 — kei-sage migration
2026-04-23 05:55:35 +08:00
Parfii-bot
91f9f050e1
Merge M4 — kei-crossdomain migration
2026-04-23 05:55:35 +08:00
Parfii-bot
af16066793
Merge M3 — kei-social-store migration
2026-04-23 05:55:35 +08:00
Parfii-bot
a28ce2b36c
Merge M2 — kei-content-store migration
2026-04-23 05:55:35 +08:00
Parfii-bot
6edcba7c4b
Merge M1 — kei-chat-store migration (dogfood via prepare)
2026-04-23 05:55:34 +08:00
Parfii-bot
76dcdc5c87
feat(r2): new kei-cache crate — deterministic result cache
...
Wraps pure (query/transform) atom invocations with SHA-256 keyed
cache. Refuses Command/Stream kind atoms as unsafe.
22/22 tests (14 unit + 8 integration). Canonical JSON keying
(formatting-drift safe). TTL expiry. AtomExecutor trait decouples
subprocess from test mocks.
Default DB ~/.claude/cache/cache.sqlite, overridable via --db or
$KEI_CACHE_DB.
Workspace Cargo.toml: +kei-cache member.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
0b948ca07c
feat(r1): new kei-pipe crate — atom DAG runtime
...
The critical missing substrate composition layer.
kei-pipe run <dag.toml> — reads DAG spec, topo-sorts atoms, executes
sequentially, pipes JSON between steps via $step.path.to.field
resolver. 6 Constructor-Pattern cubes: dag/resolve/exec/report/lib/main.
5/5 smoke tests: happy path + cycle detection + unknown dep +
nested path resolver + unreadable file.
Resolver envelope matches kei-runtime Output — atoms round-trip
identically through either runtime.
Workspace Cargo.toml: +kei-pipe member.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
5f72f6a0a8
feat(m5): migrate kei-sage to kei-entity-store engine (largest migration)
...
28/28 tests preserved — most complex migration.
Primary entity = unit via engine; edges + FTS stay sage-local in
custom_migrations (engine TextPair minimal: lacks id/weight/created_at/
UNIQUE constraint that sage's graph operations require).
pagerank.rs + bfs.rs preserved as sage-local (graph semantics tied to
typed edge_type + weight, not generic).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
59c30603f3
feat(m4): migrate kei-crossdomain to kei-entity-store engine (edges-only)
...
5/5 tests preserved. Synthetic nodes PK table via engine; cross_edges
stays in custom_migrations because engine's TextPair is too minimal
(id/weight/evidence/metadata columns needed).
Flag for engine follow-up: TextPair DDL needs optional edge metadata
columns — same gap flagged by M5 independently.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
0b645db646
feat(m3): migrate kei-social-store to kei-entity-store engine
...
5/5 tests preserved. Primary entity = person; orgs + interactions +
relationship_graph stay custom.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
6ad8fd81ed
feat(m2): migrate kei-content-store to kei-entity-store engine
...
4/4 tests preserved. Primary entity = content_units; prompts +
campaigns + campaign_assets in custom_migrations.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
519600d1bf
feat(m1-dogfood): migrate kei-chat-store to kei-entity-store engine
...
Primary entity = chat_messages (integer-PK; sessions stay bespoke —
TEXT UUID PK incompatible with engine's IntegerPk).
Secondary tables (chat_sessions, indexes, FTS rename fts_chat →
fts_chat_messages) moved into custom_migrations. FTS shadow column
session_id dropped (never used as MATCH filter).
Archive verb NOT enabled: chat_sessions.status is TEXT enum not INTEGER
flag — engine archive verb incompatible. archive_session stays bespoke.
cost REAL column dropped — engine has no Real FieldKind. per-message
cost struct field kept (=0.0) for API compat; session total_cost
aggregate still maintained bespoke in save_message.
5/5 tests preserved + 1 new engine migration-parity smoke test.
DOGFOOD prompt feedback (M1 via kei-agent-runtime prepare):
6 engine limitations surfaced for follow-up — FieldKind::TextPk,
FieldKind::Real, archive-TEXT-enum variant, FTS UNINDEXED shadow cols,
atom dir assumption, rusqlite drop logic. See M1 task report.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:12 +08:00
Parfii-bot
e075ae8df1
fix(compose): render resolved scope block — agent sees concrete paths, not generic text
...
Dogfood gap #2 from prepare workflow: capability text fragments say
"your task's scope" generically, but agent never sees the resolved
scope params from task.toml. Migration agent had no way to know
whitelist = kei-chat-store/** without me pasting it.
Fix: render_scope_block() injects a resolved-params section between
capability fragments and task body. Shows:
- files-whitelist / files-denylist glob lists
- cargo-check-crates / cargo-test-crates
- test-count-min (if Option<u32>::Some)
- report-fields-required
If no scope params set, block is empty (no section rendered).
Now `kei-agent-runtime prepare` emits fully self-contained prompt —
no external context needed. Substrate unblocked for parallel migrations.
Tests: 41/41 (was 41 — no regression; scope-block added tests deferred
to follow-up since compose_smoke already covers existing path).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:44:15 +08:00
Parfii-bot
68e37ecf68
fix(a1-integration): add EdgeKeyKind + archived_field defaults to bug_fixes_smoke fixture
...
A1's test fixture created before B5 merged new fields onto EntitySchema.
Cross-wave fixup — non-functional change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:33:21 +08:00
Parfii-bot
70867a7fd0
Merge fix/b5-textpair — EdgeKeyKind + archive verb
2026-04-23 05:31:03 +08:00
Parfii-bot
a5c5a68627
Merge fix/a1-entity-store — C1+C2+FTS5+M3+TEXT-cap+M2
2026-04-23 05:31:03 +08:00
Parfii-bot
bf5c4d3dce
Merge fix/b2-dna-role — DNA + role + traversal
2026-04-23 05:31:03 +08:00
Parfii-bot
ba75a075e3
Merge fix/b1-pattern-gate — hardening
2026-04-23 05:31:03 +08:00
Parfii-bot
a78f1aaa5f
Merge fix/b3-ledger — cycle + txn + length cap
2026-04-23 05:31:03 +08:00
Parfii-bot
da147c9a1b
Merge fix/b4-provision — exec redaction
2026-04-23 05:31:03 +08:00
Parfii-bot
3095b325d2
Merge fix/prepare-ergonomics — auto-gen agent-id for dogfood workflow
2026-04-23 05:31:03 +08:00
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
4546239e8b
fix(ledger/b3): S2 tree cycle DoS + migration txn + length cap
...
S2: tree() had no visited set; cyclic parent_branch rows → infinite
loop. Added HashSet visited + MAX_TREE_DEPTH=1024 breaker. Returns
LedgerError::MaxDepthExceeded instead of OOM.
M2 migration txn: apply_one() wraps DDL + user_version bump in
BEGIN IMMEDIATE / COMMIT / ROLLBACK. Partial failure can no longer
leave user_version at N-1 with N's schema applied.
L1 length cap: branch + parent_branch strings capped to 256 chars
via 3-layer defence: clap value_parser!(parse_branch), client-side
check_branch_lens, schema v3 BEFORE INSERT/UPDATE triggers.
New src/error.rs (46 LOC) — LedgerError + MAX_TREE_DEPTH. SELECT_COLS
const DRY'd 4 duplicated column lists (list, by_id, children_of).
Schema v3 uses triggers (not table CHECK — SQLite can't retrofit
CHECK on existing tables without rebuild).
Tests: 13/13 (was 10, +3 audit). All 3 fixes exercised.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:30:33 +08:00
Parfii-bot
fdb6939015
fix(provision/b4): exec.rs redacts args + truncates stderr
...
MEDIUM info-disclosure: run_json_strict + run_void formatted error
messages with full argv + full stderr. Today argv has no secrets
(env-only per RULE 0.8) but:
- Future refactor could pass --api-key inline → secret in logs
- vultr-cli stderr echoes request URLs with query params → enumeration
Fix:
- redact_args() → "bin_name <N args>" (argv hidden)
- truncate_stderr() → first 200 chars + "... (truncated)", UTF-8 safe
- Docstring: // DO NOT pass secrets as CLI args — env-only per RULE 0.8
Tests: 11/11 (was 8, +3: redaction asserts no argv in error, stderr
truncation + Cyrillic UTF-8 safety)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:30:33 +08:00
Parfii-bot
02e4b25af2
fix(entity-store/a1): C1 type coercion + C2 FTS transaction + FTS5 injection + M3 SQL escape + TEXT cap + M2 migration version
...
6 critical/high bugs from post-convergence audit fixed in one pass.
New src/verbs/validate.rs (95 LOC) — shared typed validator:
- coerce() returns VerbError::InvalidType{field,expected,got} on wrong-kind JSON
- Preserves "missing key → default" semantics (additive, not breaking)
- MAX_TEXT_BYTES 64 KiB cap enforced on all text fields (M2 audit)
verbs/create.rs + update.rs (C1 + C2):
- Typed validation replaces silent 0/""/empty coercion
- insert_tx() + update_tx() wrap INSERT + FTS DELETE+INSERT in
conn.unchecked_transaction(); mid-flight failure rolls back both
main row + FTS sidecar together (no orphan FTS rows)
verbs/search.rs — fts5_quote() defends FTS5 syntax injection:
- User query wrapped in "..." phrase quotes, internal " doubled
- Column-prefix `title:secret`, NEAR(), wildcards become literal
- Integration + unit tests
engine.rs:
- ddl_column() escapes ' → '' on TextDefault values (M3)
- apply_user_version() stamps CURRENT_USER_VERSION=1 via PRAGMA;
idempotent (won't downgrade). Opens migration path (M2).
Tests: 22/22 (was 10, +12). kei-task 9/9 preserved — no regression.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:27:59 +08:00
Parfii-bot
4983d38636
fix(agent-runtime/b2): DNA entropy 32-bit + role path traversal + recursion cap + warnings
...
H4/M4/S3 DNA entropy:
- short_sha256() widened to 8 hex (32-bit) for scope + body hash
- nonce expanded to 8 hex from full u32 via rand::random
- Birthday collision at ~77K agents sharing role+caps (was ~256)
- Dna::parse accepts legacy 4-hex values with stderr warning for
rolling upgrade of pre-fix DNAs
H5 role recursion: resolve_inner depth parameter + MAX_DEPTH=16.
Returns RoleError::MaxDepthExceeded{depth, trace:Vec<String>} for
clear diagnostics.
S1 path traversal — two sites closed:
- role.rs::resolve_inner validates role name + parent in extends
against regex ^[a-z][a-z0-9-]{0,63}$ before Path::join
- compose.rs::split_cap_name same validation on capability
category/slug before Path::join
- RoleError::InvalidName{kind, value} on violation
M1 relaxes warnings: eprintln replaced with ResolvedRole.warnings
Vec<String> field. Caller decides: log, fail, ignore.
New typed RoleError (thiserror) — PartialEq/Eq for test ergonomics.
Tests: 73/73 (was 66, +7: 3 DNA + 4 role). Full extends graph + malicious
name + depth+1 all covered.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:27:59 +08:00
Parfii-bot
f9bfcc23b7
fix(agent-runtime/b1): PatternGate hardening — RwLock, Result, UTF-8, explicit deny
...
H1 lock contention: Mutex<HashMap> → RwLock<HashMap>. Hot path cheap
read-lock, write-lock only on first compile per pattern.
H2 panic removed: compile_checked() returns Result<Regex, regex::Error>;
all call sites propagate as GateDecision::Deny{reason:"misconfigured
regex..."}. No .expect()/.unwrap() on compile anywhere.
H3 dead branch: AllowIfMatch + TaskWhitelist/TaskDenylist combo was
silently NotApplicable (allow-everything). Now explicit Deny with
"misconfigured" + "AllowIfMatch" in reason. Fail-closed.
S4 UTF-8 panic: &s[..60] byte-slice → s.chars().take(60). Cyrillic/
emoji safe. 60-char budget by code point.
L2 render chain: String::replace chain → single-pass render_template()
that scans {token} markers once. Substituted text cannot bleed into
later tokens.
Tests: 70/70 (was 66, +4). pattern_gate_smoke 10 → 14.
Follow-up (out of file-boundary scope): per-pattern Lazy<Regex> variant
would eliminate the RwLock entirely but requires editing sibling gate
consts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:27:59 +08:00
Parfii-bot
9c8c7c3598
fix(prepare): auto-generate agent-id when absent + dogfood ergonomics
...
Dogfood gap found: orchestrator running `kei-agent-runtime prepare
<task.toml>` hit "task.agent-id is empty" error. Required 3-step flow
(ledger fork → edit task.toml → prepare) for every spawn.
Fix: auto-generate `ag-<role>-<unix-ms-hex>-<4hex-rand>` if task.agent-id
empty. Orchestrator can still pre-allocate for deterministic ids;
auto-gen is ergonomic default. DNA compose sees the effective id via
clone+inject into TaskSpec before Dna::compose.
Helper `autogen_agent_id()` uses SystemTime millis + rand u16 — low
collision at orchestrator spawn rate (< 1 spawn/ms).
build_ledger_row() split: original preserved as thin wrapper, new
build_ledger_row_with_id() accepts explicit id for auto-gen path.
Verified end-to-end via `/tmp/keisei-dogfood/test-task.toml`:
prepare now emits complete AgentInvocation including composed prompt,
DNA, verify command — ready for orchestrator Agent-tool invocation
without pre-alloc step.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:23:55 +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
30a07e22ca
Merge feat/convergence-p3-role-dna — role expression + DNA identity
2026-04-23 04:47:30 +08:00
Parfii-bot
eba5c8ea10
Merge feat/convergence-p2-pattern-command — PatternGate + CommandVerify traits
2026-04-23 04:47:30 +08:00
Parfii-bot
b36225c03f
Merge feat/convergence-p1-entity-store — engine + schema fragments + kei-task pilot
2026-04-23 04:47:30 +08:00
Parfii-bot
84319efcb6
feat(convergence/p3): Role expression (extends/relaxes) + DNA identity
...
Layer E + G. Role TOML gains extends/relaxes for parent-role
composition; agent spawn gets self-describing DNA identity alongside
UUID.
Role expression:
- _roles/*.toml gain optional `extends = "<parent>"` + `relaxes = [...]`
- compose.rs + verify.rs delegate to new role::resolve_role() with
recursive extends-chain resolution + cycle detection
- explorer.toml: 28→18 LOC (extends read-only)
- edit-shared.toml: 31→23 LOC (extends edit-local, relaxes
scope::files-whitelist for task-param override)
DNA identity:
- new dna.rs (159 LOC) — compose/render/parse round-trip
- AgentInvocation carries dna field (prepare.rs)
- Format: <role>::<caps-bitmap>::<sha4-scope>::<sha4-body>-<hex4-nonce>
- ≤ 80 chars total, greppable, parseable
- 11 capability codes in CAP_CODES table: NG, FW, FD, CP, CG, TG, ND,
RF, SG, DT, BA
kei-ledger schema v2:
- ADD COLUMN dna TEXT + prefix index
- `kei-ledger fork --dna <string>` optional flag
- AgentRow.dna: Option<String>
- Backward compat: schema migration detects + applies on open
Docs: AGENT-SUBSTRATE-SCHEMA.md Layer E + Layer G sections + CAP_CODES table.
New deps: sha2 (workspace), rand 0.8.
Tests: kei-agent-runtime 50 (was 41, +9: 4 role + 5 DNA), kei-ledger
10 (was 9, +1 DNA roundtrip).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 04:46:48 +08:00
Parfii-bot
360a20a942
feat(convergence/p2): PatternGate + CommandVerify unified traits
...
Layer C + D. 6 gate modules + 3 verify modules → 1 generic struct per
family + const declarations. Data-driven, not module-per-capability.
New:
- src/gates/pattern_gate.rs (192 LOC) — PatternGate struct with
GateMode::{DenyIfMatch, AllowIfMatch}, static regex compilation via
once_cell, bypass env support, Capability trait impl
- src/verifies/command_verify.rs (142 LOC) — CommandVerify struct with
WorkDir::{WorkspaceRoot, CrateDir, MainRepoSub}, subprocess exec +
exit-code check, extra_env support, Capability trait impl
Converted (const declarations, ~15-27 LOC each):
- gates/policy_no_git_ops.rs (49→22)
- gates/safety_no_dep_bump.rs (35→19)
- gates/scope_files_whitelist.rs (37→16)
- gates/scope_files_denylist.rs (35→16)
- gates/tools_bash_allowlist.rs (58→27)
- verifies/quality_cargo_check_green.rs (41→18)
- verifies/quality_tests_green.rs (75→80, folded common shape)
- verifies/safety_no_dep_bump.rs (39→47)
Kept separate (different shape, not PatternGate/CommandVerify):
- gates/tools_deny_tools.rs (tool-name match, not pattern)
- verifies/quality_constructor_pattern.rs (LOC walker)
- verifies/output/report_format.rs + severity_grade.rs (text parsers)
- verifies/scope_files_{whitelist,denylist}.rs (diff-walkers)
Registry.rs preserves alias table + deprecation warnings + all_names().
Tests: 57/57 green (was 41, +16: 10 pattern_gate_smoke + 6 command_verify_smoke).
LOC net: 5 gates 214→100 (-53%), shared PatternGate+CommandVerify 334
LOC absorb duplication. Amortization breaks even around 3-4 new gates
added later.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 04:46:47 +08:00