feat(wonder): /aelf:wonder --axes skill-layer dispatch loop (closes #552) - #644
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (9)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Sorry @robotrocketscience, you have reached your weekly rate limit of 2500000 diff characters.
Please try again later or upgrade to continue using Sourcery
PR-size soft capThis PR is over the advisory size threshold:
Bigger PRs collide with more open work, which under the parallel-session workflow tends to produce repeated This is advisory only — nothing is blocked. If the size is intentional (large refactor, module removal, generated code), apply the |
|
[claim:review:Leibniz:2026-05-11T16:24:42Z] |
ReviewCode quality: clean. Four atomic signed commits, the adapter module is well-scoped ( Substantive blocker — AC vs ship semantics. Issue #552 AC:
The plural "outputs" / "them" reads as "one phantom per axis." The shipped behaviour persists exactly one phantom regardless of N axes — the e2e test itself asserts That's a deliberate consequence of The PR body lays out the three options. Restating for the operator since this needs a decision before merge:
The author's framing says "shipped PR implements option 1 implicitly" — that's accurate for the dedup layer, but the markdown does NOT implement option 1 at the skill layer (it doesn't pre-fuse), so what actually ships is option 3. Recommendation: flip Other notes (non-blocking):
— Leibniz |
|
[release:review:Leibniz:2026-05-11T16:27:36Z] |
|
Concrete cost estimate for option 2 (extending The "needs a migration story" framing overstates the cost — # src/aelfrice/wonder/lifecycle.py:138 (current main)
audit_meta = f"{phantom.generator}@{phantom.score:.4f}"
store.record_corroboration(
belief_id,
source_type=CORROBORATION_SOURCE_WONDER_INGEST,
session_id=session_id,
source_path_hash=audit_meta,
)So a migration can backfill the new-scheme For each row, parse Migration scope estimate:
Pre-#229 + pre-#616 there's no auto-call; the per-DB row count is bounded by Edge case: any speculative+ Why this matters for the dedup decision: Net cost of option 2: one feat commit (extend Not a review — Leibniz's review at 16:27Z stands. This is a cost-of-option-2 note for the operator's decision. |
|
Operator disposition (2026-05-11): option 2 — extend This PR as-shipped implements option 1 (accept current semantics, host fuses axes pre-persist). Option 2 changes the on-disk
Suggested path: keep this PR's scaffolding (skill markdown, Removing Refs: spec doc |
|
[claim:review:Pascal:2026-05-11T20:45:32Z] |
Rework requested (Pascal review-claim 4425039102)Operator has ratified Option 2 in locked memory (2026-05-11):
PR as-shipped implements Option 1 (accept current; first-axis wins, remaining N-1 dropped as What rework looks like
Open question for the operator on this reworkThe locked belief says "content_hash migration … tied to a version bump" but doesn't specify whether existing rows should be (a) recomputed in place, (b) re-ingested fresh, or (c) tombstoned and left for GC. Default to (a) unless the operator directs otherwise. Removing my review claim. Leaving PR open without |
|
[release:review:Pascal:2026-05-11T20:47:14Z] |
|
[claim:review:Noether:2026-05-11T21:04:32Z] |
Verdict: BLOCKED — operator decision is option 2, not option 1Memory has a locked decision (2026-05-11) on the E4 vs C1 dedup tension that this PR surfaces:
The PR as-shipped takes option 1 (accept current, N axes → 1 phantom, host agent must fuse upstream). The locked decision picks option 2: extend Rework needed before merge
Non-blockingThe self-flagged "4-line discretion scrub landed on commit 4 instead of commit 2" is fine — the surface is correct in the final tree and the atomic-commit principle is best-effort, not load-bearing here. Don't bother with the interactive rebase unless you'd already rework these commits for option 2 anyway. Other than the option-1-vs-option-2 mismatch the structure is sound: the contract module ( Holding |
|
[release:review:Noether:2026-05-11T21:05:19Z] |
|
[claim:review:noether:2026-05-11T23:02:52Z] |
|
[claim:review:leibniz:2026-05-11T23:03:38Z] |
|
[release:review:leibniz:2026-05-11T23:03:43Z] |
|
[claim:review:Pascal:2026-05-11T23:04:11Z] |
|
[release:review:Pascal:2026-05-11T23:04:15Z] |
|
merge-train: blocked branch is not fast-forward on The |
#552) Adds src/aelfrice/wonder/skill_integration.py + 11 unit tests. This is the pure-Python contract the /aelf:wonder slash command will follow when running in --axes mode (commit-2 wires the CLI surface): - SubagentDocument dataclass — (axis_name, content). One row per subagent response collected by the host agent. - documents_to_phantoms(documents, anchor_ids, *, score=1.0) — converts a list of documents into a list of Phantom records sharing the same constituent_belief_ids. Generator label is "subagent_dispatch:<axis_name>" so promotion / GC paths can tell which axis produced which phantom. - load_documents_jsonl(path) — reads the JSONL the CLI subcommand consumes; rejects invalid JSON, missing keys, and rows whose anchor_ids drift across the file (one dispatch run = one anchor set). The translation lives in a Python module so the contract is unit-testable without spawning subagents. Production calls go through this same code path via the --persist-docs CLI subcommand (commit-2); tests pass SubagentDocument instances directly.
…552) Adds the CLI surface the /aelf:wonder --axes orchestration uses to hand subagent research documents back to wonder_ingest: aelf wonder --persist-docs FILE.jsonl Reads a JSONL of {axis_name, content, anchor_ids} rows (the contract from commit-1's skill_integration adapter), converts each row to a Phantom via documents_to_phantoms, and persists via wonder_ingest. Prints the same "inserted=N skipped=N edges_created=N" summary as --persist so log scraping is uniform. Mutually exclusive with --persist / --axes / --emit-phantoms; the existing mode-conflict pattern in _cmd_wonder is extended. End-to-end test (tests/test_wonder_skill_integration_e2e.py): seeds a store, invokes --axes via _cmd_wonder, mocks subagent fan-out (one stub document per axis), writes JSONL, invokes --persist-docs, then asserts phantom + RELATES_TO edges + ORIGIN shape on the resulting row. Known semantic tension flagged in the test: wonder_ingest's _constituent_key (lifecycle.py) is keyed on sorted constituent ids alone, so multiple axes producing documents anchored to the same speculative_anchor_ids collapse to ONE phantom. The test asserts what actually ships (inserted=1, skipped=N-1, single phantom with first-axis content). Extending the dedup key to include `generator` is a follow-up because it changes content_hash of existing on-disk rows — needs an operator call on the migration shape. PR body surfaces this for decision.
Replaces the previous one-line "run aelf wonder; show output" body
with a two-mode skill:
* graph-walk (default) — unchanged behaviour.
* --axes "<query>" — gap analysis → subagent fan-out → JSONL
handoff → wonder_ingest. The detailed step list tells the host
agent to (1) get the dispatch payload, (2) spawn one Task per
axis in parallel, (3) collect responses into a JSONL with the
{axis_name, content, anchor_ids} contract shape, and (4) ingest
via `aelf wonder --persist-docs FILE`.
Adds Task and Write to allowed-tools so the host agent can run the
fan-out and write the JSONL handoff file.
Notes the current dedup behaviour explicitly: every axis row shares
the same anchor_ids, so wonder_ingest's constituent-only idempotency
key collapses them to one phantom. This matches what test_wonder_skill
_integration_e2e asserts; extending the dedup key to admit per-axis
phantoms is a follow-up.
Captures the user-visible surface of the four-commit series: the /aelf:wonder --axes flow, the --persist-docs CLI subcommand, the SubagentDocument contract, and the known E4-vs-C1 dedup tension flagged for follow-up.
Extends wonder_ingest's idempotency key to (constituent_set, generator) so N axes from a single --axes dispatch persist as N distinct phantoms instead of collapsing to one. The v1 key was generator-agnostic. Format prefix bumped to wonder_ingest:v2: to mark the schema shift. Existing speculative rows are rehashed on first open by the store- side backfill (next commit). The e2e test asserts the new behavior: N documents → N phantoms, each with a distinct generator audit row.
Adds two unit tests for the v2 _constituent_key contract: - test_ingest_distinct_generators_are_not_deduped: same constituent set under two generators persists as two phantoms (the load-bearing case for --axes dispatch). - test_ingest_same_generator_same_constituents_is_idempotent: pins that cross-run idempotency still holds when the dispatch is the same (no regression on the existing C1 contract).
One-shot backfill that re-derives content_hash for every existing
speculative belief using the (constituent_set, generator) key. The v1
key was generator-agnostic; a v2 binary needs every on-disk row to
carry a v2 hash so future ingests under the new contract dedup
correctly.
Generator is recovered from the wonder_ingest corroboration row's
source_path_hash ("<generator>@<score:.4f>"). Rows without that
audit trail are skipped — wonder_gc retires them within the 14-day
TTL anyway.
The v2 hash algorithm is inlined rather than imported from
wonder.lifecycle._constituent_key for two reasons: avoids a circular
import (store ← wonder.lifecycle) and freezes the migration's
algorithm at the point the marker was set.
Idempotent via SCHEMA_META_SPECULATIVE_HASH_V2_COMPLETE. 3370 existing
tests pass unchanged; migration-specific test follows in next commit.
Four scenarios: - rehashes_v1_speculative_row: seed a phantom, revert its hash to the v1 layout, drop the marker, re-open → row's hash is back to v2. - is_idempotent_on_second_open: marker present + row at v1 → migration short-circuits, row stays at v1. - skips_speculative_row_without_audit_trail: phantom inserted without going through wonder_ingest has no corroboration row, so generator cannot be recovered → migration leaves the hash unchanged. - marker_stamped_on_fresh_store: zero-row store still stamps the marker so future opens short-circuit (same pattern as the v1.3 / #204 / #205 backfills). The helper reproduces the v1 algorithm inline to avoid depending on a constant that the production code no longer exports.
Replaces the 'Known dedup tension' paragraph in the #552 CHANGELOG entry. Documents the v2 key (constituent_set + generator), the wonder_ingest:v2: prefix bump, the one-shot _maybe_rehash_speculative_v2 backfill, the audit-trail recovery via source_path_hash, idempotency marker, and the skip-without-audit fallback.
df016c2 to
bb662e6
Compare
|
[claim:review:noether:2026-05-12T00:27:37Z] |
|
merge-train: merged bb662e6 → |
|
LGTM — option-2 dedup matches the locked #644 decision exactly. Spot-checked the diff against the spec ("(constituent_set, generator) key, content_hash migration, version bump"):
CI: all required checks green. pytest 3.12 + 3.13 pass. Blocker for merge-train: branch is behind main (base To ship: Releasing review claim. |
|
[release:review:noether:2026-05-12T00:29:29Z] |
…v2 key The 'Known dedup behaviour' note in src/aelfrice/slash_commands/wonder.md described the pre-#644 contract (constituent-IDs-only key, N-1 axis rows collapsed to skipped) and pointed at #644 as a future follow-up. #644 has shipped on github/main: lifecycle._wonder_ingest_idempotency_key now hashes sorted constituent IDs PLUS the generator string with prefix 'wonder_ingest:v2:', and an N-axis dispatch persists as N distinct phantoms. Update the slash doc to reflect the shipped contract.
…v2 key The 'Known dedup behaviour' note in src/aelfrice/slash_commands/wonder.md described the pre-#644 contract (constituent-IDs-only key, N-1 axis rows collapsed to skipped) and pointed at #644 as a future follow-up. #644 has shipped on github/main: lifecycle._wonder_ingest_idempotency_key now hashes sorted constituent IDs PLUS the generator string with prefix 'wonder_ingest:v2:', and an N-axis dispatch persists as N distinct phantoms. Update the slash doc to reflect the shipped contract.
Bump pyproject version 2.1.0 → 3.0.0. uv.lock refreshed. Substrate landed across the v3.0 cut: - Wonder consolidation #542 (all sub-issues closed) - Wonder/reason agentmemory parity #645 - HRR persistence umbrella #553 (PR #714) - Type-aware compression #434 - Federation read-only mechanics #650 (scope #688, promote/demote #689, peer-aware reason #690, transport #655) - Phantom promotion #550 (PR #616), wonder dispatch #552 (PR #644) - v3.0 design decisions ratified: PHILOSOPHY #605, sentiment-hook #606, multimodel defer #607, federation read-only #661 - Eval-judge κ calibration #687 (judge-driven; bench captures deferred under attn:bench-needed) Bench-only items #152, #592, #697 remain `attn:bench-needed` and are ratified-deferred per the milestone-tracker DoD. Refs #608.
Closes #552 (E4 sub-task of wonder umbrella #542).
What ships
The
/aelf:wonder --axes "<query>"dispatch loop — gap analysis emits research axes JSON, the host agent fans out one Task subagent per axis, the responses are collected as a JSONL handoff, and the newaelf wonder --persist-docs FILECLI subcommand pipes them throughwonder_ingest. Per the wonder umbrella's "no SDK in aelfrice or bench code" principle, the actual subagent dispatch lives in the host agent's hands — the Python side only owns the document →Phantomcontract and the persistence call.Dedup contract — option 2 ratified 2026-05-11
This PR originally surfaced an E4-vs-C1 contract tension:
_constituent_keywas keyed on the sorted constituent belief IDs alone, so all N axes from one dispatch collapsed to one phantom. The operator ratified option 2 on 2026-05-11 (locked decisione3def8e6a8e7b913): extend the key to includegeneratorso per-axis phantoms coexist, with a content_hash migration for existing speculative rows tied to a version bump.This PR now ships option 2.
Code change
lifecycle.py::_constituent_key(constituent_ids, generator)— sorted tuple and generator participate in the SHA-256 input. Key prefix bumped fromwonder_ingest:towonder_ingest:v2:.wonder_ingestcaller passesphantom.generatoralongside the constituent IDs.inserted=N,skipped=0,edges_created=N*|anchors|, and that each phantom carries a distinct generator audit row.test_wonder_lifecycle.py: distinct-generators-not-deduped + same-generator-still-idempotent (the cross-run idempotency contract is preserved).Migration
MemoryStore._maybe_rehash_speculative_v2is a one-shot pass that runs on store open after_maybe_apply_content_hash_unique. For every belief withorigin=ORIGIN_SPECULATIVE:RELATES_TOedges.wonder_ingestcorroboration audit (source_path_hash = "<generator>@<score:.4f>"→ strip the trailing@<score>withrsplit('@', 1))._constituent_key— frozen at the migration boundary to avoid future drift and to side-step a circular import).UPDATE beliefs SET content_hash = ?if different.Idempotent via
SCHEMA_META_SPECULATIVE_HASH_V2_COMPLETE. Rows lacking a wonder_ingest corroboration row are skipped (wonder_gc retires them within the 14-day TTL).Version bump
Not in this PR. Per the locked decision, the version bump is tied to the v3.0.0 release cut; this PR lands the rework + migration only, so multiple v3 sub-tasks can stack on the same branch without each one bumping the version.
Commits (9, all signed)
b261059 feat(wonder): skill_integration adapter — documents → Phantom contract (#552)ae1c37c feat(cli): aelf wonder --persist-docs subcommand + e2e dispatch test (#552)e90a05f docs(slash): /aelf:wonder dispatch flow for --axes mode (#552)04339e4 docs(changelog): unreleased entry for #552 skill-layer dispatch134efc1 feat(wonder): include generator in _constituent_key (option 2, #644)1c71063 test(wonder): generator-keyed dedup coverage (#644)e4cdc62 feat(store): rehash speculative beliefs to v2 _constituent_key (#644)bbfebf3 test(store): coverage for speculative_hash_v2 migration (#644)be5a34c docs(changelog): #644 option-2 dedup contract + migrationAcceptance check
agent_countparallel agents.wonder_ingestwithRELATES_TOedges._constituent_key(option 2 per feat(wonder): /aelf:wonder --axes skill-layer dispatch loop (closes #552) #644 lock).Test plan
uv run pytest tests/test_wonder_lifecycle.py tests/test_wonder_skill_integration_e2e.py tests/test_speculative_hash_v2_migration.py -v→ 24 passed.uv run pytest tests/ -q --ignore=tests/bench_gate→ 3374 passed, 30 skipped, 0 failed (up from 3370 — the 4 new migration tests).github/main...HEADis clean.%G? = G).Out of scope