Skip to content

Matriz ejecutable de admisión v11

Propósito y límite de esta matriz

Esta es la especificación operativa de la admisión de la ruta Kernel desde SymfonicAgent para los tres switches legacy que vienen activados en FrameworkConfig(): auto_hydrate, auto_consolidate y lazy_tooling. No declara paridad ni retiro de engine.py. Una fila solamente está completa cuando demuestra, por separado, admisión, consumo por Kernel, efecto observable y ausencia de fallback en la entrada que se pretende migrar.

La fuente de decisión es symfonic.agent.cutover.envelope.admit_invocation. La fuente de composición es SymfonicAgent._retrieval_bundle; el bundle llega a KernelDelegate, que construye AgentPlanFactory, y éste alimenta InvocationKernel. La ruta nativa Agent no usa FrameworkConfig ni esta compuerta: entra directamente por Agent.run/Agent.stream a su kernel.

Contrato de admisión

flowchart LR
  A[SymfonicAgent.run] --> B[_cutover_verdict / admit_invocation]
  B -->|admitido| C[_cutover_delegate]
  C --> D[KernelDelegate]
  D --> E[AgentPlanFactory]
  E --> F[InvocationKernel]
  B -->|rechazado| G[record_fallback]
  G --> H[_legacy_run_impl in engine.py]

Regla de lectura: el bundle es evidencia de capacidad servible, no una declaración. RetrievalBundle comprueba los métodos operativos de sus puertos; admit_invocation sólo levanta una flag si el predicado de esa fila responde verdadero. La admisión no prueba que el efecto se ejecutó en una vuelta real.

Hecho base Evidencia ejecutable
Los tres switches por defecto son True. src/symfonic/agent/config.py:FrameworkConfig.auto_hydrate, auto_consolidate, lazy_tooling (líneas 225–235).
La compuerta prueba primero hidratación y después hace la comparación default-deny. src/symfonic/agent/cutover/envelope.py:admit_invocation, _hydration_refusal, _config_refusal.
FrameworkConfig() sin bundle se rechaza por la primera condición, auto_hydrate; no se alcanza una prueba independiente de los otros dos defaults. tests/agent/cutover/test_retrieval_bundle_admission.py:TestTheEnvelopeStaysClosedWithoutEvidence.test_the_stock_defaults_are_still_refused_without_a_bundle; tests/agent/cutover/test_envelope.py:test_the_default_config_is_not_admitted.
Un rechazo de una ruta conmutada registra el motivo por capability en memoria del switchboard y ejecuta el cuerpo legacy. src/symfonic/agent/engine.py:SymfonicAgent.run (llamada a record_fallback y _legacy_run_impl); src/symfonic/agent/cutover/switchboard.py:CutoverSwitchboard.record_fallback.

Matriz: defaults y palancas de rechazo actuales

