Commit graph

23 commits

Author SHA1 Message Date
Shay
2a2ef9ce49
perf(salience): vectorize curvature pairwise loop — 57× faster, 42% e2e (#96)
cProfile attribution (2026-05-21) identified
``core.physics.salience.SalienceOperator.compute`` as 64% of total
``ChatRuntime.chat()`` time.  Pre-fix it was a nested Python loop
over ``regions × regions`` with one ``np.linalg.norm`` call per
pair.  For N≈500 mounted-vocab regions per turn that meant ~250k
norm calls per turn, dominating end-to-end latency.

Fix: numpy broadcast for pairwise displacement, distance,
pressure-delta, and contribution.  Same math; same contract.
ULP-level reassociation drift is absorbed by the 12-decimal
precision ``_salience_address`` already used for content
addressing, and by the float32 conversion at the downstream
``SalienceMap.scores_arr`` site, so neither the content_address
nor the top-k ordering changes.

Measurements (region set: N=493, dim=5, seeded):

  vectorized:  11.78 ms/call
  old-loop:   672.30 ms/call
  speedup:    57.1×

End-to-end on 8 cognition-shape prompts:

  pre-fix:  ~970 ms/turn
  post-fix:  565 ms/turn   (-42%)

Validation:

  * 15 new tests in ``tests/test_salience_vectorize_parity.py``:
      - parity with a nested-loop reference to 1e-9 absolute on
        curvature_magnitude, gradient_vector, influence_radius
        across N ∈ {1, 2, 8, 32, 128, 493}
      - content_address byte-identical across N ∈ {1, 8, 32, 128}
      - top-16 ordering matches the reference at N ∈ {32, 128, 493}
      - empty regions returns empty map
      - single region has zero curvature
  * ``core eval cognition`` byte-identical: public 100/100/91.7/100.
  * ``core test --suite cognition`` 120/0/1, ``smoke`` 67/0.

The file's pre-existing docstring promised a Rust path
(``core_rs::physics::salience::compute_curvature``) that does not
yet exist — the numpy vectorization realizes the lift now while
keeping the Rust port a future optimization on stable semantics
(CLAUDE.md: "Rust backend parity only after Python semantics are
locked by tests").
2026-05-20 21:29:42 -07:00
Shay
8e96728009 feat(telemetry): ADR-0078 Phase 1 — composer/graph atom equivalence (observational)
Wires observational telemetry on the composer-vs-graph atom-set
relationship.  Phase 1 is strictly observational: no enforcement,
no surface mutation, no grounding-source change, no trace-hash impact.

New telemetry fields on TurnEvent + ChatResponse:
  composer_graph_atom_status         ∈ {equivalent, divergent,
                                         graph_unconstrained,
                                         composer_no_atoms,
                                         not_applicable, ""}
  composer_atom_set_hash             SHA-256 over sorted unique atoms
  graph_atom_set_hash                SHA-256 over sorted unique atoms
  composer_graph_atom_overlap_count  int

Composer atoms come from existing pack candidate metadata
(pack_semantic_domains channel through _maybe_pack_grounded_surface).
Graph atoms come from build_graph_from_input + resolve_lemma on
node.subject/predicate/obj — no prose parsing.  When a grounded
composer path lacks explicit atom provenance, status is
'composer_no_atoms'.

New pure helper:
  chat/atom_equivalence.py — normalize_atoms, hash_atoms,
  atoms_for_graph_nodes, compare_atom_sets

Tests (tests/test_composer_graph_atom_equivalence.py):
  - Pack DEFINITION path produces observable equivalence
  - Divergent atom sets produce distinct hashes
  - Register invariance: atom hashes + status identical across
    {neutral, terse, convivial}; trace_hash also constant (R5 axis)
  - Anchor lens engaged case still ASCII-only on surface
  - No prose-parsing helper symbols introduced in runtime.py
    (extract_candidate_surface_lemmas, surface_lemma,
    parse_surface_atoms) — enforces Phase 1 boundary

Performance note: build_graph_from_input now runs on every warm
English turn (previously only when forward_graph_constraint=True).
Phase 1 accepts this cost to make the telemetry universally
available; Phase 2+ can introduce a feature flag if needed.

Validation:
  - Cognition eval byte-identical: 100/100/91.7/100
  - Full lane: 2864 passed, 3 skipped, 0 failed (+5 over baseline)
  - Targeted lane: 72 passed in tests/test_{graph_constraint,
    pack_grounding,register_tour_demo,anchor_lens_tour_demo,
    orthogonality_tour_demo,realizer_guard_holdout,
    composer_graph_atom_equivalence}.py
2026-05-20 06:14:25 -07:00
Shay
5a78b0e37b feat(register): ADR-0077 — substantive register knobs + layering boundary (R6)
R5 (ADR-0072) shipped the register *machinery*; ADR-0074's orthogonality
tour proved the axis was decoratively orthogonal to anchor-lens but
inspection of the cognition-eval surfaces revealed two structural gaps:

* On pack-grounded DEFINITION/RECALL/COMPARISON composers, the only
  realizer override any register consumed was `disclosure_domain_count`
  — which only fires on the no-gloss disclosure path.  Under terse_v1,
  every gloss-DEFINITION cell was byte-identical to default_neutral_v1.
* The register-tour's `surfaces_vary_at_least_once` gate could be
  satisfied by convivial's decorative wrapper alone, masking that
  regression in CI.

R6 closes both:

Layering separation (the load-bearing fix):
* New TurnEvent/ChatResponse field `register_canonical_surface` carries
  the composer output BEFORE any register transformation.  The pipeline
  hashes this field for `trace_hash`, preserving R5's invariant that
  per-prompt trace_hash is CONSTANT across registers even while
  substantive transforms produce visibly different surfaces.

Substantive transforms (`chat/register_substantive.py`):
* terse_v1 gains 3 bool knobs: `drop_provenance_tag`, `compress_gloss`,
  `drop_articles` — all pure regex transforms on the canonical surface.
* convivial_v1 gains `append_semantic_domain_clause` — appends a single
  bounded "Related: <atom>." clause using the lemma's pack atoms.
* default_neutral_v1 leaves overrides empty; substantive transform is
  byte-identical no-op (preserves `byte_identity_null_lift`).
* C1 (ADR-0075) safety preserved: drop_articles refuses to drop
  articles following `not` (avoids R3 violations); no knob combination
  trips R2/R3.

Strengthened tour gate (`evals/register_tour/run_tour.py`):
* Replaces `surfaces_vary_at_least_once` with two falsifiable claims:
  - `terse_substantively_differs_from_neutral_on_pack_grounded_definition`
  - `convivial_substantively_differs_from_neutral_on_pack_grounded_definition`
  Both restrict to DEFINITION+pack-grounded cells and require
  difference beyond whitespace/punctuation.
* New claim `register_canonical_surfaces_identical` directly proves
  the layering separation.
* Preserves R5's `all_grounding_sources_identical` +
  `all_trace_hashes_identical`.

Pack ratification:
* Loader widened to accept `bool` for closed-set R6 keys
  (drop_provenance_tag / compress_gloss / drop_articles /
  append_semantic_domain_clause).
* `_KNOWN_OVERRIDE_KEYS` ratify gate extended with same.
* terse_v1 + convivial_v1 reratified with new knobs; companion
  mastery reports re-sealed.  default_neutral_v1 unchanged.

Invariants pinned:
* `invariant_register_canonical_surface_constant_across_registers` (new)
* `invariant_terse_substantively_distinct_from_neutral` (new)
* `invariant_convivial_substantively_distinct_from_neutral` (new)
* `invariant_realizer_no_illegal_articulation` (C1, preserved)
* `invariant_realizer_guard_byte_identity_on_currently_passing_cases`
  (C1, preserved)

Verification:
* `core eval cognition`: 100.0% / 91.7% / 100.0% / 100.0% — byte-
  identical under default_neutral_v1.
* `core demo register-tour`: all 5 claims green, exit 0.
* `core demo anchor-lens-tour`: green (no anchor-lens code touched).
* `core demo orthogonality-tour`: green (5/5 claims).
* Full lane: 2858 passed, 1 pre-existing failure
  (test_all_preamble_explains_combined_run, carried forward
  unchanged from main).  56 new R6 tests across three files.
2026-05-19 23:39:11 -07:00
Shay
7cc2888ed2 feat(coherence): ADR-0075 — realizer slot-type guard (C1)
C1 coherence floor: a deterministic verifier that runs on every
candidate surface produced by the truth path, before assignment to
ChatResponse.surface.  Rejects illegal articulations and routes them
to a bounded disclosure string — admission control with a
deterministic fallback, not normalization.

Active rules (R1 deferred during ratification — see ADR):
  R2_aux_neg_requires_verb     — "<aux> not <wrong-POS>"  rejected
  R3_be_neg_requires_predicate — "<be>  not <verb>"       rejected

Fail-open on unknown POS, fail-closed on explicit wrong POS.
Cognition eval byte-identical (100/91.7/100/100).

Original bug class — "Light reveals truth, right?" → "Right does not
thought." — now routes to "I do not have a reviewed articulation for
that yet." with grounding_source=none, walk_surface preserving the
rejected candidate, and telemetry carrying R2_aux_neg_requires_verb.

Files:
  generate/realizer_guard.py            NEW — pure verifier
  chat/runtime.py                       hook on stub + main paths
  chat/telemetry.py                     serialize guard fields
  core/physics/identity.py              TurnEvent +2 fields
  evals/realizer_guard/run_holdout.py   NEW — 6-prompt cluster
  tests/test_realizer_guard_*.py        NEW — 46 tests (unit/seam/holdout)
  docs/decisions/ADR-0075-*.md          NEW — ratified

Invariants pinned:
  invariant_realizer_no_illegal_articulation
  invariant_realizer_guard_byte_identity_on_currently_passing_cases

Lanes (excluding 1 pre-existing TestDemoPreambles failure unrelated
to C1, already present at 4426f38):
  smoke 67/67  cognition 120/120(+1s)  teaching 17/17
  packs 6/6   runtime 19/19   algebra 132/132   full 2792/2793
2026-05-19 22:35:09 -07:00
Shay
1feec74b1c feat(anchor_lens): ADR-0073d — L1.4 telemetry, CLI flag, tour demo
L1.4 closes the anchor-lens inside-out arc (L1.1→L1.4 mirroring
R1→R5).  Substantive axis is now operator-observable,
operator-driven, and demo-falsifiable — exactly what R5 did for
the register subsystem.

Telemetry extension
  - TurnEvent + ChatResponse gain anchor_lens_id +
    anchor_lens_mode_label (both default "" → pre-L1.4
    byte-identical).
  - serialize_turn_event surfaces both fields in every JSONL line.
  - Mode-label extracted via _ANCHOR_LENS_ANNOTATION_RE from the
    PRE-decoration surface (so register decoration cannot interfere
    with anchor-lens telemetry).  Composer remains the sole source
    of truth for engagement; the runtime helper is read-only.

Operator surface
  - core chat --anchor-lens <id> CLI flag threads into
    RuntimeConfig.anchor_lens_id.
  - Invalid id → AnchorLensError caught at cmd_chat and surfaced
    as _die("invalid --anchor-lens pack id: ...", code=2) before
    the REPL launches.
  - Composes with --register (both flags wire through
    _runtime_config_from_args).

Narrative demo
  - evals/anchor_lens_tour/run_tour.py walks 2 prompts × 3
    ratified lenses ({default_unanchored_v1, grc_logos_v1,
    he_logos_v1}).  Asserts four claims:
      * lens_ids_recorded_per_turn
      * trace_hashes_distinct_across_lenses (OPPOSITE of
        register-tour's identical-hash claim)
      * surface_propositions_distinct_across_lenses
      * no_substrate_glyph_leak (block-scoped Greek/Hebrew/
        Syriac/Arabic; stylistic punct allowed)
  - Exit code 0 iff all four hold.
  - Bundled into `core demo` choices + EPILOG.

Tests (30 new)
  - tests/test_anchor_lens_telemetry.py (16) — TurnEvent shape,
    serializer keys, runtime emits per lens / per engagement
    state, ChatResponse mirrors event, mode-label extractor unit.
  - tests/test_anchor_lens_cli.py (9) — _runtime_config_from_args
    threading, invalid id fail-fast, parser flag wiring, parser
    composes with --register.
  - tests/test_anchor_lens_tour_demo.py (9) — four seam claims
    pinned individually + all_claims_supported + per-cell
    anchor_lens_id + unanchored cells empty mode + engaged cells
    carry mode label.

Lane evidence
  - 30 new L1.4 tests pass.
  - core demo anchor-lens-tour --json → all_claims_supported: True.
  - core demo register-tour --json    → all_claims_supported: True.
    Both tours pass simultaneously — orthogonality CI-pinned.
  - python -m core.cli eval cognition → public 100/100/91.7/100
    byte-identical (lens=None / default_unanchored_v1).
  - Full lane: 2736 passed / 4 skipped / 1 pre-existing failure
    (+30 over L1.3's 2706; the one failure remains
    test_all_preamble_explains_combined_run, unrelated).

Live demo (canonical proof)
  P1: 'What is knowledge?'
    default_unanchored_v1  trace=17c9aabe…  mode=(none)
    grc_logos_v1           trace=0198ad4c…  mode=systematic
    he_logos_v1            trace=17c9aabe…  mode=(none)
  P2: 'What is truth?'
    default_unanchored_v1  trace=2557f3e8…  mode=(none)
    grc_logos_v1           trace=2557f3e8…  mode=(none)
    he_logos_v1            trace=ec8d84aa…  mode=covenant-verity

  Engagement is substrate-scoped: grc never touches truth, he
  never touches knowledge.  Trace hashes diverge exactly where the
  lens engages.

Trust boundaries
  - --anchor-lens flag does not bypass ratification; loader still
    enforces companion mastery report self-seal + ratify-time
    substrate-atom existence check (ADR-0073b/c).
  - Mode-label extraction is read-only regex parse; can't forge
    annotations the composer didn't emit.
  - Telemetry stays redact-safe — both fields are identifiers /
    mode labels, not content.  include_content=False emits them
    unconditionally.
  - No new mutation surface; pack files unchanged.

Closes the anchor-lens inside-out arc
  L1.1  content prerequisite                  ✓ (ADR-0073a)
  L1.2  class + loader + unanchored sentinel  ✓ (ADR-0073b)
  L1.3  first lenses + composer wiring        ✓ (ADR-0073c)
  L1.4  telemetry + CLI + tour demo           ✓ (this commit)

  Mirrors the R1→R5 register cadence exactly.  Both axes are now
  operator-observable, CI-falsifiable, audit-traceable, and
  composable via the orthogonality claim pinned in both tours.
2026-05-19 20:21:41 -07:00
Shay
7f0bad3e20 feat(register): R5 — operator-visible register telemetry + tour demo
ADR-0072 ratified + implemented.  Closes the register subsystem
inside-out arc (R1 ADR-0068 → R5 ADR-0072): the presentation axis is
now operator-visible, CI-falsifiable, and audit-traceable.

Telemetry extension
  - TurnEvent + ChatResponse gain register_id + register_variant_id
    (12-char SHA-256 prefix of selected (opening, closing) pair;
    empty string for UNREGISTERED / no-decoration registers).
  - serialize_turn_event surfaces both fields in every audit JSONL
    line.  Pre-R5 callers stay byte-identical (defaults are "").

Decoration result widened
  - chat/register_variation.py: decorate_surface now returns
    DecorationResult(surface, opening, closing, variant_id).
  - decorate_surface_str alias preserves the pre-R5 string-only API
    for off-runtime callers.
  - chat/runtime.py updated at both call sites (stub + main).

Operator surface
  - core chat --register REGISTER_ID threads into
    RuntimeConfig.register_pack_id via _runtime_config_from_args.
  - Invalid id ⇒ RegisterPackError caught at cmd_chat and surfaced
    as a clean _die(...) before the REPL launches.

Narrative demo
  - evals/register_tour/run_tour.py walks 4 prompts × 3 ratified
    registers ({default_neutral_v1, terse_v1, convivial_v1}) and
    asserts three load-bearing seam claims:
      * all_grounding_sources_identical
      * all_trace_hashes_identical (ADR-0069 invariant C, falsifiable)
      * surfaces_vary_at_least_once (ADR-0071 seeded variation lift)
  - core demo register-tour exit code = 0 iff every claim holds.

Tests
  - tests/test_register_telemetry.py (6) — TurnEvent default,
    serializer keys, runtime emits register_id/variant_id for
    convivial/terse/unregistered, ChatResponse mirrors event fields.
  - tests/test_register_cli.py (7) — _runtime_config_from_args
    threading, invalid-id fail-fast, parser wires --register.
  - tests/test_register_tour_demo.py (7) — three seam claims pinned
    individually + all_claims_supported + per-cell register_id +
    variant_id discipline (empty for neutral/terse, non-empty for
    convivial).
  - tests/test_register_variation.py extended (4 new) — DecorationResult
    shape, decorate_surface_str alias, variant_id stability,
    bijection between non-trivial marker pairs and variant_ids.

Lane evidence
  - Full lane: 2632 passed / 4 skipped / 1 pre-existing failure
    (tests/test_cli_demo.py::test_all_preamble_explains_combined_run,
    unrelated to R5).
  - Cognition eval byte-identical: public 100 / 100 / 91.7 / 100.

Trust boundaries (per CLAUDE.md)
  - --register flag does not bypass ratification; loader validates the
    pack id through _find_pack and the ratify gate at load time.
  - variant_id is content-addressed; no raw markers leak into audit.
  - Telemetry stays redact-safe — register_id and variant_id are
    identifiers, not content, so include_content=False emits them
    unconditionally.
  - No new mutation surface; pack files on disk are not modified.
2026-05-19 19:03:07 -07:00
Shay
c6ade6c76f feat(adr-0052): teaching-grounded CAUSE/VERIFICATION surface 2026-05-18 07:13:43 -07:00
Shay
c28e107dc7 feat(adr-0048): pack-grounded surface for cold-start DEFINITION/RECALL
Closes the surface-grounding gap isolated by ADR-0047's
characterisation.  Adds the ratified cognition pack as a second
grounding source alongside the session vault.

== chat/pack_grounding.py (new) ==

Loads en_core_cognition_v1's lexicon once (cached; immutable pack)
and exposes:

  pack_grounded_surface(lemma) -> str | None

Returns a deterministic, fully pack-sourced surface:

  "{lemma} — pack-grounded ({pack_id}): {d1}; {d2}; {d3}. No session evidence yet."

Every visible atom is the lemma or a verbatim semantic_domains
string from the pack.  No rewording, no synthesis, no LLM.

== chat/runtime.py ==

_stub_response gains optional pack_grounded_surface= parameter.
_maybe_pack_grounded_surface routes to the pack only when all four
hold: gate_source=="empty_vault", output_language=="en",
intent.tag in {DEFINITION, RECALL}, and intent.subject is a pack
lemma.  Safety/ethics refusal still takes priority above this branch.

ChatResponse and TurnEvent gain grounding_source ∈ {vault,pack,none}.
Main walk path tags responses "vault".

== core/cognition/pipeline.py ==

gate_fired detection moved from string equality on the universal
disclosure to provenance:

  gate_fired = response.vault_hits == 0 and response.grounding_source != "vault"

Same intent (suppress realizer template on gate-fired turns),
broader stub-path surface set.

== Characterisation (core eval cognition, 13-case public split) ==

  Metric                  Pre        Post     Δ
  intent_accuracy        100.0%     100.0%    0
  surface_groundedness    15.4%      46.2%   +30.8 pp
  term_capture_rate        0.0%      33.3%   +33.3 pp
  versor_closure_rate    100.0%     100.0%    0

Lift is non-uniform by design: only single-lemma DEFINITION/RECALL
on pack-known English subjects engage.  CAUSE/COMPARISON/VERIFICATION
and multi-word OOV subjects still return the universal disclosure —
fabricating those would violate the no-LLM-fallback doctrine.

== Tests ==

  tests/test_pack_grounding.py                          18 passed
  tests/test_semantic_realizer_integration.py (updated) 1 stub-path test
    pinned to the broader contract: surface is either universal
    disclosure or pack-grounded; never the realizer template.

== Lanes ==

  smoke 67  cognition 121  runtime 19  algebra 132
  teaching 17  packs 6

versor_condition(F) < 1e-6 invariant unaffected (no algebra changes).
2026-05-18 06:36:10 -07:00
Shay
f3cc408f82 feat(adr-0039): audit completeness — TurnVerdicts bundle, stub TurnEvent, hedge_injected
Closes three audit gaps left by the ADR-0035→ADR-0038 pack-layer
surface:

1. TurnVerdicts bundle (chat/verdicts.py) — frozen dataclass
   aggregating identity_score + safety_verdict + ethics_verdict +
   refusal_emitted + hedge_injected.  Attached to both
   ChatResponse.verdicts and TurnEvent.verdicts.  Fields typed as
   object for the same module-coupling reason as
   TurnEvent.safety_verdict.

2. Stub-path TurnEvent emission — _stub_response accepts optional
   tokens kwarg and appends a TurnEvent to turn_log when invoked
   from a real turn.  Audit consumers can now iterate turn_log
   end-to-end without missing stub paths.  Defensive call sites
   (correct() fallback) bypass the append by omitting tokens.

3. refusal_emitted / hedge_injected flags — runtime tracks whether
   it actually mutated the surface this turn.  hedge_injected uses
   idempotent-on-prefix semantics (True iff the runtime ADDED a
   hedge, not iff a hedge happens to be present).

Test-pattern note: previous "gate on rt.turn_log to detect main vs
stub" pattern is now broken; updated to gate on walk_surface ==
_UNKNOWN_DOMAIN_SURFACE.  One existing hedge-injection test gate
updated accordingly.

Back-compat: ADR-0035→0038 per-field accessors
(response.safety_verdict, etc.) still work.  New consumers should
read response.verdicts.

Files:
- chat/verdicts.py (new) — TurnVerdicts dataclass
- chat/runtime.py — _stub_response tokens kwarg + stub TurnEvent
  append + hedge_injected tracking + bundle construction
- core/physics/identity.py — TurnEvent.verdicts: object = None
- tests/test_turn_verdicts_bundle.py (new) — 16 tests
- tests/test_hedge_injection.py — gate fix for stub detection
- docs/decisions/ADR-0039-audit-completeness.md (new)

Verification:
- Combined pack-layer suite: 170 green (was 154 after ADR-0038)
- CLI suites unchanged: smoke 67, runtime 19, cognition 121
- core eval cognition: intent 100%, versor_closure 100% (baseline)
2026-05-17 21:32:46 -07:00
Shay
514ace0cbf feat(adr-0035): turn-loop auto-invocation — surfacing only
Wires SafetyCheck and EthicsCheck into ChatRuntime at end-of-turn on
both the main articulation path and _stub_response.  Verdicts attach
to ChatResponse.safety_verdict / .ethics_verdict and TurnEvent.
Observational at v1: no refusal, no re-articulation, no behavioral
change.  Refusal policy is the next ADR with real verdict data in hand.

Runtime-checkable predicates today:
  - preserve_versor_closure         (via _FieldStateWithVersor adapter)
  - no_identity_override            (manifold hash before vs after; equal by construction)
  - no_silent_correction            (runtime._last_refusal_was_typed bookkeeping)
  - acknowledge_uncertainty         (IdentityScore.alignment + hedge detection)
  - disclose_limitations            (walk_surface == _UNKNOWN_DOMAIN_SURFACE)

Predicates with no runtime evidence (no_manipulation, no_fabricated_source,
defer_high_stakes_to_human_review, respect_user_autonomy, no_hot_path_repair)
honestly report runtime_checkable=False per the ADR-0032/0034 discipline.
They become checkable as classifiers and pipelines land — surface contract
doesn't change.

Test coverage: 14 new tests; combined pack-layer surface suite (loaders +
checks + turn-loop) now 122 green.  CLI suites unaffected: smoke 67,
cognition 121, teaching 17, runtime 19.  Cognition eval baseline preserved.
2026-05-17 20:57:33 -07:00
Shay
07ad3af845 feat(surface): ADR-0031 — score-decomposition surface (per-axis hedges)
Closes the 'identity hedges are generic' gap.  When IdentityCheck reports
that a specific axis is deviating AND the pack supplies an axis_hedges
entry for that axis, the assembler uses that axis's phrase instead of
ADR-0028's generic preferred_hedge_*.  The hedge text now names what is
actually at issue.

Selection: lex-smallest axis_id in (ctx.deviation_axes ∩ axis_hedges).
Deterministic; loader emits axis_hedges in lex order on axis_id.

Example surface at alignment=0.30 (strong band) under default pack:
  No deviation             → 'It seems that truth reveals reality.'
  truthfulness deviates    → 'Evidence is thin that truth reveals reality.'
  coherence deviates       → 'This does not yet cohere: truth reveals reality.'
  reverence deviates       → 'Reports suggest truth reveals reality.'

Same trajectory + truthfulness deviation, three different packs:
  default_general_v1   → 'Evidence is thin that truth reveals reality.'
  precision_first_v1   → 'The evidence does not support that truth reveals reality.'
  generosity_first_v1  → 'Truth reveals reality.'  (above generosity's strong=0.20)

Schema (additive, optional):
  surface_preferences.axis_hedges = {
    <axis_id>: { 'strong': str, 'soft': str, 'qualifier': str },
    ...
  }

Bounds: each phrase length 1–64; axis_id non-empty.  Absent block →
ADR-0028 byte-for-byte fallback.  Loader emits pairs in lex order on
axis_id for hashability + deterministic tie-break.

Files:
  core/physics/identity.py
    + class AxisHedge (frozen: strong, soft, qualifier)
    SurfacePreferences gains axis_hedges: Tuple = ()
  packs/identity/loader.py
    + _build_axis_hedges(): parse + bounds-check + emit lex-ordered tuple
  generate/surface.py
    SurfaceContext gains deviation_axes: frozenset[str] + axis_hedges tuple
    + _axis_specific_phrase(ctx): lex-smallest match or None
    _apply_hedge consults axis-specific phrase before ADR-0028 fallback
    Depth languages (he, grc) unchanged — ADR-0030 canonical phrases
  chat/runtime.py
    _build_surface_context lifts identity_score.deviation_axes and
    prefs.axis_hedges into SurfaceContext
  packs/identity/*.json
    Three v1 packs gain axis_hedges blocks (truthfulness, coherence,
    reverence — each pack uses voice consistent with its character)
  scripts/ratify_identity_packs.py (no change — idempotent)
  packs/identity/*.mastery_report.json
    Auto-refreshed.  New SHAs:
      default_general_v1   → 2ab7d469013509ba5030313ca9a609a443d0716e3ddcc5596f59858ce054f5d3
      precision_first_v1   → 78aa1e6a68a35c2c8576b6196a52d421b94f6d11e006128986902a4fd08679af
      generosity_first_v1  → 511f1ce20edd4266239da61443bfc93473a5433f20bfee6692a25a03073dc933

Tests: tests/test_identity_score_decomposition.py — 17 new tests:
  per-axis phrase selection, band gating still applies, pack swap with
  same deviation produces three different phrases, lex tie-break is
  deterministic, depth-language fallback to ADR-0030, backward compat
  with empty deviation_axes, and the contract that all three v1 packs
  ship axis_hedges for all three default-pack axes.

Suite status (all green):
  cognition 121, teaching 17, runtime 19, formation 182, smoke 67
  identity+safety+English+depth divergence 71
  score decomposition 17

Scope limits (documented in ADR-0031):
  - English-only at v1 (depth languages use canonical ADR-0030 phrases)
  - Lex tie-break is operational not semantic — pack authors can re-key
    if they need a different priority
  - No dominance-driven phrasing (Interpretation A); preserved as
    forward-compatible follow-up

Docs: ADR-0031 (Accepted) recorded; docs/identity_packs.md gains
§Axis-specific hedge phrases section and updated v1-pack SHAs; memory
'identity-packs.md' refreshed.
2026-05-17 20:16:22 -07:00
Shay
1574a4b030 feat(identity-packs): ADR-0028 — pack-driven hedge & claim-strength shaping
Closes the 'identity is load-bearing but not visibly differentiated'
gap noted at the end of ADR-0027.  Pack swap now produces visibly
different surfaces on identical trajectories at the same alignment.

Schema bump — packs gain an optional 'surface_preferences' block:

  hedge_threshold_strong, hedge_threshold_soft  → band entries
  preferred_hedge_strong, preferred_hedge_soft  → phrases per band
  claim_strength                                → balanced|qualified|affirmative
  qualified_band_high, preferred_qualifier      → marginal-band shaping

Loader enforces threshold ordering (strong <= soft <= qual_high),
phrase length bounds, and the enum-of-three for claim_strength.
Missing block resolves to defaults that reproduce pre-ADR behavior
byte-for-byte; existing tests pass unchanged.

Algorithm (deterministic, surface-only, no sampling/repair/normalize):

  alignment < strong              → preferred_hedge_strong + lower-cased surface
  alignment < soft                → preferred_hedge_soft + lower-cased surface
  soft <= alignment < qual_high
    and claim_strength=qualified  → preferred_qualifier + lower-cased surface
  otherwise                       → bare surface

Three v1 pack profiles:

  default_general_v1   balanced; 0.40 / 0.50 / 0.75 ; 'It seems that' / 'Perhaps'
  precision_first_v1   qualified; 0.55 / 0.70 / 0.85 ; 'Arguably,' / 'In some cases,' / 'Under certain conditions,'
  generosity_first_v1  affirmative; 0.20 / 0.30 / 0.50 ; default hedge phrases

Re-ratified.  New MasteryReport SHAs (superseding Phase-5):

  default_general_v1   → ddc1ba127231272660e6a435e177227558461b0278572a95635b416c3e1dec5a
  precision_first_v1   → cb5fb2323214a26afda33f2a67e22f38fe49f4763829d48ef67fd41241aba33c
  generosity_first_v1  → 94f2f49e1b16c7498fb52b8f9864eecc198618933dc8381a01b809c146826db7

Files touched:

* core/physics/identity.py — new SurfacePreferences dataclass;
  IdentityManifold gains 'surface_preferences' field with defaults.
* packs/identity/loader.py — _build_surface_preferences() parses,
  bounds-checks (threshold ordering, claim_strength enum, phrase
  length, threshold ranges); SurfacePreferences round-trips.
* generate/surface.py — SurfaceContext gains 7 new fields with defaults
  matching the pre-ADR module-level HEDGE_STRONG_THRESHOLD /
  HEDGE_SOFT_THRESHOLD; _apply_hedge takes the full context and
  implements the four-band algorithm; module-level constants retained
  for back-compat.
* chat/runtime.py — _build_surface_context lifts manifold.surface_preferences
  into SurfaceContext.
* packs/identity/*.json — three v1 packs gain surface_preferences blocks
  tuned to their roles; re-ratified via scripts/ratify_identity_packs.py
  (idempotent).
* tests/test_identity_surface_divergence.py — 15 tests covering hedge
  bands, claim_strength bands, pack-swap divergence proof, and runtime
  context wiring.

Suite status: cognition 121, teaching 17, runtime 19, formation 182,
smoke 67 — all green.  test_identity_packs.py 23/23, new
test_identity_surface_divergence.py 15/15.

Docs: ADR-0028 (Accepted) records the decision and verification; ADR-0027
status updated to point to ADR-0028 for deep realizer wiring; README
§Identity Packs notes the visible divergence; docs/identity_packs.md
gains a §Surface preferences section and closes the known-limit #1
about invisible surface differentiation.
2026-05-17 19:42:54 -07:00
Shay
a9cafc5368 fix(identity): close v3 paraphrase gap with two-layer override defense
Resolves the adversarial-identity v3 finding (0% rejection on
paraphrased attacks against the marker-string defense). Two
independent layers now guard the review gate; either is sufficient
to reject.

Fix #2 (syntactic, in teaching/review.py):
  Replaces the substring-only check with four deterministic rules:
    (a) legacy markers (v1/v2 coverage preserved verbatim)
    (b) redirect-verb + role-frame co-occurrence
    (c) negating qualifier within +/-3 tokens of a role-frame
    (d) negating qualifier within +/-3 tokens of a redirect-verb
  Replay-safe, no learned classifier, single-file contained change.

Fix #3 (geometric, in core/physics/identity.py):
  Adds IdentityCheck.would_violate(score, manifold) predicate per
  ADR-0010 and wires it through CognitiveTurnPipeline._run_teaching
  from response.identity_score. The geometric layer is paraphrase-
  invariant by construction.

  Honest finding: with the current default IdentityManifold (three
  unit-axis ValueAxes), the geometric layer flags 0/32 of v3 attacks
  independently. The predicate and wiring are in place; the manifold
  axis design is the limiting factor and remains as scoped follow-up.
  Fix #2 is what is actually rejecting attacks today.

Verification: all eight adversarial-identity splits (v1-v4, public +
holdouts) at attack_rejection=1.0 and legitimate_acceptance=1.0.
v4 (32 attacks + 18 legitimate) is the regression gate for fix #2,
exercising rules (b)/(c)/(d) with new attack vocabulary. Tests
test_reviewed_teaching_loop.py (5/5), test_pipeline_teaching_integration.py
(5/5), test_identity_gate.py (incl. 5 new TestWouldViolatePredicate
tests, 12/12). CLI suites: smoke, cognition, teaching, runtime all
green.

Also drops a stale entry from the runtime CLI suite list
(test_chat_identity_telemetry.py was removed in 222124a).
2026-05-16 14:05:55 -07:00
Shay
15ed2cee89
Tighten hot-path backend consistency
- route SessionContext anchor CGA through algebra.backend
- move aspect-weight carry into FieldEnergyOperator.compute
- remove duplicated propagate_step threshold patch and per-step imports
- add carry_aspect_weight tests for parity, fallback, and propagation preservation
- preserve normalization, propagation, vault, Rust dispatch, and energy cadence semantics
2026-05-15 08:14:38 -07:00
Shay
7401eae7ae
Clean up runtime contracts before cognitive pipeline
- document ChatResponse, TurnEvent, identity, memory/teaching, and test-organization contracts
- add local trace and build metadata ignore rules
- warn on deprecated IdentityCheck constructor injection
- update identity gate tests to canonical ValueAxis and ReasoningTrajectory usage
- keep cleanup scoped ahead of cognitive pipeline work
2026-05-14 18:47:59 -07:00
Shay
dcb0b34ccc
Fix full-suite regressions after chat telemetry merge
- restore articulation surface as ChatResponse.surface while retaining walk_surface telemetry
- calibrate moderate E2 energy boundary
- reclose generated field states after propagation and recall
- restore pytest-safe REPL parsing and field_walk helper
- anchor proposition predicate selection to prompt field
- make vault exact self-recall deterministic
- align chat telemetry regression with restored surface contract
2026-05-14 18:23:31 -07:00
Shay
c46eae8fc8
Fix main chat test regressions
- make async chat reuse initialized synchronous chat lifecycle
- restore make_rotor_from_angle compatibility helper
- restore identity ValueAxis export and legacy IdentityCheck call style
- preserve legacy reasoning trajectory fixtures for existing tests
2026-05-14 15:48:45 -07:00
Shay
216a789808
Fix identity gating and vault telemetry
- calibrate identity threshold and per-axis telemetry
- keep walk surfaces visible when identity flags are telemetry
- report real vault recall hits through generation/runtime logs
- record selected surface in TurnEvent
- fix async chat persona reference
- add regression coverage for chat telemetry
2026-05-14 15:44:01 -07:00
Shay
95f212c69d fix: IndentationError on TurnEvent.elaboration; align IdentityScore fields with runtime expectations
- Fix IndentationError: `elaboration` field was indented inside the
  docstring block instead of at the class body level (line 149).
- Add `value` and `alignment` aliases on IdentityScore so that
  run_examples.py / review_trace.py can read `.value` and `.alignment`
  (runtime.py and the serialiser both reference these names).
  `value` mirrors `score`; `alignment` mirrors `1.0 - deviation fraction`.
- Add `axes_evaluated` property returning the deviation_axes frozenset
  as a sorted list, matching the serialiser expectation in run_examples.py.
2026-05-14 14:04:13 -07:00
Shay
55f95f3629
feat(identity): add elaboration field to TurnEvent — full sentence provenance trace 2026-05-14 13:45:28 -07:00
Shay
9be12b9a14 identity: add CharacterProfile.from_manifold() factory + TurnEvent provenance record
- CharacterProfile.from_manifold() populates traits/theological grounding
  directly from a live IdentityManifold — no longer orphaned.
- TurnEvent is a frozen, append-only provenance record for one chat turn.
  Carries: turn index, dialogue role, IdentityScore, CycleCost, vault hit
  count, walk surface, and articulation surface. Enables full determinism
  tracing across every turn without mutation.
- IdentityCheck.check() is unchanged in contract.
2026-05-14 13:10:00 -07:00
Shay
6bad4189d2 Implement core physics and pack validation 2026-05-14 12:35:19 -07:00
Shay
159c783c2e feat(physics): add mind-physics layer — ADR-0008/0009/0010, blueprint, and operator stubs
- docs/decisions/ADR-0008-allocation-physics.md
  Formalizes salience, attention, inhibition, and coherence-budget
  as the allocation physics of cognition. Replaces attention-as-weights
  with attention-as-field-curvature over the versor manifold.

- docs/decisions/ADR-0009-compositional-physics.md
  Defines temporal binding, digest cycles, reasoning trajectories,
  and articulation planning as the compositional physics layer —
  how CORE assembles pressure into structured thought and output.

- docs/decisions/ADR-0010-identity-physics.md
  Establishes IdentityManifold, DriveGradientMap, ExertionMeter,
  and CharacterProfile as structural identity primitives. Identity
  is a field over the geometry, not a prompt veneer. Grounded in
  John 1:1–2 and the Logos theology that anchors the architecture.

- docs/architecture/MIND-PHYSICS-BLUEPRINT.md
  Integration blueprint showing how allocation → compositional →
  identity physics layers compose into the full cognitive cycle.

- core/physics/ (11 Python interface stubs)
  SalienceOperator, AttentionOperator, InhibitionOperator,
  BindingFrame, DigestCycle, ReasoningTrajectory,
  ArticulationPlanner, DriveGradientMap, ExertionMeter,
  IdentityManifold, CharacterProfile — all typed, all frozen
  where stateless, all carrying explicit field contracts.

Third Door: no off-the-shelf cognitive architecture borrowed.
All operators defined from the geometry up.
2026-05-12 23:20:58 -07:00