Phase 13: Tools & Protocols

Evidencias, confianza y desconocidos en análisis binario

Un hallazgo sobre un programa compilado es un registro con un hash, una confianza, una autoridad y una lista de lo que no puede mostrar.

Type: Build

Languages: Python, C

Prerequisites: Phase 13 · 32 (ELF from scratch), Phase 13 · 33 (disassembly and control flow), Phase 13 · 34 (lifting to pseudocode)

Time: ~105 minutes

Objetivos de aprendizaje

  • Construir un registro de pruebas basado en los datos de rea.Evidencecon la confianza observada, derivada y inferida.
  • Computa IDs de contenido-hash que permanecen iguales cuando el archivo se mueve a otra carpeta.
  • Registra lo que cada proveedor no puede mostrar como limitaciones que viajan con el registro.
  • Rechazar el indicación de un resultado hasta que una ejecución observada de la función lo respalde.
  • Mantenga los desconocidos residuales como registros revisados unidos por una cadena de hash.
  • El proveedor de caché responde bajo una clave exacta y rechaza una reproducción obsoleta.

El problema

¿ Qué le preguntas a un agente ?gradeEn elledger-x86_64-O1.oEl agente llama rea, lee el pseudocodo de Ghidra y responde 0. Un revisor pregunta cómo sabe el agente. El agente tiene un bloque de texto que Ghidra imprimió.uVar1 = -(param_1 >> 0x1f) ^ (uint)((ulong)((long)param_1 * 0x66666667) >> 0x3f);Los bytes en ese punto dicenxor eax, eax¿ Qué ?

