core/core
Shay dccce6a7b9 fix(generate): a proposition graph must be able to represent denial (ADR-0265)
CORE served the affirmative of propositions the user denied. Measured live on
main @ 536d6e55 with realizer_grounded_authority=True:

    "evidence does not support truth" -> 'Evidence is verified: what supports truth.'
    "evidence supports truth"         -> 'Evidence is verified: what supports truth.'

Byte-identical.

Phase 4 (#136) pinned "render_semantic has no negated parameter" as a defect.
Sizing the exposure before acting on it -- the step §7 requires -- showed the
pin was correct and INCOMPLETE. The defect is two drops in series, and the
first is in the graph:

  intent.negated      parsed from the user's words, always has been
  GraphNode           NO FIELD FOR IT  <-- first drop
  ground_graph        rebuilds nodes field-by-field; nothing to carry
  depth enrichment    rebuilds nodes field-by-field; nothing to carry
  plan_articulation   cannot carry what the node does not hold
  realize_semantic    never read step.negated
  render_semantic     no parameter for it                <-- second drop

Five separate constructors, each silently defaulting to the affirmative.

Why every gate was green
------------------------
On the default config the ungrounded realizer emits "...", _is_useful_surface
rejects it, and the runtime echo wins the resolver -- and the echo contains the
user's own "does not". The truth path was correct BY ACCIDENT. ADR-0088 Phase B
grounds the graph first, which is exactly when the realizer's surface becomes
useful enough to win. So the defect sat behind a shipped flag, invisible to
every property-of-one-surface test, because nothing compared a denial to its
assertion.

Delivered
---------
- GraphNode.negated, threaded intent -> graph -> ground -> enrich -> step ->
  surface. Serialized ONLY when True, so every pre-existing as_dict and every
  trace_hash folded from one stays byte-identical -- which is why no lane pin
  moves.
- Clause grammar delegated to its one owner. Four of the eight intent
  "templates" were never frames; they were plain clauses. They now call
  render_step. Writing a second negation implementation in semantic_templates
  was the tempting fix and is rejected: Phase 2A spent a unit giving every
  linguistic fact one owner, and that design rebuilds the disease one level up.
- Frames that keep a finite verb (VERIFICATION, PROCEDURE, COMPARISON) get an
  explicit negated form. RECALL is a speech act with no proposition to deny, so
  it falls back to the clause path rather than drop the denial (ADR-0261 §5.1).

Measured
--------
    delegation on affirmatives          192/192 byte-identical
    serving realizer, all corpora       85/347 -> 109/347   (+24 = the denials)
    feature-bearing bucket              49/214 -> 73/214
    CONTROL (nothing droppable)         33/33  -> 33/33     unchanged
    multi-node (clause joining)         3/100  -> 3/100     unchanged, out of scope
    lane pins                           11/11 byte-identical, none edited

The control staying 33/33 and multi-node staying 3/100 is the evidence that
this moved the denials and nothing else.

The exhaustive control earned its keep immediately
--------------------------------------------------
It found FIVE more intents serving a denial as its own assertion --
TRANSITIVE_QUERY, FRAME_TRANSFER, NARRATIVE, EXAMPLE, DEDUCTION -- because an
intent with no frame fell back to the UNKNOWN *template* (which cannot say
"not") rather than the UNKNOWN *clause* (which can). The default is now the
capable path, so the next intent added inherits correctness. Found by the
control, not by inspection.

Mutation -- every link reverted individually
--------------------------------------------
    baseline                                        19 pass
    graph_from_intent drops intent.negated           8 FAIL
    plan_articulation drops node.negated             6 FAIL
    ground_graph drops it on rebuild                 2 FAIL
    realize_semantic stops passing step.negated      6 FAIL
    unframed intents fall back to the template       1 FAIL
    pipeline depth-enrichment drops it               1 FAIL

The last row was GREEN on the first run -- my fix there was unguarded. That is
what added the structural invariant: every GraphNode(...) built on the serving
path must NAME `negated` or be recorded in an allowlist with a reason. The
defect was five constructors; a per-site test must be written per site, and a
site added without one is invisible. Only recognition/connector.py is exempt
(an EpistemicNode has no polarity to carry).

Four Phase 4 pins are revised, not relaxed -- #136's M2 mutation ("render_semantic
GAINS a negated parameter -> FAIL") has now happened for real, and forced the
deliberate revision it was built to force.

Registered in `smoke` in the same PR that creates it, per the #136 finding that
an unregistered pin runs nowhere.

Still unexpressed, deliberately: quantifier, tense, aspect. NO PRODUCER sets
them anywhere on the serving path, so threading them would be machinery with no
caller. render_step already handles all three the moment a producer exists.

[Verification]: in-worktree on CPython 3.12.13 with `uv sync --locked` --
smoke 641 (was 621), deductive 503, lane pins 11/11 with no pin edited.
2026-07-27 13:08:17 -07:00
..
abi
adr
capability
cognition fix(generate): a proposition graph must be able to represent denial (ADR-0265) 2026-07-27 13:08:17 -07:00
comprehension_attempt
contemplation feat(adr-0244): Phase 5a — §2.7 content-id semantic rigor (4 sites) 2026-07-17 19:48:11 -07:00
demos
epistemic_disclosure
epistemic_questions
learning_arena
physics fix: skeptic remediations for Stage 3–4 exit gates 2026-07-20 14:08:37 -07:00
ports feat(ring2-ring3): multi-port residual protocol + integrity-coordinated handoff 2026-07-17 23:56:01 -07:00
proposal_review feat(teaching): HITL proposal-queue CLI — list/review contemplation-idle sinks (S4) 2026-07-24 17:05:26 -07:00
protocol
reasoning
reliability_gate test(reliability): volume-honesty invariant + distinct-evidence audit 2026-07-25 16:03:10 -07:00
response_governance
semantic_primitives feat(logos): bulk live morph authority on turn + teaching seams 2026-07-20 16:35:04 -07:00
sync
__init__.py
_safe_display.py
array_codec.py
cli.py fix(cli): core rust build was broken; report Rust parity as unfalsifiable 2026-07-26 11:50:32 -07:00
cli_capability.py
cli_doctor.py
cli_eval.py
cli_ingest.py
cli_pack.py
cli_proposal_queue.py merge: bring in the polarity unit (#125) — resolve the suite-list conflict 2026-07-26 13:08:32 -07:00
cli_rust.py
cli_teaching.py feat(telemetry): discovery-yield-per-served-turn baseline (ADR-0255) 2026-07-23 07:27:00 -07:00
cli_test.py fix(generate): a proposition graph must be able to represent denial (ADR-0265) 2026-07-27 13:08:17 -07:00
config.py chore(config): RATIFY deduction_serving_enabled — default ON (ADR-0256) 2026-07-24 16:05:11 -07:00
engine_identity.py
epistemic_state.py feat(provenance,teaching): close the lateral gaps the assessment actually found 2026-07-25 04:51:15 +00:00
ratified_ledger.py feat(provenance,teaching): close the lateral gaps the assessment actually found 2026-07-25 04:51:15 +00:00