feat: five-domain coherence engine — quality, meaning, signal, investiture, frames (closes #8 #9 #10 #11)#14
Conversation
Adds the stdlib-only shared measurement envelope (domain, score_type, scores, frame, diagnostics) that every new domain noun (quality, signal, investiture, assess) will emit from day one. build_envelope/validate_envelope round-trip a valid envelope unchanged; every violation (missing key, non-dict scores, non-numeric score value, malformed diagnostic entry, etc.) raises the dedicated EnvelopeError with a machine-readable code. An absent frame is representable explicitly via frame=None (paired with a diagnostic) or the null_frame() helper dict — never a missing key. docs/envelope.md documents all five fields and the two-speed adoption rule: new nouns emit the full envelope; existing meaning verbs keep their pinned v0.5.0 shape and only gain additive top-level keys (domain, score_type, frame), with the scores-nesting migration deferred to an explicitly versioned future change. 20 new tests in tests/test_schema.py, all offline. Full suite: 146 -> 166 passed. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Add coherence/frames/{__init__.py,provenance.py} — build_frame() assembles
the frame provenance block (embedding_model, embedding_endpoint, anchor_set,
axis/axes, projection_method, score_type) for embedding-derived measurements.
embedding_model/embedding_endpoint are resolved at call time by reusing
coherence.meaning.embed's own COHERENCE_EMBED_URL/COHERENCE_EMBED_MODEL
resolution functions directly (not duplicated default literals), satisfying
t2's acceptance criterion that a monkeypatched env changes the emitted block
and defaults only appear when the env is unset.
Absent provenance re-exports coherence.schema.null_frame verbatim (asserted
via identity in tests) rather than reinventing the null-frame shape.
17 new offline tests in tests/test_frames_provenance.py; full suite 166 -> 183
passing.
Add coherence/signal as the source-agnostic series analysis layer's input contract. coherence/signal/schema.py defines the series shape (optional domain + ordered points; per point id/index/timestamp/values + optional per-point frame) and load_series(), a robust loader that normalizes into typed Series/SeriesPoint records plus a mutable diagnostics list. - values are arbitrarily named numerics (caller-defined, never enumerated); missing/null/non-numeric values and booleans are skipped WITH a diagnostic, never a crash. bool is not numeric. - per-point frames are surfaced on the normalized point and diagnostics is left appendable, so a later mixed-frame guard plugs in cleanly. - only top-level structural failure raises SeriesError (machine-readable code), mirroring coherence.schema.EnvelopeError. - series_from_meaning_trend() converts a real meaning-trend result into a valid series dict, proving source-agnosticism (same loader as hand-written). - documented in docs/signal-series.md, referenced from the module docstring. Tests: tests/test_signal_schema.py (37 tests, fully offline; the trend JSON is built by driving the real trend engine with the synthetic embed_fn over the recorded series fixtures). Full suite 166 -> 203, green. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
First honest implementation of the "quality" coherence domain: fully offline, deterministic, rule-based scoring of freshness/provenance/fidelity. Emits the shared measurement envelope (coherence/schema.py) with domain=quality, score_type=rule_based_heuristic, and an explicit null-frame (rule_based_no_embedding_frame) — never a fabricated embedding frame. Honesty contract: - diagnostics NAME what rules could not verify (source_liveness_unverified, publication_date_unverified, quote_accuracy_unverified); - absent signals lower per-component confidence with a diagnostic (no_dateable_statements / no_source_attribution / no_verbatim_signal), never fabricating a score; - confidence is visible in the scores map as <component>_confidence. - coherence/quality/heuristics.py: rule-based detectors + component scorers - coherence/quality/score.py: assess() raw breakdown + score_text() envelope - tests: 43 new, fully offline (socket-blocked fixture proves zero network) Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Implement coherence/quality/compare.py mirroring the shape of coherence/meaning/compare.py: before/after full quality envelopes plus a delta map with signed floats for all score components (freshness, provenance, fidelity and their _confidence entries). Delta = after - before for each component. - Fully offline: reuses score_text engine, threaded with reference_date - Open component registry: delta keys mirror scores map keys - Comprehensive test suite: 13 tests covering shape, delta arithmetic, edge cases, socket blocking (zero network access), and string/Path handling All 276 tests pass (263 existing + 13 new). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Add coherence/signal/collect.py with shape-driven extraction that builds valid series from N measurement JSONs of any domain (meaning, quality, investiture). Extraction rule: if measurement has dict-valued `scores` → extract those (full envelope path); otherwise harvest numeric leaves generically (top-level numeric keys + numeric entries from any top-level dict like subdimensions). API: - collect(measurements: list[Mapping], *, ids: list[str] | None = None) -> dict - collect_files(paths: list[str]) -> dict Output per point: id, index, timestamp (None), values (extracted numerics), frame (carried from measurement verbatim or None). Series-level domain: set when all inputs agree on one domain string, else None (no error). Zero numeric leaves in an input → raises SeriesError with code "collect_no_numeric_values" (matches schema error convention). All 25 new collect tests pass; full suite 288 tests green. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Add coherence/signal/resonance.py: pairwise Pearson alignment between a series' numeric fields, reported as ONE signed metric. Positive alignment is labeled "resonance" (streams reinforce), negative is "interference" (streams conflict) — both derived from the sign of the same computation, never two separate code paths. A neutral band (NEUTRAL_BAND = 0.1) around zero labels weak alignment as neither. Pairs with fewer than MIN_COMMON_POINTS (3) shared points, or with a constant (zero-variance) field, are excluded with a diagnostic rather than producing a NaN or fabricated correlation. A defensive non-finite-result guard (CODE_NON_FINITE_CORRELATION) covers any other source of a non-finite value. Tests (tests/test_signal_resonance.py, 15 new, offline/numpy-only) cover sign-carries-meaning (co-rising -> resonance, co-falling -> interference, sign-symmetry under negation), exact +-1 correlation cases, the neutral band, and every exclusion path (too-few-points, one/both constant fields, disjoint fields, NaN-poisoned values bypassing the loader).
Add coherence/signal/pattern.py: motif detection over a loaded Series, per numeric field. Six motifs (increasing, decreasing, plateau, spike, reversal, stair_step), each a deterministic, tolerance-gated rule against the field's own observed range — no learned/tuned parameters. Sparse fields are analyzed over their present values only (gaps get a diagnostic, never interpolated); series/fields with fewer than 3 usable points get an explicit insufficient-points diagnostic instead of motifs. tests/test_signal_pattern.py covers all 6 motifs on synthetic + counterexample series (12+ assertions), short-series guards, sparse-field gaps, per-field insufficiency, multi-field independence, and JSON-serializability.
Score/compare/trend JSON gains three ADDITIVE top-level keys — domain, score_type, frame — while every pre-existing key stays byte-identical (the two-speed envelope rule; docs/envelope.md). meaning keeps its pinned v0.5.0 shape and only grows. - score.py: DOMAIN/SCORE_TYPE constants; meaning_frame() resolves the frame from the runtime embed config at call time via frames.provenance.build_frame (axes = meaning + the five subdimensions); score() = clean v0.5.0 core (_score_v050) + the three keys; offline_result() is the offline-diagnostics path — an explicit null_frame (code embed_endpoint_unreachable), never a fabricated frame. score() still raises EmbedUnavailable (exit-2 path unchanged). - compare.py: one shared top-level frame; before/after stay clean v0.5.0. - trend.py: one shared top-level frame added; difference math untouched. - CLI unchanged (it dumps the engine dict verbatim in --json mode). - New tests/test_meaning_envelope_keys.py (9): runtime-resolved frame, golden subset byte-identity on recorded vectors, offline null-frame. - Narrow additive-tolerance relaxations to existing meaning shape assertions. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Point coherence/meaning/trend.py's f'/f'' differencing at the generic coherence.signal.trend.first_difference / second_difference functions so meaning trend is a dimension-specific wrapper (embed, label, assemble) rather than a private reimplementation. Output is byte-identical: pinned via full-result JSON goldens captured from the pre-refactor code (recorded-vector + synthetic-embed series) in the new tests/test_meaning_trend_delegation.py. Removed the private _first_difference and _slot helpers; retained _cosine_distance (drift distance), _second_unavailable_reason (labeling), and the _derivatives_from_* helpers (imported by test_meaning_envelope_keys). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Add coherence/investiture/{__init__,score,compare}.py: the MVP measures
estimated micro-investiture (meaning that becomes causal, issue #8) as
meaning_score * agency * future_constraint * affordance, reusing
coherence.meaning.score.score() for every embedding/axis computation
(no duplicate embed path, same EmbedUnavailable exit-2 behavior).
score() output satisfies both the shared measurement envelope (domain,
score_type, scores, frame, diagnostics) and the issue-#8 JSON contract
(investiture_score, mode="estimated", components with the unmeasured
persistence_signal/integration_signal/behavioral_effect explicit nulls,
evidence) in one dict, since validate_envelope tolerates extra
top-level keys. compare() mirrors quality/compare.py's shape: before/
after are full score() results (each independently validating as an
envelope, frame passed through verbatim from meaning), delta is a
signed investiture_score plus the four numeric component deltas.
34 new tests in tests/test_investiture_{score,compare}.py, fully
offline via the shared synthetic hash embedder; full suite 423 -> 457
green.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Adds coherence/assess.py: one verb (assess) that runs every applicable
domain (quality, meaning, investiture) against an artifact and returns a
single report. assess itself ships the full shared envelope (domain,
score_type, scores={}, frame=None, diagnostics) per the two-speed adoption
rule for new nouns, with domains/unavailable/artifact layered on top.
Quality always runs offline. Meaning/investiture need the embedding
endpoint; when it's down, both are listed in `unavailable` with a
machine-readable code + reason (investiture is skipped rather than
re-attempted, since it derives from meaning), and meaning's offline
rule-based diagnostics are still surfaced under
unavailable["meaning"]["offline_diagnostics"] — partial availability is a
normal, honest result, never silently dropped.
tests/test_assess.py adds 19 fully-offline tests (synthetic embed_fn) for
both acceptance criteria: endpoint down (quality + offline diagnostics,
meaning/investiture unavailable with reasons) and endpoint up (all three
domains present, unavailable empty). Full suite: 490 -> 509 passing.
…n catalog Wires the five merged domain engines into the CLI, mirroring the existing meaning noun's pattern: quality (score/compare), signal (trend/pattern/ resonance/forecast/collect), investiture (score/compare, sharing meaning's EmbedUnavailable exit-2 path), frames (inspect/diff, where absent/partial provenance is a normal exit-0 result), and assess (a global verb; partial domain availability is exit 0, never an error). Extends the explain catalog with an entry per new noun/verb plus the eight frame-vocabulary concept terms, and extends cli overview/learn to list all five domains. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
…n touch-up) Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Deliverable 1 (tests/test_additive_compatibility.py): additive-only pre/post
diff proof. meaning score/compare/trend, driven offline with the synthetic
embedder, have {domain, score_type, frame} stripped and the remainder asserted
byte-identical to an independent v0.5.0 reconstruction; before/after and
per-point blocks carry no new keys. Scaffold verbs (whoami/learn/explain/
overview/doctor/cli overview) pin their established --json key sets unchanged.
Deliverable 2 (tests/test_five_domain_structure.py): a package home per domain
(quality/meaning/signal/investiture/frames + assess/schema) is importable;
quality/signal/investiture/frames/assess are registered CLI nouns (top-level
help, -h, explain); and the offline nouns never dial the embed endpoint
(localhost:8002) — proven by a socket guard plus the green offline suite.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
|
/agentic_review |
Code Review by Qodo
Context used✅ Tickets:
🎫 Implement Meaning Gradient MVP per converged plan — 10 tasks, 6 waves (continuation of #4)✅ Compliance rules (platform):
5 rules✅ Skills:
doc-test-alignment 1.
|
…ldens float-tolerant across CPU/BLAS (structure still exact) The golden literals were captured pre-refactor and reproduced byte-for-byte on the capture machine; CI CPUs shift the last float ulp, so the assertion is now a deep compare — exact keys/strings/nulls, floats at 1e-9 rel tol. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
…d in previous commit) Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
PR Summary by Qodofeat: five-domain coherence engine (quality, meaning, signal, investiture, frames)
AI Description
Diagram
High-Level Assessment
Files changed (71)
|
- merge implicit string concatenations (S5799) in overview/quality CLI verbs - constants for duplicated literals in signal CLI (S1192) - drop redundant JSONDecodeError from except clause (S5713) - split validate_envelope and _extract_values into per-field helpers to cut cognitive complexity below the threshold (S3776); codes, messages, and extraction semantics unchanged (suite-pinned) Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
1. Recorded vectors gain a model tie-out (Qodo #1): recorded_vectors.json is now {metadata, vectors} — the refresh script stamps the embedding model/ endpoint it actually ran against, the committed fixture is wrapped post-hoc with its known 2026-07-04 provenance (vector values unchanged), and the loader exposes load_recorded_metadata() with legacy-format fallback. 2. --json placement no longer matters (Qodo #2): verb-level --json flags use default=argparse.SUPPRESS via a shared helper so they never clobber a noun-level --json; applied to all six noun groups including meaning. 3. signal collect rejects non-object measurements (Qodo #3): valid JSON that is not an object raises SeriesError(collect_measurement_not_an_object) naming the offending file — exit 1, never an AttributeError. 4. Duplication: the per-noun file-error guard, remediation strings, and reference-date parsing move to cli/_commands/_artifact_io.py; the five noun modules keep only their domain-specific branches. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
|
FIX — commit 4519b36. The recording now carries the model tie-out:
|
|
FIX — commit 4519b36, exactly as suggested: verb-level
|
|
FIX — commit 4519b36.
|
…ity 17 -> under 15) Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk
|