Configuración / fila Admisión actual Bundle o capability exigida Target Kernel y efecto que debe ocurrir Pruebas/evals existentes Métrica de fallback existente Próxima prueba que falta
FrameworkConfig() stock (hydrate=True, consolidate=True, lazy=True) sin bundle Rechazada. El primer rechazo verificable es auto_hydrate=True sin bundle; no implica que los otros dos estén resueltos. Un bundle que satisfaga las tres filas; el engine lo intenta construir en _retrieval_bundle. Ninguno: la compuerta devuelve rechazo antes de delegar. Por SymfonicAgent.run, el sink efectivo es _legacy_run_impl. test_retrieval_bundle_admission.py:...test_the_stock_defaults_are_still_refused_without_a_bundle; test_envelope.py:test_the_default_config_is_not_admitted. CutoverSwitchboard.fallbacks("invocation.run"), registrado por SymfonicAgent.run; la prueba de caída por auto_hydrate es test_engine_dispatch.py:test_an_out_of_envelope_call_falls_back_and_records_why. Es un contador en proceso, no telemetría durable. CORE-20/24: prueba de integración de construcción stock que enumere todos los motivos no satisfechos (o un diagnóstico compuesto), y exportación durable/por proceso de los motivos. Hoy sólo se observa el primer guardia.
auto_hydrate=False, auto_consolidate=False, lazy_tooling=False Admitida si no hay otra desviación default-deny. Ninguno. SymfonicAgent puede construir KernelDelegate; KernelDelegate.run compila con AgentPlanFactory y llama a InvocationKernel.run. No ejercita memoria ni router. tests/agent/cutover/test_envelope.py:test_a_stateless_text_turn_is_admitted; tests/agent/cutover/test_engine_dispatch.py usa STATELESS para probar dispatch. No debería incrementar fallbacks("invocation.run"); hay espía que prohíbe legacy en test_engine_dispatch.py:test_a_flipped_run_never_enters_the_legacy_implementation. No basta para retirar engine: ejecutar una batería diferencial Agent nativo vs SymfonicAgent/Kernel para el contrato base, incluyendo run, stream y stream_typed, con resultados y eventos observables.
auto_hydrate=True con bundle ausente, parcial o con puertos no operativos Rechazada. _hydration_refusal exige bundle y bundle.missing(); no levanta por presencia. RetrievalBundle.serves_hydration(): retrieval con retrieve y scan_candidates, más conversation con recent. Cuando cumple, fold_retrieval_bundle crea HydrationCoordinator/MemoryCapability; los stages y handlers viajan a AgentPlanFactory desde KernelDelegate.__init__. Admisión y negativos: test_retrieval_bundle_admission.py:TestTheEnvelopeStaysClosedWithoutEvidence, TestTheBundleReportsWhatItServes; consumo de memoria dual: test_memory_turn_on_the_kernel.py:TestTheMigratedPathServesAMemoryTurn.test_a_bundle_with_all_three_pieces_admits_both_flags; paridad dedicada: tests/agent/cutover/test_hydration_parity.py. Si llega a SymfonicAgent.run con switch de invocación activo y el veredicto rechaza, suma la razón en fallbacks("invocation.run"); evidencia directa: test_engine_dispatch.py:test_an_out_of_envelope_call_falls_back_and_records_why. Fila requiere eval adicional: una prueba de turno completo por SymfonicAgent.run con auto_hydrate=True y bundle real que pruebe: no entrada a _legacy_run_impl, llamada a retrieval y ventana, y contenido de prompt/resultante. Repetir para stream y stream_typed; no inferirlo de admisión.
auto_hydrate=True con bundle completo Admitida para esta palanca, pero sólo si las otras flags/configuración también satisfacen la compuerta. El lift es estrecho: no levanta consolidación ni routing. Igual que la fila anterior; _config_refusal añade auto_hydrate a lifted sólo si serves_hydration(). HydrationCoordinator es la capability que el fold añade y el plan compila; el Kernel ejecuta su stage como parte del plan. test_retrieval_bundle_admission.py:test_a_complete_bundle_admits_hydration (admisión); test_bundle_reaches_the_plan.py comprueba que bundle/plan no pierden el half-shape. Mismo contador en memoria por invocation.run; no existe umbral, SLO ni exportador consultable entre procesos. CORE-21: fixture determinista de memoria y comparación legacy/Kernel de los observables acordados (ventana, recall, orden, exclusiones, límites y efectos). Debe fallar si se pincha legacy o si el stage no corre.
auto_consolidate=True con bundle ausente o incompleto Rechazada. _config_refusal sólo levanta cuando serves_consolidation() responde. RetrievalBundle.serves_consolidation(): writes.write y lifecycle.flush. En la composición real también se exige records_from para poder plegar el stage. El engine toma las tres piezas en SymfonicAgent._consolidation_pieces, fold_retrieval_bundle construye MemoryCapability con consolidación y lo entrega como stage al plan. Admisión: test_consolidation_admission.py:TestAdmission; composición de las tres piezas y admisión junto con hydration: test_memory_turn_on_the_kernel.py:...test_a_bundle_with_all_three_pieces_admits_both_flags y ...test_the_producer_is_required_with_the_ports. Rechazo en run se cuenta con la razón de la compuerta, pero no hay prueba focal que pruebe el fallback auto_consolidate mediante un turno completo ni persistencia de la métrica. Fila requiere código/eval: el predicado de admisión sólo comprueba write+flush; añadir una prueba de integración que construya el bundle por SymfonicAgent._retrieval_bundle, ejecute el post-response stage y pruebe records_from → write → flush → memoria recuperable sin legacy. Añadir la comparación diferencial contra legacy y sus fallos.
auto_consolidate=True con bundle de consolidación servible Admitida para esta palanca, si hydration/routing y el resto de config no rechazan. writes.write + lifecycle.flush; el fold protege records_from al construir. MemoryCapability de la composición; AgentPlanFactory recibe stages/handlers y InvocationKernel debe ejecutar el stage post-respuesta. Sólo admisión aislada: test_consolidation_admission.py:test_a_bundle_that_serves_consolidation_admits_it. La prueba de memoria dual muestra que ambos predicados admiten, no que commit/flush se observó en el Kernel. CutoverSwitchboard por capability/razón, local al objeto. CORE-20/21: convertir esta fila en verde sólo cuando el eval anterior capture los tres eventos/efectos y pruebe que _legacy_run_impl no se toca.
lazy_tooling=True sin router servible Rechazada. _config_refusal no levanta lazy_tooling. RetrievalBundle.serves_routing(): router con método contribute. Ninguno ante rechazo; desde SymfonicAgent.run vuelve a engine.py. tests/agent/cutover/test_lazy_palette_end_to_end.py:TestAdmission.test_lazy_tooling_refuses_without_a_router; también test_envelope.py:test_each_unmigrated_capability_names_itself. Mismo contador local de invocation.run; no hay prueba de fallback real específica de lazy_tooling. Fila requiere eval: un SymfonicAgent.run/stream con lazy_tooling=True sin router debe demostrar contador + entrada legacy, igual que la prueba existente de auto_hydrate.
lazy_tooling=True con router que contribuye Admitida para esta palanca si el resto de la configuración es admisible. ToolsCapability (o compatible) que responda contribute; fold_retrieval_bundle(router=...) conserva la capability para AgentPlanFactory. La capability contribuye tools.routing; el target observable es PaletteProjector.bind, que debe recibir el subconjunto por turno antes de bindear al modelo. test_lazy_palette_end_to_end.py:TestAdmission.test_a_router_that_can_contribute_lifts_it; TestTheModelIsOfferedTheRoutedSubset.test_the_cue_decides_the_palette prueba la paleta en el projector. El contador existe pero no se conecta a una métrica durable ni se valida en una ejecución SymfonicAgent end-to-end de esta fila. Fila requiere código/eval: prueba integrada a través del delegate/Kernel para run, stream y stream_typed, con dos cues y un spy de model.bind_tools; comparación legacy vs Kernel de herramientas ofrecidas y tool calls. El test actual llega al projector, no prueba por sí solo el composition root ni todas las puertas.