La expresión y la instrucción producen 0 para cada entrada. El agente no sabía eso.NDSS BAR 2026En el estudio de 2026 se plantó texto dentro de los binarios y se encontró que los modelos propusieron la acción insegura plantada en 35 de los 40 casos (arXiv 2607.12507¿Qué es lo que se hace?

La respuesta de la agencia es que, en el caso de las llamadas de herramientas, cada llamada de éxito produce una.Evidenceregistro con un confidencede observed¿ Qué ?derived, oinferred, un authority, y una lista de limitations. La habilidad envasada le dice al agente: "Cada conclusión debe distinguir observaciones, inferencias y desconocimientos. Cita ID de Evidencia, preserva limitaciones y cobertura incompleta, y nunca implica que el análisis estático observado ejecución".

Tres cosas que realmente le deja a usted. Sus instantáneas almacenan en caché los resultados exactos de la consulta, no el análisis. Su verificación pasa una reclamación cuando una dimensión de comparación no cambia, y su propio comentario dice que un pase "no establece equivalencia global de implementación". Su libro mayor de obligaciones toma candidatos sólo de JavaScript y gráficos gestionados, por lo que una función nativa nunca alcanza.verifieda través de ella.

Esta lección construye la pieza que falta en Python simple. Usted escribe un libro mayor que almacena todos los hechos sobre el dispositivo como un registro con un hash de contenido. Usted hace predicciones sobrepercent_changey gradeImporta dos registros reales reales y la instantánea de donde provienen, y su libro mayor recalcula cada hash rea escrito.

Tres palabras para la confianza, cinco para la autoridad

confidencees un enum con tres valores, nunca un número. authorityCuando un productor no dice nada, rea utilizashipped-artifactconobserved¿ Qué ?

ValueMeaning on the fixtureRecords in this lesson
observedA fact read from bytes or from a runthe ELF reader's section and symbol reads, the two Ghidra records, 17 host runs
derivedA fact computed from observed recordsthe switch table model, the division model, every unknown mutation
inferredAn expectation that no observation states yet18 predictions
shipped-artifactThe file on disk was the sourceevery read of ledger-x86_64-O1.o
controlled-replayA run you controlled produced the factthe host runs of harness.c
analyst-inferenceYour own judgementpredictions and unknown mutations
historical-referenceAn older source tree or documentnone here
external-serviceA service outside the file and the hostnone here

Dos confusiones cuestan más tiempo. La primera trata de pseudocodo como una observación del comportamiento. Es una observación de lo que Ghidra imprimió. La segunda trata de una lista vacía como prueba de ausencia.code/main.pycodifica ambas reglas.

El registro

Un registro tiene exactamente dieciséis campos, y rea 6.5.0 rechaza cualquier otro campo. code/main.pymantiene los mismos nombres que rea, por lo que un registro de ambos lados se valida en el otro.relationship_coverage, dice cuán completa es una lista de llamados o llamados.complete¿ Qué ?partial, ounknown, onullcuando la operación no informa de relaciones de llamadas.

FieldWhat it holds
evidence_idev_ and 64 hex digits, a hash of the content
subjectname, digest.sha256, format, architecture, local_path, or null
providerid, name, version or null
analysis_profilethe provider's settings and their digest, or null, always present
predicate_typea tag, rea.analysis by default
operation, parametersthe tool and its input
raw_result, normalized_resultprovider output and the canonical result
confidence, authoritythe enums above
environmentid, platform, architecture, isolation, or null
limitationsplain sentences
relationship_coveragestatus complete, partial, or unknown with diagnostics, or null
locationsaddress, address-range, artifact-path, file-offset, file-offset-range
evidence_linksthe ev_ ids this record rests on

Este es el verdadero disco que escribió rea paragrade, cortar a los campos que importan aquí.code/fixtures/rea-evidence-grade.json, 37.573 bytes.

json{
  "evidence_id": "ev_67b6d3f992eaf49a2e16de084b6ebfdd9884e8c5c7f75e175b7bb20f4f748ce1",
  "subject": {
    "name": "ledger-x86_64-O1.o",
    "digest": { "sha256": "9a4a8082ba5e285a732552981a6935e0c5255725664f380e37c44ebfb04d803f" },
    "format": "elf",
    "architecture": "x86_64",
    "local_path": "/private/tmp/aiefs-re/phases/13-tools-and-protocols/35-evidence-confidence-and-unknowns/code/fixtures/ledger-x86_64-O1.o"
  },
  "provider": { "id": "ghidra", "name": "Ghidra", "version": "12.1.4" },
  "analysis_profile": {
    "provider": { "id": "ghidra", "name": "Ghidra", "version": "12.1.4" },
    "parameters": { "jump_table_evidence": "typed-case-default-blocks-v1", "import_mode": "ephemeral-source-immutable" },
    "digest": "9c7f6b24be69294e61da046e4583e3856cb9e40433b149c1bf8bb534d2fe03ef"
  },
  "operation": "analyze_function",
  "parameters": { "procedure": "grade" },
  "confidence": "observed",
  "authority": "shipped-artifact",
  "environment": null,
  "limitations": [
    "Default-space addresses use lowercase 0x-prefixed hexadecimal; other address spaces use <percent-encoded-space>:0x<hex>.",
    "Resolved reference metadata identifies computed, indirect, external, call, jump, and data edges; unresolved targetless flows remain unknown, and function classifications distinguish thunks and externals."
  ],
  "relationship_coverage": {
    "status": "complete",
    "diagnostics": [
      "Only resolved Ghidra call references are returned; unresolved computed or indirect calls remain unknown, while function classifications distinguish thunks and externals."
    ]
  },
  "locations": [],
  "evidence_links": []
}

La verdadera .parametersEl objeto del perfil tiene 25 claves.limitationsUna limitación es parte del contenido, así que dejar de lado una cambia la identificación, y su libro mayor rechazaría el registro.

Observe lo que el registro no dice. environment¿ Es verdad ?nullporque Ghidra leyó un archivo y no corrió nada.locationsestá vacío porque este informe de operación se dirige a dentro normalized_result- ¿ Qué ?relationship_coveragetiene el estatus completeSu diagnóstico dice que sólo se devuelven referencias de llamadas resolvidas de Ghidra, y que las llamadas informáticas o indirectas no resueltas permanecen desconocidas.

El Id es un hilo de contenido, y el camino no está en él

reacomputaciones evidence_id¿ Cómo ?ev_más SHA-256 sobre el RFC 8785 canónico JSON de una proyección del registro.digest¿ Qué ?format, y architecturey gota .namey local_path- Se cae .relationship_coveragecuando su valor es null, así que un registro sin relaciones de llamadas mantiene la misma identidad que antes de que el campo existiera.raw_resulty cada limitación, se hacha.

RFC 8785 clasifica las claves de objetos, elimina el espacio blanco y fija las formas de número y cadena. Para los registros cuyos números son enteros, la biblioteca estándar de Python produce los mismos bytes:

pythondef canonical_json(value):
    return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False, allow_nan=False)

code/main.pyRechaza los floats antes de que se hash, porque RFC 8785 y Python imprimen algunos floats de manera diferente.

rea valueRecomputed by code/main.py
ev_67b6d3f992eaf49a… for gradeequal
ev_e88b10dc0c6400e5… for percent_changeequal
profile digest 9c7f6b24be69294e… over {provider, parameters}equal
query_26122aebe9d8abae… for the grade snapshot entryequal
query_0f95ef38038d3666… for the percent_change entryequal