What
The five-domain coherence engine, built per the converged spec + plan merged in #13. Implements #11 (restructure), #9 (signal), #8 (investiture), #10 (frames provenance), plus the user-approved additions (quality MVP, forecast, assess, signed resonance, frames inspect/diff + mixed-frame guard, signal collect). v0.5.1 → v0.6.0, 146 → 665 tests, all offline in CI.
Built via
/assign-to-workforce: 18 tasks across 7 dependency waves, one agent per task in isolated worktrees, every merge TDD-gated (full suite green before and after). Zero merge conflicts — the plan's file-disjoint waves held.The five domains
quality score/comparemeaning score/compare/trenddomain/score_type/framekeyssignal trend/pattern/resonance/forecast/collectinvestiture score/comparemode: estimated, unmeasured components explicitly nullframes inspect/diffPlus
coherence assess <file>— one multi-domain report with per-domain availability honestly reported (embed endpoint down ⇒ quality still answers, meaning/investiture listed unavailable, exit 0).Compatibility (the merge gate)
domain,score_type,scores,frame,diagnostics—docs/envelope.md); meaning outputs gained only additive keys. Proven by golden tests (tests/test_additive_compatibility.py): stripping the three new keys yields the v0.5.0 shape byte-identically.colleague/coherence.pypasses unknown payload keys through verbatim (_KNOWN_PAYLOAD_KEYS+ pass-through loop), its tests assert subset-style, andtest_unknown_payload_keys_pass_through_verbatimexplicitly injects aframekey (colleague PR #298, merged). Optional colleague-side follow-up: refresh_LIVE_PAYLOADfrom a 0.6.0 run.signal.trend's functions, and a source-level test asserting the old helpers are gone.Verified live
Smoke-tested end-to-end against the local embed gear: the emitted frame block reports the actual runtime endpoint (
http://localhost:8001/v1, not the hardcoded default) — the h9 honesty condition observed in the wild. Offline: quality → collect → trend pipeline works; forecast's minimum-points guard exits 1 with hint on a 2-point series;frames inspectreportsabsentwith a machine-readable reason on a rule-based measurement.Docs
README repositioned around the five domains (claim quality named the first practical domain, not the whole product),
docs/domains.md+docs/envelope.md+docs/signal-series.md, explain catalog +19 command paths +7 frame-vocabulary concepts, and a banned-terms language test keeping the docs to model-relative, anchor-defined framing.Deferred (documented as planned extensions, not built)
Harmonic/wave/decay analyses (#9), gauge-robustness checks (#10), investiture trace (#8), experiment runner / doctor / certify / LLM-judge / routing output (#4/#6), freshness half-life prediction.
Closes #8. Closes #9. Closes #10. Closes #11.
🤖 Generated with Claude Code
https://claude.ai/code/session_01SmwUt5WBBbrUc1vt2RdQYk