Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
18 changes: 18 additions & 0 deletions examples/eu-ai-evidence/p1-observer.mjs
Original file line number Diff line number Diff line change
@@ -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),
};
}
38 changes: 38 additions & 0 deletions test/eu-ai-p1-observer.test.mjs
Original file line number Diff line number Diff line change
@@ -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);
});