La misma observación de los mismos bytes obtiene la misma identificación en cualquier máquina y en cualquier carpeta.local_pathEn la lista anterior se nombran carpetas en un Mac. La identificación no cambia cuando se copia el dispositivo a /home/you/re- ¿ Qué ?rebind_subject_path()Te permite mostrar un disco bajo un nuevo camino.sha256¿ Qué ?format, oarchitectureLa diferencia. rea 6.5.0 hace lo mismo con rebindEvidenceToTargetPathCuando reproduce un registro de instantáneas para un objetivo en una nueva ruta.

validate_evidence()Recomputa el ID y rechaza una incompatibilidad con la frase de Rea, "El identificador semántico de la evidencia no coincide con su registro".analysis_profile.providerdifiere de su provider- El examen .test_tampered_id_and_mismatched_profile_are_rejectedEdita una línea de pseudocodo dentro de la real graderegistrar y ver el libro mayor rechazarlo.

Observe usted mismo el objeto

Antes de cualquier proveedor, el libro mayor lee el archivo. observe_object()analizará los encabezados de las secciones ELF64, .symtab¿ Qué ?.strtab, y .rela.textconstruct.unpack_fromEscribe una .inspect_objectregistro y uno read_function_bytesregistro por símbolo de función.observedcon autoridad shipped-artifact, porque la fuente era el archivo en el disco.

RecordContentId
inspect_objectfive sections with offsets, sizes, and hashes, four functions, three relocationsev_645e0a145f28bd5c…
read_function_bytes percent_change16 bytes at .text+0x00ev_2572a7d254ad15cb…
read_function_bytes grade46 bytes at .text+0x10, SHA-256 ffcb75c2a7bb1104…ev_a467c2427bfc0c56…
read_function_bytes total31 bytes at .text+0x40ev_b1e845cea2543073…
read_function_bytes grade_label63 bytes at .text+0x60ev_c50041be26e6b7f4…

llvm-objdump -testá de acuerdo: gradeEn el0000000000000010con tamaño 2eLas tres reubicaciones en.rela.text¿ Qué ?R_X86_64_PC32contra.rodataen compensaciones 0x36¿ Qué ?0x84, y 0x93, con adiciones 0x10¿ Qué ?0x24, y -0x4Cada disco lleva unfile-offset-rangeubicación y una limitación: "Los bytes de sección se leen desde el archivo en el disco. El lector no aplica ninguna reubicación y no ejecuta ningún código".

La lección 32 construye este lector en su totalidad. Aquí hay 60 líneas, porque esta lección es sobre lo que usted registra sobre la lectura.

Derivar la tabla y decir que lo derivó

Los 46 bytes de gradecontienen cuatro patrones que la lección 33 decodificó:

BytesInstructionOffset in grade
48 69 c0 67 66 66 66imul rax, rax, 0x666666673
48 c1 f9 22sar rcx, 3413
83 c1 faadd ecx, -623
83 f9 04 77 0ccmp ecx, 4 then ja28

Un multiplicador por 0x66666667Después de un cambio de 34 se firma una división por 10. El archivo tiene el número 10.derive_grade_model()escribe ese hecho como una limitación: "El divisor 10 es una derivación del multiplicador 0x66666667 y el cambio 34. El archivo tiene el número 10. "

El add ecx, -6El primer caso se sitúa en 6.cmp ecx, 4con un salto sin firmar admite cinco casos, 6 a 10.

El leaEn el.text+0x33lleva la reubicación con adenda 0x10. Una PC32 reubica medidas desde el final del desplazamiento de 4 bytes, por lo que la tabla comienza en .rodata+0x14Cinco palabras de pequeño endio allí leyeron1, 2, 3, 4, 4- El interruptor en .ledger.cEl compilador convirtió el interruptor en una tabla de búsqueda de valores de devolución.

El registro resultante ev_605106bff2d9998f…¿ Qué ?confidence derived, y su evidence_linksEl registro de bytes se encuentra en el libro mayor y el registro derivado tiene un enlace colgante.ev_a467c242…¿ Qué ?

Ahora compárate con Ghidra. Su pseudocodo para los mismos bytes:

cuint grade(int param_1)
{
  uint uVar1;
  uint uVar2;

  uVar2 = param_1 / 10 - 6;
  uVar1 = -(param_1 >> 0x1f) ^ (uint)((ulong)((long)param_1 * 0x66666667) >> 0x3f);
  if (uVar2 < 5) {
    uVar1 = *(uint *)(&DAT_001000b4 + (ulong)uVar2 * 4);
  }
  return uVar1;
}

