From e5ea87bf5cf2c9a6300814f26d237249d6fb8693 Mon Sep 17 00:00:00 2001 From: Marius Talpos Date: Sun, 6 Sep 2026 19:31:44 -0400 Subject: [PATCH 1/2] docs: link shared EU AI evidence phase tracker --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d14be2d..13cc0b2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # GKOS-Engine +**Owner-fork work:** [EU AI evidence demonstration — shared phases and status](https://github.com/mariusTalpos/gkos-standard/blob/planning/eu-ai-evidence/docs/eu-ai-evidence/PHASES.md). The Standard fork hosts the single tracker for both repositories. + Operator settings: [complete settings reference](docs/SETTINGS.md) and [all TOML coordinates](docs/SETTINGS-TOML.md). Run `gkx settings --runtime desktop --json` to distinguish configuration wiring from runtime readiness. Integration/remaining-work tracker: [#36](https://github.com/Odenknight/GKOS-Engine/issues/36). Turn a folder of Markdown into a dependable knowledge map—locally, From 07f13e810aed23dd66cf843ed39b5c214f10b021 Mon Sep 17 00:00:00 2001 From: Marius Talpos Date: Mon, 7 Sep 2026 09:55:02 -0400 Subject: [PATCH 2/2] test: add P1.1 dossier observation adapter Signed-off-by: Marius Talpos --- examples/eu-ai-evidence/p1-observer.mjs | 18 ++++++++++++ test/eu-ai-p1-observer.test.mjs | 38 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 examples/eu-ai-evidence/p1-observer.mjs create mode 100644 test/eu-ai-p1-observer.test.mjs diff --git a/examples/eu-ai-evidence/p1-observer.mjs b/examples/eu-ai-evidence/p1-observer.mjs new file mode 100644 index 0000000..4cf66cf --- /dev/null +++ b/examples/eu-ai-evidence/p1-observer.mjs @@ -0,0 +1,18 @@ +/** Informative P1.1 observer. No expectations, selection rules, or verdicts. */ +import { buildGraph, ENGINE_NAME, ENGINE_VERSION } from '../../dist/gkos-engine.mjs'; + +export function observeDossierSnapshot({ records, now }) { + if (!Array.isArray(records) || !Number.isFinite(now)) { + throw new TypeError('records and a finite fixed observation time are required'); + } + for (const record of records) { + if (typeof record.relativePath !== 'string' || typeof record.content !== 'string' + || !Number.isFinite(record.createdTime) || !Number.isFinite(record.modifiedTime)) { + throw new TypeError('Each record requires a path, content, and explicit source times'); + } + } + return { + engine: { name: ENGINE_NAME, version: ENGINE_VERSION }, + graph: buildGraph(records, [], now), + }; +} diff --git a/test/eu-ai-p1-observer.test.mjs b/test/eu-ai-p1-observer.test.mjs new file mode 100644 index 0000000..5f9fb01 --- /dev/null +++ b/test/eu-ai-p1-observer.test.mjs @@ -0,0 +1,38 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { observeDossierSnapshot } from '../examples/eu-ai-evidence/p1-observer.mjs'; + +const uid1 = '719823a1-5299-48ba-89e0-6771f6fbbba1'; +const uid2 = '719823a1-5299-48ba-89e0-6771f6fbbba2'; +const source = (uid, path, at, predecessor) => Object.freeze({ + relativePath: path, + createdTime: Date.parse(at), modifiedTime: Date.parse(at), + content: `---\ngkx_version: "2.0"\nuid: "${uid}"\ntitle: "${path}"\ntype: semantic\ncreated_at: "${at}"\ntimestamp: "${at}"\nepistemic_state: reported\nsensitivity: public\nauthorship_origin: authored\n${predecessor ? `supersedes:\n - "${predecessor}"\n` : ''}---\nFictional observer test.\n`, +}); + +test('P1 observer exposes actual UID resolution and one-sided lineage without changing input', () => { + const at = '2026-08-02T10:00:00.000Z'; + const records = Object.freeze([ + source(uid1, 'one.md', '2026-08-01T10:00:00.000Z'), + source(uid2, 'two.md', at, uid1), + ]); + const before = JSON.stringify(records); + const result = observeDossierSnapshot({ records, now: Date.parse('2026-08-03T12:00:00Z') }); + const first = result.graph.nodes.find(n => n.id === result.graph.gkxUidIndex[uid1]); + const second = result.graph.nodes.find(n => n.id === result.graph.gkxUidIndex[uid2]); + assert.deepEqual(first.gkx.supersededByIds, [second.id]); + assert.deepEqual(second.gkx.supersedesIds, [first.id]); + assert.equal(first.gkx.invalidAt, at); + assert.equal(first.gkx.head, false); + assert.equal(second.gkx.head, true); + assert.equal(first.gkx.projection.authored.uid, uid1); + assert.equal(JSON.stringify(records), before); + assert.equal('pass' in result, false); + assert.equal('selection' in result, false); +}); + +test('P1 observer rejects unavailable input instead of fabricating an observation', () => { + assert.throws(() => observeDossierSnapshot({ records: null, now: 1 }), TypeError); + assert.throws(() => observeDossierSnapshot({ records: [], now: NaN }), TypeError); + assert.throws(() => observeDossierSnapshot({ records: [{ relativePath: 'missing.md' }], now: 1 }), TypeError); +});