README.md como puerta de entrada y cierre: qué es sheafsync, el arco honesto
(cada fase, qué prometía vs qué terminó siendo, con puntero al doc), el terminus
(seguridad coord-free módulo un supuesto físico nombrado), la contribución real
y defendible, el mapa de módulos (motor lineal / retículos como control
histórico; escrow como núcleo vivo; adapter en producción; reach experimental),
el contrato de M4 que Tawasuyu consume, build/test, y el trabajo opcional
eventual con su frontera honesta.
Proyecto marcado CERRADO. M4 congelado y en producción; el resto documentado.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Exploración del reach que Balegas marca no resuelto (constraints over multiple
counters), en módulo aislado, sin tocar la API que Tawasuyu consume.
- reach::CoupledInvariants (politopo C·x ≤ slack, C ≥ 0) + VectorBudget:
escrow-por-restricción. certificado_politopo (proptest): reparto válido +
gastos ≤ presupuesto ⟹ todas las restricciones aguantan. La corrección.
- reach::{coboundary, sheaf_laplacian, SheafRouter}: el Laplaciano de haces
vectorial (L=δᵀδ) reusando nalgebra y la idea del coboundary del MVP.
diffuse conserva cada recurso y reduce la energía; ker L = totales
conservados = el H⁰ del MVP.
VEREDICTO HONESTO (REACH.md): la corrección es escrow sobre el politopo, NO
necesita haces. Con restricciones identidad (lo que un presupuesto real tiene),
el Laplaciano de haces colapsa a d_r Laplacianos escalares = el router de T9b
d_r veces (test identidad_colapsa_...). El haz sólo importaría con coupling en
bases incompatibles, que no es requisito real. Consistente con todo el arco: el
haz nunca fue lo que sostuvo la garantía. Recomendación: si Tawasuyu necesita
multi-invariante, usar el certificado del politopo + routers escalares; NO
promover reach.rs a estable ni venderlo como 'potenciado por haces'. Frontera
abierta dicha: restricciones no monótonas (C con signos mixtos) no cubiertas.
85 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unifica todo el proyecto tras adapter::SovereignAccount, con las precondiciones
del contrato §H en el centro:
- SubstrateCapabilities + AdapterError: open() REHÚSA (NoDurability /
NoDeviceIdentity) si el sustrato no cumple, en vez de prometer seguridad que
no tiene. La negativa es parte del diseño.
- Compone las piezas: EscrowState (presupuesto con procedencia, T10a) + WAL
durable por dispositivo (T11b) + ruteo edge-local por el nervio (T9b/T10b) +
época de fencing (T11c).
- API: spend (local | rebalanceo | Rejected{spendable}, fail-safe), available,
value/invariant_holds (certificado value≥floor), recover (desde WAL),
reboot (época), sync (Ok | CloneDetected como ALARMA, no recuperación).
M4.md: contrato congelado en tabla (cláusula → cómo se cumple → test), la API
pública, qué compone cada garantía, y las fronteras dichas (no previene clon;
no hay disponibilidad ilimitada bajo partición; no es motor de replicación).
Nerve ahora deriva Clone. 81 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dos precisiones para que el registro diga exactamente lo que el código hace:
- durable: documentar que `real` es un oráculo INDEPENDIENTE del desembolso
FÍSICO al usuario — se incrementa en el ack (punto de entrega externo e
irreversible), una vez por retiro entregado, y NUNCA lee la contabilidad
interna (value/committed). Cuenta eventos de entrega, no lo que el sistema
cree que gastó. El guard usa la contabilidad para decidir; si se corrompe
(rollback) se entrega de más y `real` lo atrapa. Ahí vive detección vs
prevención.
- BOUNDARY.md: CloneDetected es una ALARMA, no una recuperación. El daño de
una celda ya ocurrió en el mundo (dinero real entregado); aislar evita que
el doble conteo se propague, pero no recupera nada. La compensación vive
fuera del sistema, es coordinación, y puede fracasar. Acotado y delatado,
sí; reversible, no necesariamente. Para que M4 no lo lea como auto-reparación.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completa lo que faltaba de §G.4 (antes solo estaban los tests positivos):
- fencing: witness_clone_detected_impreso imprime el testigo (dos épocas 1/2,
total_claimed=100 de una celda de 50, reconciled=50 [linaje vivo], gasto
aislado=50 [clon obsoleto], overspend=50<=budget ⟹ daño acotado a UNA celda).
- durable: valor_real_tras_rollback(con_durabilidad) — tally independiente del
desembolso real. CON durabilidad: recover atrapa el rollback, re-gasto
bloqueado, valor real=0 (VERDE). SIN durabilidad: doble gasto, valor real=-50
(ROJO). g4_el_certificado_se_pone_rojo_bajo_rollback (#[should_panic]) prueba
que la aserción del certificado FALLA ruidosamente sin la capa de durabilidad
— el diente de §G.1/§G.4.
69 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T11 §D: una celda con dos escritores vivos que no se comunican es IMPOSIBLE
de resolver coordination-free (CAP dentro de la celda). El fencing es lo mejor
posible: bounded + detect, no prevent.
- fencing::FencedCell: spent indexado por (device_id, epoch); epoch monótona
DEVICE-LOCAL (evita consenso), persistida al arrancar (boot). merge une por
máximo por época y devuelve MergeOutcome::CloneDetected{device_id,
stale_epoch, live_epoch} cuando halla dos linajes. overspend acotado a una
celda; reconciled_spent = solo el linaje vivo (aísla el obsoleto).
Tests §G.3 (clon detectado, acotado a una celda, delatado; el linaje vivo no
propaga el doble gasto) y §G.4 (fuente monótona una época = Ok; el clon nunca
pasa como Ok silencioso). proptest: daño de clon siempre ≤ una celda.
BOUNDARY.md: el teorema de imposibilidad, la garantía real (bounded+detect vs
el fencing token linealizable de Kleppmann), y por qué epochs device-local.
STRONG_RESULT.md: el terminus honesto §E (seguridad coord-free módulo un
supuesto físico nombrado) + el contrato de M4 §H listo para escribir.
73 tests, clippy limpio. Hito T11 cerrado.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T11 §B: el supuesto oculto de T10 (spent monótono en la fuente) se hace real
con un write-ahead log. Un gasto se ackea SOLO tras persistirse; un crash
pierde gastos no reconocidos, jamás uno reconocido.
- durable::WriteAheadLog (committed solo crece; commit_spend persiste antes de
devolver AckToken) + DurableSpent (wal durable + live volátil; recover
reconstruye live desde el WAL ⟹ nunca por debajo del último ack).
- try_restore_snapshot rechaza restaurar por debajo del WAL (adversario de
rollback → doble gasto).
Tests §G.1 (el crash MALO, no el benigno): el WAL sobrevive al crash y no
olvida; el adversario que intenta revertir por debajo del compromiso durable
es rechazado. Con dientes: proptest sobre secuencias de gastos+crashes
(value nunca cae bajo el ack) y rollbacks (siempre rechazados).
Combinado con el merge por max de T10, garantiza la monotonía que el
certificado exige. 69 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T11 §C: el supuesto oculto de T10 (spent monótono-durable en la fuente) se
rompe con multi-writer. Cura F2: NO modelar la identidad como una réplica —
una identidad es un CONJUNTO de celdas-dispositivo, cada una réplica del
esquema de T10 con su b0[device] y spent[device].
- escrow::Identity { devices, inv }: total_avail/value/invariant_holds sobre
las celdas de la identidad. La disciplina single-writer se cumple a nivel
de celda-dispositivo, no de identidad.
Tests §G.2: dos dispositivos gastan concurrentemente sin pisarse (el gasto de
uno no toca el avail del otro; cada celda un único escritor); rebalanceo entre
dispositivos = grant, conserva total_avail; identidades disjuntas aisladas.
F2 es un no-problema por diseño, coordination-free, sin fencing (eso es solo
la frontera del clon, §D/T11c). 65 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T10 §F.5: sube el certificado de estático a DINÁMICO. proptest que entrelaza
gastos + grants concurrentes + crashes (grants sin propagar) + particiones
(merges en orden arbitrario) sobre copias por réplica, y verifica en TODO
momento:
- valor = inicial − Σ spent ≥ K (nunca sobregira);
- total_avail ≥ 0 (nunca fabrica presupuesto).
Subsume el certificado estático de T9. Con single-writer por réplica (spend/
grant guardados por el avail local) y merge CRDT, ninguna carrera rompe la
conservación.
STRONG_RESULT.md: marca la evitación de escrow como segura DINÁMICAMENTE (no
solo snapshot) y declara M4 desbloqueado de verdad, con la honestidad §G
(T10 = Bounded Counter/CRDT clásico bien implementado, no novedad; el aporte
sigue siendo el ruteo/localización por el grafo).
62 tests, clippy limpio. Hito T10 cerrado.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T10 §D/§F.4: T9 no definía el eslabón cuando no hay ruta al presupuesto
(partición). Ahora:
- router::RebalanceResult { Routed{edges} | Unreachable }. rebalance_to es
TRANSACCIONAL: si las vecinas directas cubren el déficit aplica el flujo
(Routed); si no, no mueve nada y devuelve Unreachable. Nunca a medias, nunca
bloquea.
- SpendOutcome + spend_with_rebalance: gasta local, o repone por rebalanceo, o
ante Unreachable RECHAZA con spendable = presupuesto local (fail-safe). Nunca
sobregira ni cuelga.
Tests: el 60/60 particionado con [50,50] → Unreachable → Rejected{spendable:50}
(gasta ≤50, valor≥0); con ruta se cubre por rebalanceo. Tests de T9b migrados a
la nueva firma.
AVAILABILITY.md (§F.6): el precio honesto del escrow — bajo partición la réplica
se limita a su presupuesto local (CAP: safety > availability); diffuse lo mitiga,
no lo elimina; sin promesas de liveness, solo safety. 61 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T10 §C.1 (vía Balegas): sube el certificado de estático a con-base-dinámica.
El Budget mutable de T9 (b_i leído-y-escrito) era seguro solo en snapshots
secuenciales; una transferencia concurrente podía FABRICAR presupuesto (§B).
- escrow::EscrowState { b0 constante, granted[from][to] monótono, spent[i]
monótono }. avail derivado; grant/spend guardados por avail local
(single-writer por fila ⟹ sin conflicto); merge por max (CRDT).
- Teorema §C: Σ avail = Σ b0 − Σ spent, invariante a los granted (se cancelan:
+en i, −en j). Imposible fabricar por fusión; imposible perder por crash
(un grant vive entero en granted[from][to]).
Tests: el modo de fallo §B prevenido en el origen (segundo grant de 20 falla);
crash a mitad de transferencia seguro; proptest total_avail_es_invariante
(Σ avail == Σb0−Σspent siempre); merge conmutativo/idempotente; merge nunca
sube el total. Budget de T9 se conserva (router migra en T10b).
59 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T9 §F/§G. Documentación fundamentada en tests, no a mano:
- tests/comparison.rs: corre detector T8 vs escrow T9 sobre los mismos
escenarios; los veredictos de la tabla son exactamente los aserados.
- COMPARISON.md: tabula detector vs escrow. Fila 3 (particionado 60/60):
detector da FALSO-VERDE (corre libre al caso más peligroso), escrow lo
bloquea con NeedsRebalance — con o sin partición. Rendimiento (reparto)
separado de corrección (certificado).
- STRONG_RESULT.md reescrito (§G): RETIRA el reclamo fuerte de T8
('más fino que CALM / I-confluence sobre el grafo real'). Documenta:
(1) era detección, no evitación; (2) no hay separación vs I-confluence/CALM
(Prop.3); (3) el 60/60-particionado era un BUG (punto ciego), no virtud.
Apunta a escrow+router como la evitación real, con la honestidad §B
(escrow transforma la operación, no vence a CALM).
54 tests, clippy limpio. Hito T9 cerrado: de detección a evitación.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T9 §C: el Laplaciano lineal, que en el MVP era un detector con falso-positivo
(H¹=β₁), reaparece como ruteador de presupuesto legítimo. Misma máquina,
problema correcto.
- nerve: por fin útil — Nerve::from_edges/num_replicas/edges/neighbors sobre
el grafo petgraph (era scaffold desde M0).
- router::BudgetRouter (reusa el nervio):
· rebalance_to(r, deficit): flujo MÍNIMO que repone a r desde vecinas con
excedente; devuelve (desde,hacia,monto). Conserva Σb, solo aristas
adyacentes a r.
· diffuse(): paso de Laplaciano (promediado por pares, mitad entera de la
diferencia) que suaviza conservando Σb y sin aumentar la varianza; deja
los presupuestos no negativos. TODO: Laplaciano de haces si multi-recurso.
Tests (+ proptest): rebalanceo conserva Σb y solo toca vecinas del nodo seco;
diffuse conserva Σb y no aumenta Σb² (varianza). 53 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T9 §A/§B: corrige los dos errores de T8c. (1) el veredicto de T8 era
DETECCIÓN reactiva por-estado, no evitación; (2) trataba un invariante
GLOBAL como edge-local, de ahí el falso-verde particionado.
- invariant::GlobalInvariant (restricción global valor≥floor, no edge-local;
slack = initial - floor).
- escrow::Budget/SpendResult: reparto con Σ b_i ≤ slack (is_valid_split,
split proporcional por división entera), gasto local try_spend (Local |
NeedsRebalance{deficit}), certificado value_after.
- verdict::Verdict::via_escrow: Local→RunsFree (cero coord, correcto incluso
particionado), NeedsRebalance→NeedsCoordination localizado. Nunca 'libre
global' a ciegas.
Tests: EL CERTIFICADO (proptest) — para todo reparto válido y todo gasto
spent_i ≤ b_i (particiones y máximos incluidos), valor = inicial - Σspent ≥
piso, por construcción. El caso 60/60 con [50,50]: particionado recibe
NeedsRebalance (bloqueado), no Local — muere el falso-verde. El detector de
T8 se conserva pero su 'topología importa' se reetiqueta como PUNTO CIEGO.
Honestidad §B: escrow no vence a CALM, transforma la operación para que sea
I-confluente. 49 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T8 §C-§F: la coordinación real no vive en el tipo de dato sino en un
INVARIANTE que la fusión no preserva. Modelo canónico de Bailis (saldo ≥ 0).
- invariant::AccountConfig: bound + retiros por réplica + grafo. Estado =
GCounter grow-only de retiros; V = {s : bound ≥ Σ retiros}.
- haz_verdict (§C): reconcilia por el orden nativo y corre libre ⟺ punto
fijo ∈ V, con localización de réplicas/aristas culpables.
- i_confluence_oracle: oráculo independiente (suma por componente vía
union-find), camino distinto de la difusión.
- calm_syntactic: condena el retiro por-programa (a batir).
VERSIÓN FUERTE PROBADA (STRONG_RESULT.md): testigo A (retiros [10,10] sobre
100) → haz=libre / CALM-sintáctico=coordina con I preservado. Barrido halla
>100 testigos. proptest: haz == I-confluence en toda instancia (corrección);
haz nunca miente (soundness). La topología importa: mismos 60/60 corren
libres particionados y coordinan conectados.
Honestidad §F: el booleano ES I-confluence (Bailis 2014), no más allá de
CALM; la novedad es el cómo (topología-consciente, difusión a punto fijo) y
la propina (estado reconciliado + nudo). M4 desbloqueado. main muestra el
testigo. 46 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T8 §B/§F: el oracle_verdict de T4 usaba la etiqueta monotone = monotonía de
VALOR. Un LWW-register baja de valor pero es un CRDT (monótono en su orden
de fusión), luego CALM real lo declara libre. Separo:
- calm_syntactic: el check grueso por-programa (coordina ante cualquier op
no monótona en valor). Es la respuesta a batir en T8c.
- oracle_verdict (corregido): monotonía en el orden de FUSIÓN. Todo CRDT
puro es CoordinationFree en cualquier grafo; la coordinación real solo la
trae un invariante (T8c).
Tests históricos (lineal, labeled) repuntados a calm_syntactic (el oráculo
grueso que espejaban). Nuevo test t8b: oráculo corregido y haz nativo
coinciden en todo CRDT puro — acuerdo correcto (ambos ven que el merge
reconcilia), no circular como el de T7.
40 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T8 §A/§B: el acuerdo perfecto de T7 con el oráculo era en parte circular
(el encoding leía la etiqueta monótono/reset via 'generación = componente
del subgrafo monótono'). T8a deriva el orden MECÁNICAMENTE del merge:
- native::Merge (join := merge del CRDT; a ≤ b := merge(a,b)==b) + reconcile
(propagación de joins a punto fijo). Impls para GCounter y LWW register.
- oracle: tarski_verdict ahora es NATIVO (no lee la etiqueta); el circular
de T7 se conserva como tarski_verdict_labeled (control histórico).
tarski_reconcile expone el estado reconciliado (la 'propina' del haz).
- Bajo el orden nativo el LWW-register es una CADENA → reconcilia al máximo
→ corre libre. Todo CRDT puro corre libre en cualquier grafo (ciclos incl.).
FLIPS.md: 8 casos con reset voltean de 'coordina' (T7 circular) a 'corre
libre' (nativo). Cada flip prueba que T5-T7 era circular ahí. DISCREPANCIES.md
anota la salvedad. La versión débil (haz colapsa a CALM) no está descartada;
se decide en T8c.
39 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addendum §F/T7 — cierra la brecha de modelado de §2.3:
- verdict::Verdict::via_tarski(sheaf, seed): harmoniza y lee. Corre libre si
el punto fijo no colapsa a ⊤; coordina si colapsa, con localización difusa
(R-L1: aristas cuyo desacuerdo sobrevive al punto fijo).
- oracle: Config::tarski_verdict encoda cada config como haz de retículos
(ResetVal uniforme, generación = componente del subgrafo monótono) y
harmoniza. Tests maestros: Tarski coincide con el oráculo en TODA la
batería; y resuelve las discrepancias del lineal (triángulo/cuadrado
monótono → corre libre, igualando a CALM).
- properties: invariante nuevo 'monótono sobre grafo arbitrario (cíclico
incluido) ⟹ corre libre' — el que el MVP lineal no podía satisfacer.
- main: contraste en vivo (lineal coordina vs Tarski corre libre).
- DISCREPANCIES.md: entradas marcadas RESUELTAS; documentado el porqué
(eliminar la resta del coboundary) y el residuo abierto (ninguno).
35 tests, clippy limpio. La Hipótesis H pasa de 'solo el caso acíclico' a
'se sostiene en general' bajo el encoding de retículos.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addendum §D/T6, aditivo — el motor lineal intacto:
- tarski::LatticeSheaf (haz constante de retículos) y TarskiLaplacian con
step (fórmula Ghrist-Riess Def.2/Lemma7: join sobre arista, F* adjunta,
meet sobre aristas incidentes; sin resta) y harmonize (Kleene ascendente
a punto fijo, con cota de seguridad).
- Prueba de cordura CLAVE (la inversión): sobre el mismo triángulo donde el
haz constante LINEAL inventa H¹=β₁=1, la difusión de Tarski con datos
monótonos NO tiene obstrucción (preserva lo local, no colapsa a ⊤).
- Un reset incompatible (generación incomparable) colapsa a ⊤: obstrucción
semántica real, no topológica (§C.4).
- Convergencia en tiempo finito verificada + punto fijo genuino.
32 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addendum §D/T5, aditivo — no toca el motor lineal:
- lattice::LatticeCell (join/meet/bottom/top) y GaloisRestriction
(lower/upper adjuntos, ley lower(a)≤b ⟺ a≤upper(b)).
- Encodings §D.1: Nat (casilla GCounter, cadena ℕ con ⊤=∞) y ResetVal
(ResettableRegister; post-reset incomparable → join de generaciones
distintas colapsa a ⊤, meet a ⊥: la obstrucción semántica de §C).
- IdentityGalois y ScaleGalois (adjunción k·a≤b ⟺ a≤⌊b/k⌋).
- proptest: leyes de retículo (conmut/asoc/idemp/absorción/neutros) para
Nat y ResetVal, colapso de incomparables, ley adjunta de Galois y
monotonía de lower.
ADDENDUM.md incorporado (antes addendumsdd.txt). 29 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- oracle: Config/Share, oracle_verdict (CALM independiente: free ⟺ toda
op compartida monótona), to_sheaf (codificación honesta: reset → 2-ciclo
en conflicto), sheaf_verdict (H¹ vía GF(2)).
- Batería casos_de_acuerdo() (21 casos ≥20) + test maestro: el haz coincide
con el oráculo en todo el régimen de acuerdo.
- casos_de_discrepancia() + test: datos monótonos sobre grafo cíclico donde
el haz ve una falsa obstrucción topológica (Hipótesis H falla, dirección
conservadora). Documentado en DISCREPANCIES.md — el 'oro científico' de R1.
- tests/properties.rs (proptest, §9): (1) monótono sobre bosque → H¹=0,
(2) añadir arista no reduce H¹ ni aumenta H⁰, (3) haz constante reproduce
los números de Betti (H⁰=componentes, H¹=E−V+C) sobre grafos aleatorios.
24 tests pasan (incl. 3 propiedades), clippy limpio. Cierra el MVP: M0–M3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- gf2: Gf2Backend bit-packed con u64 (BitMatrix, eliminación gaussiana
sobre F2 vía XOR de filas). rank y cokernel_basis exactos, sin epsilon.
Reduce las entradas f64 mod 2 (-1 ≡ 1). Detrás del mismo trait LinAlg.
- cohomology/tests: cross-validan que f64 y GF(2) coinciden en H⁰/H¹.
- verdict: test de 'todos los ciclos obstruidos' (dos triángulos → 2 nudos).
- tests/m1.rs: M1 verificado también en exacto; localización idéntica en
ambos backends.
Base matemática: sobre GF(2) el espacio de ciclos tiene dim E−V+C = b₁,
así la cordura §7.2 y M1 dan resultados idénticos que f64 pero exactos.
19 tests, clippy limpio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- cell: impl Cell para GCounter (join por máximo, is_monotone=true) y
ResettableRegister (reset no monótono, is_monotone=false), con tests de
las leyes de retículo y de la no-monotonía.
- verdict: Verdict::diagnose(sheaf, coho) localiza cada generador del
cokernel en réplicas/aristas concretas (§6.5) + Display legible.
- main: hito M1 (§8). Corrida A (G-Counter, camino acíclico) → H¹=0 →
corre libre. Corrida B (ResettableRegister, enlace doble irreconciliable
entre réplicas 1 y 2) → H¹≠0 → nudo localizado entre réplicas 1 y 2.
- tests/m1.rs fija el criterio de éxito: A=0, B≠0, localización correcta.
13 tests pasan, clippy limpio. Modelado de frontera (§2.3/Q1) documentado
en comentarios: H¹≠0 nace de ciclos en el grafo de compartición.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implementa el corazón (§7):
- linalg: F64Backend::rank y cokernel_basis vía RREF con pivoteo parcial;
Matrix con identity/transpose/get/set.
- sheaf: ensamblado del coboundary δ (bloque +R_u / -R_v por arista) con
validación de dimensiones, y constructor Sheaf::constant.
- cohomology::compute + compute_with(backend): rank δ, dim H⁰, dim H¹ y
base del cokernel como localización de la obstrucción.
Cordura topológica (§7.2) verde: árbol H¹=0, triángulo H¹ dim1, dos
triángulos pegados H¹ dim2, bosque desconexo H⁰=2, stalk d=2 escala Betti.
9 tests pasan, sin warnings de clippy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Estructura de módulos (§5) sin lógica todavía: cell, nerve, sheaf,
cohomology, verdict, oracle, más error y linalg (trait LinAlg con impl
f64 vacía). Deps petgraph/nalgebra/thiserror + proptest dev-dep.
main imprime "hello sheaf"; test dummy pasa. DESIGN.md (antes sdd.txt).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>