Ghidra aplicó la reubicación y nombró la tabla DAT_001000b4, que es .rodata+0x14después de que se colocó.textEn el0x100000. Recuperó la división por 10 y los cinco casos. Para el valor predeterminado imprimió una expresión que es siempre 0 y nunca dice 0.native_value_flowmarca esas operaciones is_dead: trueEl registro es una fiel observación de Ghidra. El significado que se lee de él se deriva, y el valor que se espera de una carrera se deduce.

El percent_changeEl registro muestra el otro fracaso.undefined1 [16] percent_change(int param_1,int param_2,ulong param_3)La fuente dice:int percent_change(int before, int after)- ¿ Qué ?idivescribe EDX:EAX, y el camino cero sale .EDXNo se ha tocado, así que el descompilador dedujo una vuelta de 16 bytes y un tercer parámetro.native_api.return_type.confidenceporgrade¿ Es verdad ?"low"Tratar una firma recuperada como la inferencia del proveedor, y registrarla de esa manera.

Las predicciones son registros inferidos

Una predicción es una afirmación sobre el comportamiento que ninguna observación ha declarado. claim_suite()construye dieciocho de ellos a partir de los modelos derivados y de la fuente. record_prediction()almacena cada uno como un disco con confidence inferredy authority analyst-inference, vinculado a los registros en los que se apoya.

ClaimPredicted valueRests on
percent_change(12400, 15500)25, from 310000 / 12400division model ev_076a9167…
percent_change(0, 5)0, the zero guarddivision model
percent_change(100, 50)-50division model
percent_change(-7, 3)-142, because idiv truncates toward zerodivision model
grade(55)0, index -1 fails the unsigned comparetable model ev_605106bf…
grade(60), grade(69)1, 1table model
grade(70), grade(85)2, 3table model
grade(95), grade(100), grade(105)4, 4, 4table model
grade(110), grade(-5)0, 0table model
total(1, 2, 3), total()6, 0source record ev_2f1e6d25…
grade_label(85)"B"source record and table model
grade(score) for 90 to 1004 for all eleven inputstable model

predict()utiliza la semántica C, no la semántica Python. c_div()truncates hacia cero, y wrap32()Pone cada intermedio en 32 bits.//rodadas hacia el infinito negativo, así que (3 - -7) * 100 // -7La lección 36 hace que esta cuadrícula sea mucho más grande.

Cada predicción abre un desconocido residual.observedpruebas con autoridad controlled-replayy recomienda una sonda:execute_functionLa siguiente sección produce esa evidencia. La pregunta para la afirmación de primer grado dice "¿Se califica ((95) == 4 cuando se ejecuta la función compilada?"

Compruebe si se comparan con una carrera

code/fixtures/harness.cincluye ledger.cy imprime un resultado por invocación. observe_runs()lo compila con la primera de clang¿ Qué ?cc, ogccEn el camino y ejecuta cada entrada en la cuadrícula una vez.

json{
  "operation": "execute_function",
  "parameters": { "function": "grade", "args": [95] },
  "normalized_result": { "result": 4, "stdout": "4\n", "exit_code": 0 },
  "confidence": "observed",
  "authority": "controlled-replay",
  "environment": { "id": "host-process", "platform": "darwin", "architecture": "arm64", "isolation": "process" },
  "limitations": [
    "The run executed a host build of ledger.c, not the x86-64 object. The claim about the object rests on the shared source and on the compiler.",
    "One run observes one input. It proves nothing about other inputs."
  ]
}

El tema de un registro de ejecución es el arnés binario, un archivo Mach-O arm64 en este Mac, con su propio SHA-256.course-harnesscon la línea de versión del compilador, aquí Apple clang version 17.0.0 (clang-1700.6.3.2)- El .evidence_linksNombre del registro fuente ev_2f1e6d251543d017…, porque la carrera y el objeto compartenledger.cY nada más.

La primera limitación se lee dos veces. El objeto x86-64 nunca se ejecutó en esta máquina. Lo que se ejecutó fue una segunda construcción de la misma fuente para otra arquitectura. Eso sigue siendo una observación, y es la más fuerte disponible sin un emulador, por lo que la afirmación pasa con esa frase adjunta. Un informe que omite la ha perdido la información que el lector necesita.

Las 17 entradas únicas coinciden con las predicciones.code/fixtures/run-evidence.jsonposee esos 17 registros y el registro de origen, exportado con --recordEn 2026-10-13. Cuando no hay compilador presente,build_ledger()El informe de la Comisión de Agricultura y Desarrollo de la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Comisión de Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, la Comisión de Agricultura y la Agricultura, larunscampo.

