From dd1388abb74951c59bfd3619867ceec89bbc9d39 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 22 Aug 2026 20:52:57 -0500 Subject: [PATCH] chore(okf): revisa OKF v0.2 y reconoce el hash; el proyector no cambia MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El vigía salia con exit 10 desde el 2026-07-24: el SPEC upstream paso de v0.1 (15 KB) a v0.2 (37,7 KB), una reescritura de 2,5x. Esta es la revision que el guard pedia, y su conclusion es que NO hay que tocar la proyeccion. Como se reviso. Recuperados los cuatro blobs del historial upstream y hasheados para anclar los extremos: el lock apuntaba a ee67a5ca (b9655e60..., v0.1) y el upstream es 62432a09 (26aa5da0..., **Version 0.2**). Con los dos textos delante, el propio SPEC trae una seccion §13 "Changes from v0.1" con §13.1 Breaking changes — no hace falta diffear a mano las 61 secciones. (Mi primer grep buscaba "Changelog/History/Revision" y no la vio; el dato estaba ahi.) Las dos roturas declaradas, contra lo que emitimos: 1. `timestamp` queda superseded por `generated: { by, at }`. Nos afecta: emitimos `timestamp: '2026-07-28'`. Pero §13.1 dice que el consumidor MAY caer al `timestamp` legado cuando falta `generated`, asi que el bundle sigue siendo consumible por un lector v0.2. 2. El listado `# Citations` del cuerpo queda superseded por `sources`. NO nos afecta: emitimos cero `# Citations` (verificado sobre el bundle). Y lo que §13 declara explicitamente que NO cambia es justo aquello sobre lo que se apoya el ADR-0105: estructura del bundle, nombres reservados, el `type` obligatorio, los recomendados title/description/resource/tags, cross-linking, index, logs y la conformidad permisiva. Nuestro validador solo exige `type` no vacio, y `--check`/`--verify` pasan (15 ficheros, 0 violaciones). El ADR-0105 ya habia previsto este caso en su seccion de riesgos ("OKF v0.1 is young... watched by knowledge-okf-standard-watch"), y sus afirmaciones de v0.1 siguen siendo exactas: proyectamos v0.1, a proposito. Por eso el lock se acepta y el proyector no se toca. Queda como mejora OPCIONAL, no como deuda: adoptar `generated: { by: human:@winston, at: ... }` haria que un consumidor v0.2 clasifique el corpus como autorado por humano (§5.3 keys off the `human:` prefix) en vez de caer al `timestamp` sin procedencia. Es un cambio del bundle publicado y una decision sobre como representamos confianza, no una correccion. Aparte, un fallo del propio vigia encontrado al usarlo: `--accept` reconocia el hash y acto seguido imprimia "NO ha sido reconocido... confirma con --accept", y mostraba en `locked:` el hash VIEJO. Se lee como que el reconocimiento fallo. Causa: `status` solo miraba si el upstream cambio, sin distinguir lo que hizo esa corrida. Se anade `accepted` (no toca el vocabulario de `status`, que un test fija) y el informe pasa a decir "Cambio upstream RECONOCIDO" con el hash nuevo. Cubierto por dos tests: 8 -> 9 en verde. Verificacion: --check 0 violaciones, --verify al dia, guard offline exit 0, el vigia sin flag reporta `status: ok`, y el escenario de --accept reproducido de extremo a extremo rebobinando el lock y restaurandolo (identico byte a byte). Co-Authored-By: Claude Opus 5 Signed-off-by: aarroyo --- .harness/scripts/knowledge-okf-standard-watch.mjs | 15 +++++++++++++-- .../scripts/knowledge-okf-standard-watch.test.mjs | 12 ++++++++++++ reference/knowledge/canonical/okf-spec.lock.json | 4 ++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/.harness/scripts/knowledge-okf-standard-watch.mjs b/.harness/scripts/knowledge-okf-standard-watch.mjs index 94f78edbf..6fc919723 100644 --- a/.harness/scripts/knowledge-okf-standard-watch.mjs +++ b/.harness/scripts/knowledge-okf-standard-watch.mjs @@ -53,6 +53,7 @@ export function staleness(lock, now, staleDays = STALE_DAYS) { /** * Núcleo del vigía (puro: fetch inyectado). Devuelve { status, nextLock, exitCode, ... }. * status: 'initialized' | 'ok' | 'changed' | 'error'. + * accepted: true cuando ESTA ejecución reconoció un cambio upstream (--accept sobre 'changed'). */ export async function runWatch({ lock, fetchText, url = SPEC_URL, now, accept = false, init = false }) { let text; @@ -87,6 +88,12 @@ export async function runWatch({ lock, fetchText, url = SPEC_URL, now, accept = upstream, lockedHash: lock.sha256, nextLock, + // `status` describe el ESTADO DEL UPSTREAM (cambió o no) y se mantiene + // 'changed' aunque se acepte, porque es lo que ocurrió. `accepted` describe + // lo que hizo ESTA ejecución. Sin distinguirlos, `--accept` reconocía el hash + // y acto seguido imprimía "NO ha sido reconocido... confirma con --accept", + // que se lee como que el reconocimiento falló. + accepted: changed && accept, // 'changed' sin --accept es advisory (10); aceptado o al día = 0. exitCode: changed && !accept ? 10 : 0, }; @@ -122,11 +129,15 @@ function report(result, lock, now) { console.error(`error: ${result.message} — lock intacto, frescura sin cambio.`); return; } - console.log(`locked: ${short(result.lockedHash ?? result.upstream)}`); + console.log(`locked: ${short(result.nextLock?.sha256 ?? result.lockedHash ?? result.upstream)}`); console.log(`upstream: ${short(result.upstream)}`); console.log(`checkedAt: ${result.nextLock.checkedAt} reviewedAt: ${result.nextLock.reviewedAt}`); console.log(`freshness: ${s.stale ? 'STALE' : 'fresh'} (${s.daysSinceChecked ?? 'never'} d; umbral ${s.staleDays} d)`); - if (result.status === 'changed') { + if (result.accepted) { + console.log(''); + console.log('✅ Cambio upstream RECONOCIDO: sha256 y reviewedAt actualizados.'); + console.log(' Commitea el lockfile (es metadato canónico, no derivado).'); + } else if (result.status === 'changed') { console.log(''); console.log('⚠️ El estándar OKF cambió upstream y NO ha sido reconocido.'); console.log(' Acción de Winston: revisa el SPEC + [ADR-0105], ajusta knowledge-okf-project.mjs'); diff --git a/.harness/scripts/knowledge-okf-standard-watch.test.mjs b/.harness/scripts/knowledge-okf-standard-watch.test.mjs index 263d5f6da..d37798af6 100644 --- a/.harness/scripts/knowledge-okf-standard-watch.test.mjs +++ b/.harness/scripts/knowledge-okf-standard-watch.test.mjs @@ -62,6 +62,18 @@ test('runWatch --accept reconoce el nuevo hash y baja a exit 0', async () => { assert.equal(r.exitCode, 0); // aceptado assert.equal(r.nextLock.sha256, sha256(SPEC + '\n## New section\n')); assert.equal(r.nextLock.reviewedAt, '2026-07-07'); + // `accepted` distingue "el upstream cambió" de "esta corrida lo reconoció": + // sin él, --accept imprimía el aviso de "NO ha sido reconocido" tras reconocerlo. + assert.equal(r.accepted, true); +}); + +test('runWatch sin --accept deja accepted=false sobre un cambio upstream', async () => { + const lock = { sha256: sha256(SPEC), checkedAt: '2026-06-01', reviewedAt: '2026-06-01' }; + const r = await runWatch({ lock, fetchText: fetchChanged, now: '2026-07-07' }); + assert.equal(r.status, 'changed'); + assert.equal(r.accepted, false); + assert.equal(r.exitCode, 10); + assert.equal(r.nextLock.sha256, sha256(SPEC)); // el hash NO se mueve sin reconocer }); test('runWatch falla cerrado en error de red sin tocar el lock', async () => { diff --git a/reference/knowledge/canonical/okf-spec.lock.json b/reference/knowledge/canonical/okf-spec.lock.json index fd4b8d8e3..fe7ded70b 100644 --- a/reference/knowledge/canonical/okf-spec.lock.json +++ b/reference/knowledge/canonical/okf-spec.lock.json @@ -2,8 +2,8 @@ "spec": "OKF", "version": "0.1", "sourceUrl": "https://raw.githubusercontent.com/GoogleCloudPlatform/knowledge-catalog/main/okf/SPEC.md", - "sha256": "b9655e607346dbbdc6de21190e9a953313eda6a7eba68d4d272a65975940ad6e", + "sha256": "26aa5da029278939f914e578107242d9607d4f2dc5fe153272b82f9ed1030101", "checkedAt": "2026-08-23", - "reviewedAt": "2026-07-08", + "reviewedAt": "2026-08-23", "adr": "ADR-0105" }