Secuencia de verificación por fila

Una implementación o ticket que cambie una fila debe ejecutar la secuencia siguiente; no se puede reemplazar una fase por una prueba de admisión.

  1. Admisión negativa: ausencia, medio bundle y objeto impostor deben rechazar con el nombre de la flag.
  2. Admisión positiva: el bundle construido por la composition root real debe levantar únicamente su campo; las palancas vecinas deben seguir rechazando si no tienen evidencia.
  3. Entrega al plan: comprobar stage/handler/tools en el AgentPlanFactory que consumirá el KernelDelegate, no sólo el objeto bundle.
  4. Turno observable: invocar run, stream y stream_typed según aplique; espiar el puerto/efecto final y prohibir _legacy_run_impl.
  5. Comparación diferencial: correr la misma fixture en legacy y Kernel, comparando el contrato de la feature, no una igualdad accidental del texto.
  6. Telemetría de salida: verificar que no se incrementa fallback para la fila positiva y que el motivo exacto se exporta para la negativa.

Work items derivados (sin implementación en este documento)

Prioridad Ticket / entrega Fila que cierra Criterio objetivo
P0 CORE-20 — diagnóstico compuesto de admisión stock y matriz ejecutable stock Reporta cada requisito no satisfecho o una cobertura explícita por flag; no confunde el primer rechazo con completitud.
P0 CORE-24 — telemetría durable de fallback todas Contador/atributos por entrypoint, switch y razón sobreviven al proceso y permiten medir cero fallbacks.
P1 CORE-21 — batería diferencial hydrate, consolidate, lazy tooling Fixtures deterministas hacen fallar ante ejecución legacy, stage omitido o observable divergente.
P1 Entrega de eval de consolidación consolidate Verifica producer/write/flush/retrieval después de una vuelta Kernel y su equivalente legacy.
P1 Entrega de eval de routing lazy tooling Verifica paleta ofrecida al modelo en las tres puertas, desde el composition root.
P2 CORE-23 — composition roots FastAPI stock / despliegue Prueba qué bundle y qué ruta construye cada root; no presume que el bundle de tests representa producción.

Criterio de salida de esta matriz

La matriz no podrá marcar FrameworkConfig() como kernel-native hasta que las tres filas positivas se ejecuten sin fallback en los entrypoints soportados y los evals diferenciales cubran sus contratos. Aun entonces, eso sólo elimina un bloqueo del retiro: la API pública, otros capabilities y el gate de retirement siguen siendo contratos separados.

Comandos de verificación focal

uv run pytest -q \
  tests/agent/cutover/test_retrieval_bundle_admission.py \
  tests/agent/cutover/test_consolidation_admission.py \
  tests/agent/cutover/test_lazy_palette_end_to_end.py \
  tests/agent/cutover/test_memory_turn_on_the_kernel.py \
  tests/agent/cutover/test_engine_dispatch.py

El comando verifica el estado de las pruebas nombradas; no certifica la completitud de las próximas pruebas listadas como faltantes.