Reglas de promoción

Una reclamación pasa de inferida a apoyada sólo a través de ejecuciones observadas. check_claim()Busca porexecute_functionregistros con la misma función y argumentos, compara cada resultado con la predicción y cuenta las entradas cubiertas:

StatusConditionrea's completion ledger
passevery input has an agreeing run and none disagreespass
failany run disagreesfail
unknownsome inputs have runs, others have noneunknown
unsupportedno input has a rununsupported

promote_claim()Es la forma estricta.ClaimErrorcuando cualquier identificación es inferredo derived. Se eleva cuando un id nombra una serie de otra función u otros argumentos. Se eleva cuando la lista está vacía y cuando las carreras cubren menos entradas que la afirmación.grade(55), y ninguno puede promoverlo.ev_7be90c0c…en la figura y ver la reclamación caer a unsupportedMientras que dos registros sobre gradeNo se vuelva.

La afirmación de rango muestra el caso parcial. Sólo dos de sus once entradas, 95 y 100, aparecen en la cuadrícula de ejecución. check_claim()retorno unknownconcovered2 de 11, y promote_claim()se niega con "2 de 11 entradas han observado ejecuciones". El libro mayor no redondea eso.

completion_ledger()Espejos rea EvidenceCompletionLedgerSu identificación esecl_más el hash de sus registros, y completees verdad sólo cuandopassigual totalLas huellas de demostración .ecl_da64933ea13befed…concomplete: false, debido a esa reivindicación de un rango.

Los desconocidos son registros con una cadena de hash

rea almacena un residuo desconocido como un registro estricto. code/main.pymantiene los mismos campos y las mismas invariantes.

El ID esunk_más SHA-256 por encima {domain, question, scope_digest}Dos analistas que hacen la misma pregunta sobre el mismo archivo obtienen la misma identificación.scope_digestes el SHA-256 del objeto.

Cada cambio es una nueva revisión.previous_revision_digest nullCada revisión posterior nombra a losrevision_digestde la anterior, y la digestión cubre todo campo excepto a sí misma.verify_unknown_chain()El sistema de corrección de datos de la lista de cambios de datos de la red de datos de la red de corrección de datos de la red de datos de la red de corrección de datos de la red de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de la red de corrección de datos de corrección de datos de la red de corrección de corrección de datos de la red de corrección de corrección de datos de corrección de corrección de datos de la red de corrección de corrección de corrección de datos de corrección de corrección de corrección de corrección de datos de corrección de corrección de corrección de corrección de datos de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de corrección de

Cada mutación es en sí misma un registro de pruebas, como lo hace con el proveedor rea-unknown-registryNuestros cargos .confidence derived¿ Qué ?authority analyst-inferenceSu limitación dice: "Una mutación registrada registra lo que el analista decidió.

Es por eso que los 81 registros de la demostración incluyen 36 registros de mutación derivados: 18 aberturas y 18 actualizaciones.

Se aplican tres invariantes en cada revisión:

  • Sólo unresolvedUn desconocido lleva un resolution, y sólo la revisión 1 no tiene un predecesor.
  • ¿ Qué es esto ?contradictednombres desconocidos al menos un identificador contradictorio, y ningún identificador aparece en ambas listas.
  • ¿ Qué es esto ?verifiedla resolución nombra al menos una identificación de la prueba con la confianza y autoridad requeridas.

La tercera regla es donde el libro mayor se niega con más frecuencia. Las notas de flujo de trabajo de rea dicen "Sólo las pruebas observadas calificadas pueden verificar una resolución". resolve_unknown()Por lo tanto, rechaza el modelo de tabla, rechaza un registro observado con autoridad shipped-artifact, y acepta el registro de carrera ev_f4ffbe8f922ec7fe…. La revisión resuelta para grade(95)es la revisión 2, y su previous_revision_digest¿ Es verdad ?ffca840b55a8a188…, el resumen de la revisión 1.

update_unknown()¿ Qué es ?expected_revisiony eleva .revision-conflictCuando está envejecido, como es rea.update_unknownLa reacción correcta es la que nos dan las notas de Rea: volver a leer la revisión actual y decidir de nuevo.

Un desconocido permanece abierto después de la demostración:unk_f2eb0d7f84c80a19…, "¿Clasifica la puntuación) == 4 para cada puntuación de 90 a 100 mantener cuando la función compilada se ejecuta?" Su estado es investigating, sus IDs de apoyo incluyen las dos carreras, y su sonda todavía nombra las nueve entradas sin una carrera.

Un caché de respuestas no es una base de datos para análisis

