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.
- Admisión negativa: ausencia, medio bundle y objeto impostor deben rechazar con el nombre de la flag.
- 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.
- Entrega al plan: comprobar stage/handler/tools en el
AgentPlanFactoryque consumirá elKernelDelegate, no sólo el objeto bundle. - Turno observable: invocar
run,streamystream_typedsegún aplique; espiar el puerto/efecto final y prohibir_legacy_run_impl. - Comparación diferencial: correr la misma fixture en legacy y Kernel, comparando el contrato de la feature, no una igualdad accidental del texto.
- 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.