Rea tiene tres cosas que se parecen a una caché.-readOnly -deleteProjecty eliminado al cerrar.AnalysisSnapshotCacheEl archivo de instantáneas contiene hasta 10.000 entradas para una identidad binaria.target¿ Qué ?binding¿ Qué ?entries¿ Qué ?workflow_entries, y un evidence_bundle¿ Qué ?

La llave de caché es query_más SHA-256 por encima {target, binding, operation, parameters}- ¿ Qué ?target¿ Es verdad ?{sha256, kind, format, architecture}, y un raw-binaryEl objetivo también haentry_point- ¿ Qué ?bindingEl análisis de los datos de los datos de los usuarios es el proveedor y todo el perfil de análisis, incluido el digesto.jump_table_evidencede latyped-case-default-blocks-v1a una v2, y el digesto cambia, así que cada clave cambia.

code/fixtures/rea-snapshot.jsonEs el archivo rea escrito durante las dos ejecuciones, 142.690 bytes. rea lo escribió con permisos exclusivos del propietario, y la copia comprometida es legible para todos. Tiene dos entradas y un paquete de pruebas con los mismos dos registros. AnswerCache.import_snapshot()recalcula cada uno query_idY rechaza el archivo cuando cualquier difiere.targeto bindingSe diferencia de la activa, con la redacción de rea profile_mismatchRechaza una instantánea cuyaformat_versionNo escourse-answer-cache-1¿ Qué ?

Tres mediciones de esta máquina.gradeLa consulta tardó 8,6 segundos, con una nueva importación de Ghidra.percent_changeLa consulta contra el mismo instantáneo tomó 8,5 segundos, porque una consulta diferente es una falta de caché.gradeLa consulta tardó 2,1 segundos y devolvió el registro idéntico con el mismo evidence_id. La reproducción en memoria en rea añade la limitación "Cargado desde una instantánea de análisis local de REA; esta llamada no re-ejecutó al proveedor". Nuestro lookup()añade una oración del mismo tipo, para que el lector pueda distinguir una repetición de una respuesta fresca.

Una mutación termina la caché. en rea 6.5.0, un cambio de nombre o un comentario elimina la caché de instantáneas antes de que rea envíe la llamada al proveedor. Una respuesta fallida no puede probar que la escritura se haya vuelto a rodar, por lo que una escritura fallida también detiene la reproducción. Una importación de metadatos que cambia la base de datos hace lo mismo.

Por qué un agente necesita esto

Un agente que maneja rea a través de MCP ve el registro completo de cada llamada y puede citarevidence_idEn el estudio de NDSS BAR, mostrando contenido binario como datos solos, todavía quedaron 15 propuestas inseguras de 40, y las comprobaciones de procedencia con autorización de herramienta las eliminaron.arXiv 2606.06838En binarios con cientos de funciones, sólo entre el 10 y el 15 por ciento recibieron análisis real antes de que el agente produjo estubes.

El libro mayor responde a cada uno de estos con un registro, y el agente informa sólo lo que el libro mayor contiene.unsupportedUna reclamación con algunas carreras esunknownUn mensaje de proveedor esobservedNo hay más que darle al agente el archivo de habilidades.outputs/Y hacer que el libro mayor sea el único lugar donde se escriben conclusiones que se aplica a Claude, Cursor, Codex, OpenClaw, Hermes, o cualquier agente que lea SKILL.md.

Construye el mismo

Ejecutar la demostración de la biblioteca estándar:

bashcd phases/13-tools-and-protocols/35-evidence-confidence-and-unknowns
python3 code/main.py

La demostración lee el objeto, importa los dos registros rea, verifica la instantánea rea y deriva los dos modelos. Luego registra 18 predicciones, abre 18 desconocidas, compila y ejecuta el arnés, verifica cada reclamo y resuelve 17 desconocidas.

json{
  "records": 81,
  "by_confidence": { "observed": 25, "derived": 38, "inferred": 18 },
  "rea_snapshot": { "entries": 2, "replay_hit": true, "stale_profile_refused": true },
  "grade_table": [1, 2, 3, 4, 4],
  "runs": "live: Apple clang version 17.0.0 (clang-1700.6.3.2)",
  "claims": [ { "claim_id": "grade(95)", "status": "pass", "covered": "1/1" }, { "claim_id": "grade(90..100)", "status": "unknown", "covered": "2/11" } ],
  "completion_ledger_id": "ecl_da64933ea13befed9483f8b00447bb3f4ceb74324c01e2515eff03f3af3ca750",
  "complete": false,
  "unknowns": { "resolved": 17, "investigating": 1 }
}

Sin un compilador C,runsLeíaimported 17 recorded run records from run-evidence.jsony el resto es lo mismo.

Leer .code/main.pyen este orden:

  1. canonical_json()y compute_evidence_id()Mantenga la receta de hash y la proyección semántica.
  2. create_evidence()y validate_evidence()construir y comprobar un registro.
  3. EvidenceLedger.record()y import_bundle()almacenar registros y rechazar conflictos.
  4. open_unknown()¿ Qué ?update_unknown(), y resolve_unknown()Mantenga la cadena de revisión.
  5. observe_object()se lee el ELF, y derive_grade_model()Leía la mesa.
  6. claim_suite()¿ Qué ?predict(), y record_prediction()escribe el nivel inferido.
  7. observe_runs()transforma cada arnés en un registro observado.
  8. check_claim()¿ Qué ?promote_claim(), y completion_ledger()aplicar las normas de promoción.
  9. AnswerCacheLas llaves responden como las instantáneas de Rea y rechaza las viejas.

Usalo

Mantenga un libro mayor por objetivo y por investigación. Ponga el SHA-256 del objetivo en cada tema y el alcance de la pregunta en cada desconocido.providerCuando reconstruyes el archivo, el sujeto se altera y cada registro se convierte en evidencia de otro archivo.

Escribe las limitaciones en el momento en que las conoces. El lector que no aplica ninguna reubicación lo dice. La ejecución de una construcción de host lo dice. El modelo que infere un divisor lo dice. Un registro escrito sin sus limitaciones parece más fuerte de lo que permiten los hechos, y un lector posterior no puede reparar eso.

Tratar a cada texto de proveedor como datos. Las cadenas y pseudocodes del objetivo son textos que el objetivo controla._meta.provenance.untrusted_content: trueLas instrucciones del servidor le dicen al modelo que trate el contenido objetivo como datos y que informe cualquier solicitud en él para ejecutar, instalar, descargar o enviar algo como un intento de inyección rápida.

Laboratorio interactivo

Laboratorio A: recomputar una identificación real

Desde elcodedirectorio, Python abierto:

bashcd phases/13-tools-and-protocols/35-evidence-confidence-and-unknowns/code
python3 -q
  • ¿Qué quieres decir ?
pythonfrom main import *
record = load_evidence_file(FIXTURES / "rea-evidence-grade.json")
record["evidence_id"] == compute_evidence_id(record)
record["subject"]["local_path"] = "/home/you/re/ledger-x86_64-O1.o"
record["evidence_id"] == compute_evidence_id(record)
record["limitations"].pop()
record["evidence_id"] == compute_evidence_id(record)

Las primeras dos comparaciones son ciertas. El camino no está en el hash. La tercera es falsa, porque una limitación está contenida.

Laboratorio B: rechazar un ascenso

pythonledger, report = build_ledger(live_runs=False)
claim = [c for c in claim_suite(ledger.find(operation="derive_switch_model")[0], ledger.find(operation="derive_arithmetic_model")[0], ledger.find(operation="read_source")[0]) if c.claim_id == "grade(55)"][0]
promote_claim(ledger, claim, [ledger.find(operation="derive_switch_model")[0]["evidence_id"]])

La llamada se eleva .ClaimErrory nombra el ID derivado. Ahora pasa el ID de ejecución:

pythonrun = run_records_for(ledger, "grade", [55])[0]
promote_claim(ledger, claim, [run["evidence_id"]])["status"]

El estado es pass, y los regresados limitationsllevar la sentencia de construcción de anfitrión.

Laboratorio C: rechazar una instantánea obsoleta

pythonimport json
snapshot = json.loads(REA_SNAPSHOT_PATH.read_text())
target, binding = rea_snapshot_binding(snapshot)
AnswerCache(target, binding).import_snapshot(snapshot)
stale = dict(binding["analysis_profile"]["parameters"], jump_table_evidence="typed-case-default-blocks-v2")
AnswerCache(target, {"provider": binding["provider"], "analysis_profile": make_profile(binding["provider"], stale)}).import_snapshot(snapshot)

El primer importe de la exportación 2. El segundo aumento CacheErrorconprofile_mismatchUna cadena de versiones cambió y la instantánea entera se rechaza.

Lab D: rompe la cadena

pythonunknown_id = [u for u, r in ledger.unknowns.items() if r[-1]["status"] == "investigating"][0]
ledger.verify_unknown_chain(unknown_id)
ledger.unknowns[unknown_id][0]["severity"] = "critical"
ledger.verify_unknown_chain(unknown_id)

La primera llamada regresa 2. La segunda se eleva.EvidenceIntegrityError, porque la revisión 1 ya no coincide con su propio digesto y la revisión 2 pone en un digesto que ya no existe.

Laboratorio de práctica

Cierra el abierto desconocido y agrega un segundo proveedor.

Requisitos:

  • Extenderserun_grid()Así que las nueve entradas faltantes de la demanda de rango se ejecutan, luego confirmen los movimientos desconocidos a resolveden la revisión 3.
  • Añadirllvm-objdump -dcomo segundo proveedor con su propio providerobjetar y registrar su lista de grade¿ Cómo ?observed¿ Qué ?
  • Escriba underivedregistro que indica las dos listas, Ghidra y llvm-objdump, decodificar las mismas 14 instrucciones, y vincular ambas.
  • Abre un desconocido para grade_label(105)con severidad high, ya que el índice de la tabla 4 dice labels[4], y resolverlo con una carrera.
  • Exporta el libro mayor con export_bundle(), importarlo en un nuevo libro mayor, y demostrar que cada cadena todavía verifica.

El éxito significa un informe en el que cada oración cita un ID del paquete y el uno unknownEl reclamo se ha ido.

Lección Artefacto

Esta lección produceoutputs/skill-evidence-ledger.md. Le dice a un agente cómo escribir cada hallazgo como un registro con confianza, autoridad, limitaciones y enlaces.pass¿ Qué ?fail¿ Qué ?unknown, ounsupported¿ Qué ?

Verifique el hecho

Ejecutar la demostración y la suite determinista:

bashcd phases/13-tools-and-protocols/35-evidence-confidence-and-unknowns
python3 code/main.py
python3 -m unittest discover -s code/tests -v

Las 28 pruebas demuestran:

  • ambas rea evidence_idvalores, el perfil de la digestión, y ambos instantáneos query_idLos valores se recomputan a partir del contenido
  • una ruta cambiada mantiene la identificación y una limitación cambiada la cambia
  • se rechazan un registro manipulado, un proveedor de perfil descoincidente, un float y un valor enum desconocido
  • un registro duplicado de los resultados duplicate, un récord contradictorio se eleva, y una importación de paquete es atómica
  • las importaciones de paquetes de explotación registradas con 18 registros y sin vínculos colgantes
  • Un desconocido se abre en la revisión 1, se niega a una obsoleta expected_revision, y se resuelve sólo con observado controlled-replaypruebas
  • una revisión editada rompe la cadena
  • La promoción rechaza las pruebas inferidas, derivadas, vacías y no relacionadas, y pasa con un resultado de acuerdo
  • cobertura parcial es unknowny una carrera en desacuerdo es fail
  • la caché se golpea en la clave exacta y se pierde en otros parámetros
  • la caché rechaza una versión de perfil golpeado, un objetivo equivocado, una versión de formato equivocado, y una clave manipulada
  • El lector del ELF está de acuerdo con llvm-objdumpsobre los desplazamientos, tamaños, bytes y reubicaciones, y la tabla se lee 1, 2, 3, 4, 4
  • Las predicciones utilizan la división C, y las carreras registradas coinciden con las 17 afirmaciones de entrada única
  • con un compilador presente, las carreras en vivo coinciden también

Modos de falla de producción

FailureWhat the weak report saysWhat the ledger requires
Pseudocode read as behaviour"grade returns 0 for failing scores"an execute_function record for that input, or unsupported
Decompiler signature trusted"percent_change returns 16 bytes"the signature marked as the provider's inference with its low confidence
Empty list read as absence"the function has no callers"an unknown status, or a coverage field when the tool provides one
Path hashed into the id"the record changed" after a copythe semantic projection without name and local_path
Limitation dropped from a copya record that looks stronger than the sourceid mismatch and rejection on import
Partial grid rounded up"all scores from 90 pass"unknown with covered 2 of 11
Host run presented as the object's run"the x86-64 object returned 25"the host-build limitation carried on the claim
Unknown closed by a sentence"resolved, see above"a verified resolution with observed ids of the required authority
Stale revision overwrittentwo analysts' edits colliderevision-conflict and a reread
Old snapshot replayed after a releaseanswers from a changed contractprofile_mismatch on import
Cache kept after a renamea replay that hides a metadata writeinvalidation before dispatch and a failed export

Regla de funcionamiento

Registra lo que has leído, lo que has calculado y lo que esperas como tres tipos de registro con tres palabras. Cierra un desconocido con un id, nunca con una oración. Repite una respuesta solo bajo la clave exacta con la que se guardó, y rechace cuando una cadena de versiones difiere.

Leer más

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.