Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab18540d7e | ||
|
|
f489467e1b | ||
|
|
64172d8675 | ||
|
|
8e75414907 | ||
|
|
7a9d823792 | ||
|
|
98b5a73ed1 | ||
|
|
4a9d8001c1 | ||
|
|
538bbeb821 | ||
|
|
cc3b3d81eb | ||
|
|
eb01156d9f | ||
|
|
290d264f31 | ||
|
|
16c147dbee | ||
|
|
15cba0bb24 | ||
|
|
1283b0bf94 | ||
|
|
1ee35d76c9 | ||
|
|
e8daf78eaa | ||
|
|
19976c310c | ||
|
|
e2430a9154 | ||
|
|
de5445357e | ||
|
|
e94c8e27a8 | ||
|
|
0816c5997d | ||
|
|
b502a1d7e8 | ||
|
|
0cd587dfd3 | ||
|
|
8404cddb1d |
No files matched your search
@@ -72,7 +72,8 @@ jobs:
|
||||
const managedLabels = new Set([
|
||||
'memory', 'governance', 'identity', 'growth',
|
||||
'perception', 'infrastructure', 'life', 'custodian',
|
||||
'priority: high', 'bug', 'feature', 'research',
|
||||
'bug', 'feature', 'research',
|
||||
'P0 — critical', 'P1 — high', 'P2 — medium', 'P3 — low',
|
||||
]);
|
||||
|
||||
// Type label: DECLARED over GUESSED. The template spine
|
||||
@@ -135,9 +136,31 @@ jobs:
|
||||
desiredLabels.add('custodian');
|
||||
}
|
||||
|
||||
// Priority labels
|
||||
if (text.includes('urgent') || text.includes('critical') || text.includes('broken')) {
|
||||
desiredLabels.add('priority: high');
|
||||
// Priority labels (2026-10-05: PROGRAMMATIC P-ASSIGNMENT —
|
||||
// the gate demanded P0-P3 labels but nothing assigned them;
|
||||
// the dead 'priority: high' label is gone per the 2026-09-04
|
||||
// normalization). Assignment from the TITLE prefix first
|
||||
// ([P1]/P1:/priority=...), then keyword inference using the
|
||||
// gate's own rule set (the scale lives in ONE place — the
|
||||
// priority-gate job above).
|
||||
const pMatch = title.match(/\bP([0-3])\b/);
|
||||
const priorityLabelNames = ['P0 — critical', 'P1 — high', 'P2 — medium', 'P3 — low'];
|
||||
if (pMatch) {
|
||||
desiredLabels.add(priorityLabelNames[Number(pMatch[1])]);
|
||||
} else if (text.includes('urgent') || text.includes('critical') ||
|
||||
text.includes('spine') || text.includes('blocks other work')) {
|
||||
desiredLabels.add(priorityLabelNames[0]); // P0 — critical
|
||||
} else if (text.includes('broken') || text.includes('fix') ||
|
||||
text.includes('repair') || text.includes('defect') ||
|
||||
text.includes('real defect') || text.includes('money')) {
|
||||
desiredLabels.add(priorityLabelNames[1]); // P1 — high
|
||||
} else if (text.includes('improve') || text.includes('consolidat') ||
|
||||
text.includes('refactor') || text.includes('kernel') ||
|
||||
text.includes('port')) {
|
||||
desiredLabels.add(priorityLabelNames[2]); // P2 — medium
|
||||
} else if (text.includes('benchmark') || text.includes('measurement') ||
|
||||
text.includes('deferred')) {
|
||||
desiredLabels.add(priorityLabelNames[3]); // P3 — low
|
||||
}
|
||||
|
||||
const issueNumber = context.payload.issue?.number || context.payload.pull_request?.number;
|
||||
|
||||
@@ -78,6 +78,9 @@ jobs:
|
||||
MS_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libmemory_scoring.so
|
||||
CS_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libcapability_scoring.so
|
||||
TC_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libtoken_counting.so
|
||||
SC_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libscaffold_core.so
|
||||
MEMS_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libmemory_storage.so
|
||||
MR_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libmemory_retrieval.so
|
||||
steps:
|
||||
# actions/checkout v4.2.2, pinned to the audited upstream tag commit.
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
@@ -129,6 +132,9 @@ jobs:
|
||||
cargo build --release --manifest-path src/rust/memory_scoring/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/capability_scoring/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/token_counting/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/scaffold_core/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/memory_storage/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/memory_retrieval/Cargo.toml
|
||||
- name: Test with coverage (global floor + changed-lines ratchet)
|
||||
run: |
|
||||
# #149 coverage ratchet — both floors live in .coveragerc; raise,
|
||||
@@ -176,6 +182,9 @@ jobs:
|
||||
MS_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libmemory_scoring.so
|
||||
CS_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libcapability_scoring.so
|
||||
TC_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libtoken_counting.so
|
||||
SC_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libscaffold_core.so
|
||||
MEMS_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libmemory_storage.so
|
||||
MR_RUST_LIB: /tmp/rune-ci-target-${{ github.run_id }}/release/libmemory_retrieval.so
|
||||
steps:
|
||||
# actions/checkout v4.2.2, pinned to the audited upstream tag commit.
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
@@ -212,6 +221,9 @@ jobs:
|
||||
cargo build --release --manifest-path src/rust/memory_scoring/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/capability_scoring/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/token_counting/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/scaffold_core/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/memory_storage/Cargo.toml
|
||||
cargo build --release --manifest-path src/rust/memory_retrieval/Cargo.toml
|
||||
- name: Run canary suite
|
||||
run: |
|
||||
FAILED=0
|
||||
@@ -247,6 +259,9 @@ jobs:
|
||||
src/rust/memory_scoring/canary_memory_scoring.py \
|
||||
src/rust/capability_scoring/canary_capability_scoring.py \
|
||||
src/rust/token_counting/canary_token_counting.py \
|
||||
src/rust/scaffold_core/canary_scaffold_core.py \
|
||||
src/rust/memory_storage/canary_memory_storage.py \
|
||||
src/rust/memory_retrieval/canary_memory_retrieval.py \
|
||||
src/rune/canary_unbounded.py \
|
||||
src/rune/canary_full_system.py \
|
||||
src/rune/canary_native.py; do
|
||||
|
||||
@@ -14,3 +14,4 @@ state/
|
||||
# Runtime artifacts (cwd-local event journal + capability index)
|
||||
index/
|
||||
journal/
|
||||
src/rust/*/target/
|
||||
@@ -1,6 +1,6 @@
|
||||
# Rune
|
||||
|
||||
**Current release: v0.91.0**
|
||||
**Current release: v0.95.1**
|
||||
|
||||
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
"modules": [
|
||||
"audit_ledger",
|
||||
"build_pipeline_policy",
|
||||
"cc_loader",
|
||||
"claim_audit",
|
||||
"contracts",
|
||||
"curator",
|
||||
@@ -58,7 +59,8 @@
|
||||
"drift_ledger",
|
||||
"drift_observability",
|
||||
"failure_auto_filer",
|
||||
"programme_gates"
|
||||
"programme_gates",
|
||||
"sc_loader"
|
||||
],
|
||||
"depends_on": [],
|
||||
"mirrors": [],
|
||||
@@ -69,7 +71,8 @@
|
||||
"canary_spine_meta"
|
||||
],
|
||||
"rust_crates": [
|
||||
"evidence_provenance"
|
||||
"evidence_provenance",
|
||||
"scaffold_core"
|
||||
],
|
||||
"configs": [
|
||||
".coveragerc",
|
||||
@@ -163,6 +166,8 @@
|
||||
"memory_env",
|
||||
"memory_selector",
|
||||
"memory_store",
|
||||
"mems_loader",
|
||||
"mr_loader",
|
||||
"ms_loader",
|
||||
"query_memory",
|
||||
"recall_router",
|
||||
@@ -181,7 +186,9 @@
|
||||
"canary_query_memory"
|
||||
],
|
||||
"rust_crates": [
|
||||
"memory_retrieval",
|
||||
"memory_scoring",
|
||||
"memory_storage",
|
||||
"query_memory"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -38309,3 +38309,602 @@
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_27044643acf3", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f841b27cd0a3f14a7fa1be8e87d46c0b65a23b0a75d6324d2b14be717476459d", "schema_version": 1, "timestamp": "2026-09-29T02:59:13.857300+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_edb2d4f65dc2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:478b26b3101f2da813ba48b2c1c1afc463c1c0d5299904de9faf947b8854afbd", "schema_version": 1, "timestamp": "2026-09-29T02:59:13.923428+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fe5b4b43370a", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c5855d77df4b36cebe2c0c18f7bea277d0f779b73b84f357375563349f3e984c", "schema_version": 1, "timestamp": "2026-09-29T02:59:13.934399+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b0e19f4acdf9", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:21:25.789100+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_016be0c4b465", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T05:21:25.806792+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_086af48a13f3", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:21:25.823965+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5551023172fa", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T05:21:25.838205+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_80fd52f13829", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T05:21:25.848050+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_087025013478", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c78e434affa5f0ba0f4682f0cd5352b6050baf50ba81fd03451a7b2c1c3ca785", "schema_version": 1, "timestamp": "2026-10-05T05:23:11.984154+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_24cbfc281745", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7fed33b30bb04b86a51308ba4ac316b81b5e334fd294d0d91cc88f5d7811a579", "schema_version": 1, "timestamp": "2026-10-05T05:23:12.283402+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c232600ff73f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5ae7726f99a8b4ac388a40057e42d5b327181180d8e8358e09816e5b8eeeb07f", "schema_version": 1, "timestamp": "2026-10-05T05:23:12.530839+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a2525db7221a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1e825cba1cabbbd6333c03e88eda16bb01395e84505925366367f4406ce9e3eb", "schema_version": 1, "timestamp": "2026-10-05T05:23:12.744665+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_563adf9a5f35", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:763695d7a131c268d6bcbe4a691bbd78be59068649e1c80caa0665c33cd74665", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.009164+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_816a22f4d447", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:aaaf89f49546f49e337ef8cdd1fe3720fbd84655677dd4fefe81939d81f2ff00", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.268251+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_17643f9c08d3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c1d39e849fe42430601ee240366550572fb4c0d7c016fd887aac50b5328b6e10", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.331692+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_acc564bb5e04", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:34b51a7de4f22973c41fdb3b7b947b2a9f4c5de5904335e5a89b39466aa95ac5", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.343968+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_75d26cf7246c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c2a8dfa6e57ded3f85dd2339b16a0ea3a40568e2831560b5c15891b08ce15e7d", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.355213+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7b7adcfd4fdb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cc49dbc2afd1cb8d4f226df8f8e28a2c9fdb52140ef6dc9f9ab79aedc9e18557", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.366512+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4bfe85f92dd6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:81a61375083c0c2a8b0eb756bdfa452118ea92332a0197d8d1e2e43648ee4279", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.377960+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8513a24cc16b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1f6079f682719dbec8bdd455a1098c1c0ba64fc063968329fe9ddc6a716f9c56", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.389163+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6e97b06ebde1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:15fd87c25a425dcf9d07ddb24ffe91fc03c6ae68431ad887067362b3d2eb7550", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.400338+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4d7e8da95431", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4ea1b6698f4d71fe15549b852957d618db6ea67ccaae0cbff8c0e49ce5b4d526", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.411227+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f796ee067453", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7307f3ecceeed949123988f8e438bd3cbe1169e27cb5d6159f77a6ff600c4802", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.422300+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_46bc455a244c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b1e7a541ab66571a7f8061380574c0755b0a1d2613b9331831cb801c87b1710d", "schema_version": 1, "timestamp": "2026-10-05T05:23:13.432243+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_89a5c3f5916a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:12b0b024840c0b30ee3afbc023e1a72586024ce42e34f7ec0363990c983bf9db", "schema_version": 1, "timestamp": "2026-10-05T05:23:16.976063+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8340dcba0ee9", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f9ac3ca3cfb75d4d88edabe5ba101af2bf580c89d06a9077b80152db8a222f9a", "schema_version": 1, "timestamp": "2026-10-05T05:23:19.934351+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1200db078626", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:89450873a6b1a0c4755b443f10fb807e3a308aede5fce1820840c2cefb56b43d", "schema_version": 1, "timestamp": "2026-10-05T05:23:19.942616+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_89c8feea275a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cab0efc6c547df0511f048933ed628afa5fc02962a028d383dc5772fea73a0e5", "schema_version": 1, "timestamp": "2026-10-05T05:23:20.051988+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_38dff4e11ccd", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a9ab994b6ecbce010c3190bb7144b56fb77049021e72613a52471af773a44597", "schema_version": 1, "timestamp": "2026-10-05T05:23:20.060629+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c8e9380dd848", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a1d29ee3e813f549c8e8bbbacd64a419240911445811116100e5b4dd2488c672", "schema_version": 1, "timestamp": "2026-10-05T05:23:20.312488+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c2e0ed12291f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8d1ad954a4da5edc5a23b0c87759d0f7f7345af1eafb4181fcb9224ebc45c7b5", "schema_version": 1, "timestamp": "2026-10-05T05:23:20.325260+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b73836b33bdf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0e657de7974c57b514a1a56c0882e4f7c5e5b80598bed0b02933ea7f5bef571f", "schema_version": 1, "timestamp": "2026-10-05T05:23:20.334787+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0c173fc1d3cc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ede576070fc93e8e039c44444be8a044401ee95af2e0c3b3a6d7dc48d994584d", "schema_version": 1, "timestamp": "2026-10-05T05:23:29.588228+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5b2271cbb551", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2274151dcba0975ee1a3aa8a239d2ea47e66ec289fffc6832d0767c9456aa4fc", "schema_version": 1, "timestamp": "2026-10-05T05:23:29.611251+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_34338986691f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e3a74c42d1b951be16321b4a88f929daa94795333bc482910828341b5633472d", "schema_version": 1, "timestamp": "2026-10-05T05:23:29.635440+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7cc6e81e1801", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T05:23:29.678207+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1b14c0ed4e61", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T05:23:29.746400+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b2dbe5833cf1", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.342279+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_deeca46b17d3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2140010d66eac2b9f209070d86ccadd5b36f6eeacb73f486d8352ce7b3af9b38", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.366683+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_92845503a937", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2fc949e469e7c56151e298835012db3d348b78c7c8ebf4b5f834a19a983939e6", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.374544+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6a0ce25783a7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8085f4a6a55f8ba91267690d7c098dbf8b2761e7847b7928ef12ea450199a834", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.387814+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_672844a86bab", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0af82eb6d979f50ebc79a8b7a55c5285ce8e33ae59657bc492154123a5a0d976", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.395837+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b1fdffc18dd3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9dbcf32d01e7e497296797b117daaea11782fca4a5fa72007630ee62c2f6cf02", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.407145+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8e6b6044f667", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ad451919c0d25830adc1c2b82d9e2030a71c60a9726811cea52e78648d665595", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.415615+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a602deb56bf1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7004f9afb320d2fec931359297a4667cbe8cf78de131fe7bbeb52107feb88afd", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.591693+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_983155bebc20", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1b3cec7b74728266d9369c52a0557b007cd55ad230d4db441755bbd6876242f6", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.600649+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b0b0c611580e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2e13684b717ea5fb6950cf67b5a00a81d62df06b4898dd20a787579e6e99868f", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.614050+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cb991f5b273e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c1b8c60560793a61d67ea8b954b0bfa1f7f7cb316c2d2dd3b0d147747420bf58", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.636737+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_40b7cf40d80f", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.651465+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9ceaf311bc74", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.668562+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ca7424aa2083", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.760632+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9083dfff3b45", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.775813+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dc688dae7058", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7ced6642e67f8be4e5e3530576ab9c6d98ddcc4a1416c79988dc34225b750c8f", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.786010+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_013636606e3e", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.859102+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c858eef7778b", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.873133+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_89ec31fad8c2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:653ca70f91b53be286aaa0f17c30a2b4e7736b75ea343a93e5ea14ed1a28be6d", "schema_version": 1, "timestamp": "2026-10-05T05:23:33.882320+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a82038972d92", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:072e8f7d9fc3e57275a09c1453f75d5e2f9e81536235be64f8528a1bb979b7b2", "schema_version": 1, "timestamp": "2026-10-05T05:25:17.396213+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b8eb53953104", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a22cb8f16063fdadc7fd10bbfd441998175f5fd4b7b6725c968dab4b1cde994e", "schema_version": 1, "timestamp": "2026-10-05T05:25:17.416907+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_91907ae5b9b6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6c2b5a4a7f98be5a78d6b4c90ff52b0a17a8bb4795f14ce51981cfa0cf99c50b", "schema_version": 1, "timestamp": "2026-10-05T05:25:17.430981+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1412a44236ea", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d9ea3a87b24a45857950d84d42d3de81d837bc9fa49e4476876c5ded07eaae8d", "schema_version": 1, "timestamp": "2026-10-05T05:25:17.443944+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6ba5a799e1f4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f5ce7f4257fc0b5152a8a2e6a571758f2e8b377c573447a4631392741ce3409f", "schema_version": 1, "timestamp": "2026-10-05T05:25:17.462161+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8c902011aabf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7acd608e1a5d2e803f7cf624f595a570669c3634771de03b5cfb5ad9013a375a", "schema_version": 1, "timestamp": "2026-10-05T05:25:20.413886+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_15df1245d414", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2a12efb91d5fe122a91e061a4c099ebc8b439f62a71f05e80466f0912fefa745", "schema_version": 1, "timestamp": "2026-10-05T05:25:20.425874+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1a3a8a9f59da", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:913868291eb1a253926b00356c41e9c6ca8dba1aa618936d21760cbc33395b13", "schema_version": 1, "timestamp": "2026-10-05T05:25:22.519216+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_99dd71ab164d", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:060381d18e06e0539920b1840d1528fe30e62a3efe4d98231795388580cf2024", "schema_version": 1, "timestamp": "2026-10-05T05:25:22.538570+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3820eea4d142", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2b5425f3fe253df866f8344a2fff39e3bda8720d3b6b7e0863d37253f62f91c5", "schema_version": 1, "timestamp": "2026-10-05T05:25:22.651874+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_916a7ff0fc86", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c6cd20ab75e396c5805a2d937214cbded98ffb005bfdd0805b9e67cf6e18ed54", "schema_version": 1, "timestamp": "2026-10-05T05:25:22.663015+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fead6a5de91b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:959100e6d856c13f461109b4f9ae7f0851cf96fd39d757a7ffee276843894697", "schema_version": 1, "timestamp": "2026-10-05T05:25:22.736998+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bde7430c2e25", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:927514bf2c22c63c1ba643aabd27dcc42bb5c380eeacf0ba3dbcbacc8e9c25e1", "schema_version": 1, "timestamp": "2026-10-05T05:25:22.748338+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_23caf9dacc88", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:26:05.058788+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_845ca4f6f24f", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T05:26:05.075917+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_51070f52b8a6", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:26:05.094522+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fd2082fc8c0f", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T05:26:05.109473+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_185b4b2d6154", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T05:26:05.121919+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_408e3b8cfe78", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:84a918f8e91c2dc10b4755511a3082452a8fedf1e447fffafee15fce8fc1a93b", "schema_version": 1, "timestamp": "2026-10-05T05:27:51.531186+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9435749ca47f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6e89b2470934ea8c42e1a7499eb6d0d5294da7433e396be707ab799980f95368", "schema_version": 1, "timestamp": "2026-10-05T05:27:51.818842+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2f016168152a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d788663a9e9c9a89dea8f732a20888687d27957a80c381d14c08065a053e0ef8", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.051261+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_61c614715445", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9bb7d151c830f42fa63a11f8bc4ea925dcf868689dee13c3cd29bfa223a4bbd5", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.266625+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b6208cccd918", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:203a108f9dcdce6ca650375e2b244805852570cd8c7ceefa8449c3c690642fd1", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.528285+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c5200840c4a6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:36cea66931af503b14f27b105f830fc170dfeafbb29a6128af4f130d544effbf", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.796399+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3e527fffd6fe", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0d12f3da21598ab74316e8b65936d6e56d90403d3eff70238e10d3bdecb73838", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.863927+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6291e3591991", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d0a86ab3af6a721a4050075172b898ffd2e2a5d6561bbb8bff1d89ba18dd458a", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.876986+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_653474ae5a38", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fe262eaff1d3744c73f76f110492a9ec7a1ad179f6f1e19fca66311669a15ed4", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.888746+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_28eedd2abbae", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fa2cb5946ba2f778d509d0f368c4613304ba54c82fc4889eb3799001237dbc7e", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.901213+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_37da570bc113", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0e8c4e296896af8faaa1432c38fa72bfcefa226ccb35e1998414d7803ae65168", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.913445+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a7829f63eb5b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:640393fd25398d4e0a111c578197687bb017f6f084014a0ae4181dbccdbe7c70", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.925756+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_41d478b7d782", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:025c1d4fbe7722fc4aad0bd7e9382712889a806f84394ee66a092077e2bbfef8", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.939111+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b4015935cdbb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:565898daea9457ece7ae44df52fd5027b0b7cc909cb60342fdfb5b5e6f366a12", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.953016+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6421e7749b93", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:818a29ba114e0730207cf1c5f768d327edc5bf290e4f56d9c2367e385ca48aa9", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.965166+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_08983922cc57", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a442fbd2f9a0f05832aa41d04d01b8f1c766b471089f912e8d272c7f0407e8e5", "schema_version": 1, "timestamp": "2026-10-05T05:27:52.976327+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_125847fe8b69", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b1deef4708eb9aa1af381749bbea11a422c64897ab5d4b578cc8af433d831d73", "schema_version": 1, "timestamp": "2026-10-05T05:27:56.131473+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3ea4fee2207a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2ffe96d1999af5fb0698c2d0e62c17852fa8107980b05eb0b73540364d0dea99", "schema_version": 1, "timestamp": "2026-10-05T05:27:59.070955+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e989056d43fe", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2e30696c1651d69e185f25e8db4ce01d47c6787fe50ef32c2683ac39371986aa", "schema_version": 1, "timestamp": "2026-10-05T05:27:59.085972+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d5f1bee048cd", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c332225c74917e14f18e7fdda828bfa2c5d8a332514e580df135b1480bce738b", "schema_version": 1, "timestamp": "2026-10-05T05:27:59.220918+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f56911180a9b", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ceca0a4364b9ee3f2419bcd9ac18b40ab9e07d1cdb03d909f2f5b7efb51cee7e", "schema_version": 1, "timestamp": "2026-10-05T05:27:59.229532+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b2824390c450", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9819b775ac6aa5f32de4878ad79f0e98dca6493fefcc5ae8df8e83c2dfcec6cd", "schema_version": 1, "timestamp": "2026-10-05T05:27:59.495278+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e23f1441be5c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c5159c0a313804bc805c68de7eca26b39fe3392aef5d41fa66e5923f0c0ea597", "schema_version": 1, "timestamp": "2026-10-05T05:27:59.508673+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_73e2d31b03bf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:93f915bdae3b5313f277e830bfd0fb2e0d1b02aab3c44b20a510a9469f46bdb6", "schema_version": 1, "timestamp": "2026-10-05T05:27:59.520027+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8d8bdeed008e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9bc8685d2399e0460be64e145836d78c206a9712e6f117330a4b6463b8ced171", "schema_version": 1, "timestamp": "2026-10-05T05:28:08.329960+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f6908d666ad4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:78c32e964baacf6a73151ebad029892e09ae53ad4710890c9d0193ee71978ee3", "schema_version": 1, "timestamp": "2026-10-05T05:28:08.353126+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7e6c6b73d1c6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d65b046a0f7bbc04806ed066f5e935e2b9a520ba33e552e89e65d53d30ae09ec", "schema_version": 1, "timestamp": "2026-10-05T05:28:08.375244+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_94194cef5eb2", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T05:28:08.416223+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a6ccc11f9f42", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T05:28:08.485358+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bcf71e09c3e5", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.599749+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_75027bb0ef3d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9f9011ff2c006bb7507fe67cbd61e641b0a2f80b91c67d31aed389e0fbf09e00", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.621348+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8208b0e35fa5", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0181775b8514a812d37751511072f301a31643c5a5be26e2512547c240a0790a", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.628860+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2f47d2443960", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5eb815e5ec80814ddca17127677556f15798c7ce94ce94cb4eed530311e7d7ff", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.640465+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0f6bd7361917", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b12fbd56aec61b17630f0dbc7e488dc88e6999f57ec51ef467d7029d93f604a4", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.647963+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a7531bc14b51", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ad5ffe6d99ba7eb8e220803d051c140524085622902a5940b2391a19c7414b92", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.658146+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c978e0bfd637", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5600a9577bb076c0ff0b9d656462b09831e21a8f4d02bc50e99659fd17e2ba44", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.665658+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c39a1f0f397b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4be05784a86523109449a6b2769bc348428beb7602b5d2c35098c1035b2fca36", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.822047+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0b4a21b38eb0", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4f7119e456d1e5aea07adf44fdab0b90e0f68e2c48c23c61c10844afcf5bf98f", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.830449+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5add87c241be", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6cf3772ab4f5ec3b4a9abab8380d02cbe3f24ca0609e68b07639fe96e98e8e43", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.842537+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_70de0f155f49", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6a48c8b921a89cf1b8c2e28696267123b85b04317af349213e654640aa42a5e9", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.861340+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4025fac6f1e0", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.874488+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b873e7b563cd", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.886610+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3daf0f2d44b6", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.984176+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e4c5ebf30fca", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:28:11.998542+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_539377a95676", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:95b1442f065a87dda2cfabd70a8effcccdd85a7d5bb083dd29aa627386c62db2", "schema_version": 1, "timestamp": "2026-10-05T05:28:12.007236+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4b782fd4e3eb", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:28:12.078949+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ff20a4ad072d", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:28:12.091816+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4f937d75332a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2c26d0134b9ac0d13d5787d3417d511b684f73324de1e0f23f0da45491db1e40", "schema_version": 1, "timestamp": "2026-10-05T05:28:12.100678+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7e5a45264260", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9dea7628059a7e5e2b7c2494b865238f95084208b1a7763e395444e7aa64e796", "schema_version": 1, "timestamp": "2026-10-05T05:29:55.509557+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_874accd00f3d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:34dbc39a404b72b14e6d9c0045b7fc23daa35ab97667f01402cf2416d662836b", "schema_version": 1, "timestamp": "2026-10-05T05:29:55.529787+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_277237fb122a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1a7a83b9e1f78b9dc88e4ad1f3b272d639288eb70dad9e2bc5ae720d70411c5c", "schema_version": 1, "timestamp": "2026-10-05T05:29:55.542625+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cba8e215b145", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ea509c55bb8a2adf416e25fdad70e6567c536399b8141f90aa26b033c33e3309", "schema_version": 1, "timestamp": "2026-10-05T05:29:55.555819+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a55a21dd7235", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b628de52c8bba806aa6264c4d42a19dc3e65c46bbdca05436ee8a808b32701e8", "schema_version": 1, "timestamp": "2026-10-05T05:29:55.571734+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3c3e0839e638", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:113d8d7baadb6dbc00443b1ee200b3e11dae0d751d4483a28d85318050111293", "schema_version": 1, "timestamp": "2026-10-05T05:29:58.721804+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4933d7245822", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ad3f3a76048316c3c20579bea2166845c15950e5d5f3de57d7dbbd8ebd9edc3f", "schema_version": 1, "timestamp": "2026-10-05T05:29:58.734844+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e0138977793c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a90c96a2d9366bc6951ec3b992a61f3beaefeaaa886c122c743ab6acd74ed408", "schema_version": 1, "timestamp": "2026-10-05T05:30:00.494219+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fc56f6741b93", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:802bb686f4b5a1ad8c8ef9568bf02ca217feaacafe8702ac45c0b57040412e56", "schema_version": 1, "timestamp": "2026-10-05T05:30:00.508976+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1d8fe2b1fd81", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:56ca27fed0caa063afda5e6c21d190385719834588b340415d4c3a01c2eb038a", "schema_version": 1, "timestamp": "2026-10-05T05:30:00.628493+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6f1b9fd10a21", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:39002b10daacf00c62e6c79aef7909eb166730847fa08d042f41457ec1d60da0", "schema_version": 1, "timestamp": "2026-10-05T05:30:00.637183+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e4c9c7ffa6c0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:13f7ef2fd1220ab45bcd59b5bb088b3d3e1bf0877b521f7596ce7f0c7afcc0c6", "schema_version": 1, "timestamp": "2026-10-05T05:30:00.698934+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8a645ac69fea", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7fa2bbcfca701f753edb2e4f4d881825925b4e663886b736a0a744dd8c004590", "schema_version": 1, "timestamp": "2026-10-05T05:30:00.707238+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bc09da2f7370", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:30:24.356970+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e32fe810ee7c", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T05:30:24.374002+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ba52c8226135", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:30:24.392343+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_92ea4ceb0d28", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T05:30:24.407304+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7cff4933612d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T05:30:24.418294+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8aac99f05776", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:212d17607942f17ba29c9f9d9bc9cf5d37d67f93386de5ee5b9d9e4e79acbeb4", "schema_version": 1, "timestamp": "2026-10-05T05:32:10.735398+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_32ef3f39c9cf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4367751c718d5feef38fb559b14cb544bcf0f55dd0a6b7631f9902099930fd1d", "schema_version": 1, "timestamp": "2026-10-05T05:32:11.023659+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f92b9a8bde55", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e94ba1ba17669ef2379c863670295ffe1647c63ebb00b29aba7383c26fd5f9df", "schema_version": 1, "timestamp": "2026-10-05T05:32:11.251196+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_48a0a4b749cc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bbde1c4f32585bab26f8f274abef3abfd0789b0b89be1cb58ec82e5629dad7dd", "schema_version": 1, "timestamp": "2026-10-05T05:32:11.466600+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_61b2f9392328", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a9b1f87f4671a779561551ba84803bb39b41412476daf7883f5f7ee6e7439fdb", "schema_version": 1, "timestamp": "2026-10-05T05:32:11.727830+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c176c699cc61", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:efa754113d15c83e90d8b9f0f4318947009d48c921dbc1c288c031cd3f901173", "schema_version": 1, "timestamp": "2026-10-05T05:32:11.990992+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7e31c7c108d1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b1e9a428a0af40b1b8f6d99b075d98886cd352c9913ccd9e6d104f924108fe68", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.053590+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9ed7e24448aa", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:51070dd900366646171319b023082ec0e40a5b90e69a87bc4db311edb25fd393", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.066468+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_497f97d21aaf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:39f543b29c4eebcdaef669a7511da196fcd0f271305a447c7e680af7365fd915", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.078586+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_de0ec7cbcc04", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4658efead9526c67f82b01aca2914354d1854b0a987dc104b21caf8e148702b1", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.089830+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3db0955932aa", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:50330e358d50974da891edc86c0914c13b5682bd046ebd4b13e20fe5150557a9", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.101835+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3171bf0dc94f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dd11850ceee05c042162c7613f621e44bccd74b1a00454891910b4c873648a37", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.114009+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ddef6b58dbdf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4af9d21435106567bec27acf9c9675800ae79b1e35fd4267855170b07e96a83c", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.127026+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_39638ea4797d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0a37b21dcdf495db8b49a7f4d6fa93f3427faaa8b66455bd8db0c2220d68aff9", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.138781+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_03d0a3262591", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:88929433d0eb43ffb4783fe141d41fa16d7d73ea8c3bc6f7b5dd375c18fa04ab", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.149909+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_668453e96811", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:615e3765dc0689bcbdab8898862382f60d8fe88ed94e05c98ac3178378967a73", "schema_version": 1, "timestamp": "2026-10-05T05:32:12.160223+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2fdb4ba329d7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:961e5b27d08ff355f182a438afa3576c6e8b276bdafabbad9d568f7fa3b3b292", "schema_version": 1, "timestamp": "2026-10-05T05:32:15.742945+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dd72011e587f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ac29a1b2e20d1288f6e5d34618970e54cdbbabbf65f8d977dd47bd3f95f5f25f", "schema_version": 1, "timestamp": "2026-10-05T05:32:18.672702+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5055a5efc8d4", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:193c45356bb4efc1e1bbcb1678feb70f1340d9b72b9c58ec19d5a4e1077293a7", "schema_version": 1, "timestamp": "2026-10-05T05:32:18.687521+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f5061bab2701", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d80bf3e826e76b337c46839ce7998919f518a031d323ec0f748af4d5c15cf7b4", "schema_version": 1, "timestamp": "2026-10-05T05:32:18.803632+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6c03c0fff614", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:88b441f40713e3d94d5e9a6def7a5e98292ede6d3261b97cb3e156e3d7a2478b", "schema_version": 1, "timestamp": "2026-10-05T05:32:18.812694+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4382a4801bb6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:60a1560123af24fb64633ed54db9be99215bb3ccf068a0f00b82615c6de495b3", "schema_version": 1, "timestamp": "2026-10-05T05:32:19.077518+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b7e31919f41f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f8678821cf3dd1511274f75c7eaa05d76c987596e59f14c39d243102b10d6c83", "schema_version": 1, "timestamp": "2026-10-05T05:32:19.092019+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5a4b57cca41d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:63c47ff5ed33e524064b29769a7c8fe49e265ece8adfeb3e6f9aa0669035f879", "schema_version": 1, "timestamp": "2026-10-05T05:32:19.102213+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4324375af2fb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3d0345f44345bb52d7a616c834c85f6c9d9f5300027ed1d36961a1ad98de2973", "schema_version": 1, "timestamp": "2026-10-05T05:32:27.729235+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7d4161720461", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:688e0db718e6f500194d3df3a930bc8061f81c4c04bb13e7d43281f8e3ab2b66", "schema_version": 1, "timestamp": "2026-10-05T05:32:27.752108+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b75d089537a8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e111e67ac4c9f9b0c8686bd29d6c931fdab5914adc263e0f125ebe00eebd9cd7", "schema_version": 1, "timestamp": "2026-10-05T05:32:27.772302+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_be0914011cce", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T05:32:27.810939+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_081a064f7d69", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T05:32:27.873295+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_897ee9583487", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.023568+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b1397f503580", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:75b37792f400ec70c671de1fb27693d614e9c5ba77288fd82f87257db93d6b8b", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.045987+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f36ff6d7e755", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b3b0f6669e253ce09237ae45d741e784e37b56c20e3efd6e095fe989107c0809", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.053770+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_abde6de9bbab", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:725fa51d74580066281cd5d9c5e16b2dbb6dace7b9a4c2b344959647b37d6d86", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.066121+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ed3069467d1f", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1ca67b9b3840714b448db4e74946bb21f854202201adc4e398a8b11d58bfec4a", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.073818+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b55456aada25", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8975932008450e38b49ff7cdc75636e12b266866b2538d60ab5625eab40c9b47", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.084206+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dfa183677d58", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:54ce15eed524b886bd2787af14a35e463010ccb4bdafec9a2b3da9bd2d83e860", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.092031+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_09e10a729ab5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b0024bf50af59f5baae93d5e63fb452ef75128faad67d00b57a86c418c532eab", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.250783+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fb7e16b2754b", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:789310a900e34f34e18b58d3fe470d9b064548c1676c9dc332b92c0dc07904aa", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.259992+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f43d6eeb71b3", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3bd47e0ecc07aa84a34dc7eaca2448650a1d51f5c2a891248bff24e3739a1483", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.273201+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b7a05e59f4f8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a2d91502fb3eb4f201823443b5de6a9a296f791b6f3d0620044eaf9062a65783", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.295255+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2eb13b60fd74", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.308851+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b1a3e11d8d5b", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.324788+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1a1fedf70564", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.416777+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cdb6a49e28e5", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.430919+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cecb09f369e4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:533946b8405da4368789644e2e85df16bea9023c8e79c6e2e96dee8883e17f67", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.440919+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0903ca4adacf", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.505857+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7c3ce5921891", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.518092+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4238b1795f43", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7bd43c48929090b1ac26823d3c5f579353c199d6229188f14c38ce93d34d29f9", "schema_version": 1, "timestamp": "2026-10-05T05:32:31.526993+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_43587350f3f4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:71896095ebf7f71be94cdb069b034c6f68ca6ede9b82d2e8b50de3c955cbd419", "schema_version": 1, "timestamp": "2026-10-05T05:34:14.711009+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_43f44f24fe13", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1db3165da25422b99c3337567ae88138223a1383d0824a6dda2fe61b091ee6e2", "schema_version": 1, "timestamp": "2026-10-05T05:34:14.729598+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0cfdce66a3e3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:015d4218faa5914504ee3fa032a79c182aa95fde887b9d8801c5363e39362ab8", "schema_version": 1, "timestamp": "2026-10-05T05:34:14.740188+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_85ebd1258ff1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ad46fa8aa08518716e3d7e502f87ca5a28bee0757bd753261b637e49a60953ca", "schema_version": 1, "timestamp": "2026-10-05T05:34:14.751344+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f2bb24df2916", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:09a9df2e7850c64a1effcb172ec3c8ae3df42d5cf190a144a3c85ff254d62e09", "schema_version": 1, "timestamp": "2026-10-05T05:34:14.765763+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0ab073d1e179", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:12d45dd1374f6973719c4d7f0e3701a2c08163e82596f90cb0eb0359f3ed82d4", "schema_version": 1, "timestamp": "2026-10-05T05:34:16.986105+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8506701fb589", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:85adf7ad469119210ac1c00a15a9a44bac8870ca3a953771748575b7deb2ea80", "schema_version": 1, "timestamp": "2026-10-05T05:34:16.997758+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bfad360f1ac3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2ecfe3143938314e2547ceab5797d3a92e40d5bc63104238591f1ac7e40d5722", "schema_version": 1, "timestamp": "2026-10-05T05:34:18.689748+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fea3f40ed64a", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ee1f25067da4f7d7a16793a487a82b28e5b00934d6b5405c44cf270cb8ce9205", "schema_version": 1, "timestamp": "2026-10-05T05:34:18.707650+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_92378415102a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3dfe0184e2ffc36e89400eebb0a16eecf1df4ba17ecf3168145ca3dd2bde1478", "schema_version": 1, "timestamp": "2026-10-05T05:34:18.817581+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2196bb7a5eed", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b9eaa1794e82d24a5cc3f486871d74dde7cef301135ba579a2bb6306c3664904", "schema_version": 1, "timestamp": "2026-10-05T05:34:18.826342+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1e28686d6212", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:da581993cb7d5b13d2cc0c8fb5638e4008e714b88910560628bd03a7fe114f03", "schema_version": 1, "timestamp": "2026-10-05T05:34:18.886502+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a78b2b45db1d", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3ddc3201d2a544f70259a3cd8dffcdac49efa289a31a2531bc011b3f3b0060e6", "schema_version": 1, "timestamp": "2026-10-05T05:34:18.894367+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7ec6b1f9e4af", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:34:42.503144+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6ad73605aab7", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T05:34:42.519529+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_10d3c8c5fdab", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:34:42.535483+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c76904ae0e04", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T05:34:42.549651+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_76001f7526fa", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T05:34:42.559475+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5fff77055197", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7ac55112036f1406c7735f2e111cbf6206e739a83705abdcc05130e5e7f6b973", "schema_version": 1, "timestamp": "2026-10-05T05:36:28.572925+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d5d63c2b4483", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:635799e277a34930633ce00f47f6bc93e39aa57484c45a6a1fc6264f5192e874", "schema_version": 1, "timestamp": "2026-10-05T05:36:28.842810+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d1f83b915d86", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:baeac84a339c7ff1455a78bb860de29ddeda0155dac8c91e85468c6ad58106f4", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.058262+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6464d3c50dfc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:63b894ac3cad3484b95f01f927357329e3fbd2df6ebdb37217827763985f96e5", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.258839+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ee8708ba0780", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:95a096539637349b1754528c822116a2bbf09b6e85df83a7181bfa0b6a2f3931", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.502558+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5a7636065682", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:272b95b3e8645980af844c2028bcbd50fae16cb8f1d78c3c19d57248a57af461", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.748219+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_64976fb1851b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bf325354c7d07d4c4ad5a408e76ff55d83400cbfaf19f4ec00173422e0d8983e", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.809885+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_48f21af6b779", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3d12fb8c86fbb4efdb0ef7f6b608f3ed6fea84a8650386abcc41ea1a59880226", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.821228+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_622bf806031d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5c34b4f5d0bf12000255cef431fb79bec2ee89a2ff432a6ad70406038ca5d01f", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.831955+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_89f419bab511", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1294483e5b6220c7090f9e4e44e9744a3b4ae7e4eb255de5bc24d8833378bb67", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.842691+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b088836711b8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:60e2abaf508eb3e6488851044a5db422cf2d43a486c6edbba4b778e9b27bfe74", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.853702+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_af69b181cd27", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:149509d97283e6717614db93daf6f25f2eef9e4c65601f26d69c62841f9bf509", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.864484+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_92ff2859f11d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a3d216fec0c35ca5de2792ad55705506b2c4a790566f7821f898e5db37dcd511", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.876232+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f208e23547ab", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5534f53025673952a38abafcba1a53811a1ed1c1fe1fdc1be2c943208ee62870", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.886997+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_59b606f790a1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1f722e514428e15f93d5350cc2759ac6c8f6cb67320b3014672848e0ab0e7eb6", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.898336+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b3e908b9b8df", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:086fd5cc9b046be26354b539d35174bcce53c843f82d929ac98abaaf7ac499ad", "schema_version": 1, "timestamp": "2026-10-05T05:36:29.908868+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4abb26b61660", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c7a22e5a661480b81453eb12a1296cb1af4d86d948887a9b33b8e43fb2b05581", "schema_version": 1, "timestamp": "2026-10-05T05:36:33.804475+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fc05cbafca99", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:644d95718b81d6a1c068625a56354f7ce695e4f076a2c9d1d3408cbb45bff72a", "schema_version": 1, "timestamp": "2026-10-05T05:36:36.706654+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ff18afb585af", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c15cd557d92635664a3493a7fc7e3fd9d16339d2f0562981ff341577ea4ee883", "schema_version": 1, "timestamp": "2026-10-05T05:36:36.721525+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f8becb75e15c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3770d522f8a1d9ec0881ac5571c35c43b5ddb2963693fc8eae063e2bb71208b3", "schema_version": 1, "timestamp": "2026-10-05T05:36:36.837539+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c0ac8ddb44c3", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:009e3ae5133a6d1a71fe0fa2769f9b7ae18578b3d08099d78241d403f2b11603", "schema_version": 1, "timestamp": "2026-10-05T05:36:36.846574+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5e291a148e97", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e2c3e19284e518a1cfc7f38847cabd6252691028687a623ba892095a1a7d4eef", "schema_version": 1, "timestamp": "2026-10-05T05:36:37.096606+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e188724befcd", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c5c37130f04617f7d4974ee40cb759ac02589daab1dbbe78c7e77dc6c75231f9", "schema_version": 1, "timestamp": "2026-10-05T05:36:37.108895+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a32a820cbe36", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:da4fd17cfcede765d22b744f4c1a6998de260a6f12d3af9f14194b6092b936e1", "schema_version": 1, "timestamp": "2026-10-05T05:36:37.118581+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a2d77d321a7f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:744405806a505497e6318bc3071b3caa3cc4b854aad81fc1f392718ac37813c0", "schema_version": 1, "timestamp": "2026-10-05T05:36:46.383606+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1562b6da5aad", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5d5b47c38c8689d56acfe7bbd8efff77369d736b869761ac4c5fcf987736e3b0", "schema_version": 1, "timestamp": "2026-10-05T05:36:46.406949+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_29f4d6e3b7f4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7c7ea7f162c6aafee91f16e3c27d2018bebc2cdc96365f11518cd3f4a7ca710b", "schema_version": 1, "timestamp": "2026-10-05T05:36:46.428540+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8101d54cf4bc", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T05:36:46.467135+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9c84c8c3b947", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T05:36:46.529402+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b96b4514f591", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.662215+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8dc1a6a3c32a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:816db414e044ff88c1dbcb2a8de7915f5a0896ffff123cfd7d40514500be8dc4", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.684928+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6104baafbf36", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d19650cb022291bbfbd72e69ff047265f24802fcbb49591b32e00091b9786a87", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.693029+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7970e7bcfe59", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d21502f4e18c552acb0df33acde2fcb31fb13132e330066ad3fa8c7ca76cc460", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.705536+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b3827519a7a8", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:be1370c1bc215e37b54839a805e120e232ce9c006bcf92b886e95ee4b1f50cd7", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.713134+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_22c677bf37e8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:597f388d12f319142904c586e6fe52ca89103507046e544c09e4c22fafb0eff5", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.722937+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0255df35ee54", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:92fc08439a50f8b30f3031914c1c679fbbf6b1286aa57d3c275e7bc7fcf9ec6b", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.730451+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_428234477249", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:33bcd7a4bab1aaaca61f0b04a1ccb2d8738f69cdc02811796693a74bfd427b70", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.894059+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e33c45069fc1", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:806c6e13038e6bec7d2cb5629500f4e20641913d271cd41b4f43220e38e7947c", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.902495+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2bb2e855acb2", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:920783237c5da06c006a0fad524ced79ffd630a1588f4dfa842617bc4f31a8d4", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.915409+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e1e457811917", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d8952a2002bf9e1ce5a58d88a1c5960d83d446671a7c08eb18169a678fec203e", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.935917+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_600a07fe3b81", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.950326+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ed0bdeffab01", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:36:49.966938+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0a0c4a914df9", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:36:50.061831+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5b9d961577a7", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:36:50.075143+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_774ed53da96a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d634b3c56c2a754cfcad6ce6ebde0962f59ef8da63d8bd3fae76f563c3e679a7", "schema_version": 1, "timestamp": "2026-10-05T05:36:50.083527+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8f1971814595", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:36:50.147575+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c47c4e1a8eaf", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:36:50.159367+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2b1a067e9bb2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:53b9a2cb183e07b7a99451739b68e1bc8737884a3eb76ade3c808b4ded168d5a", "schema_version": 1, "timestamp": "2026-10-05T05:36:50.167368+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_90d11eeb10ff", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:98b1e1fe6b660f86412dfb433421bba18ef3e4cc64666170fa747dc51dfef456", "schema_version": 1, "timestamp": "2026-10-05T05:38:33.445774+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_67268fc0d9c1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9778a18c9f67e3ec65992c8071ba4bd657d748acc6cc74533615c0fab363eddc", "schema_version": 1, "timestamp": "2026-10-05T05:38:33.465888+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3e3860a63113", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3ae362a255148cb037b10542e1eb3d731e2ddbdfdf91462106ec1619949244ec", "schema_version": 1, "timestamp": "2026-10-05T05:38:33.478388+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7faffe7a5a8b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9c5be5bbbc518628a84b0e88b3e48f368ac12577177279c500c587c2dff746e1", "schema_version": 1, "timestamp": "2026-10-05T05:38:33.491615+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_095da8cac7ea", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7952e2373f4564092d77605de6c19442e33fd0daeaa368c5da9d35789fe9500d", "schema_version": 1, "timestamp": "2026-10-05T05:38:33.507000+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3cb464de6c72", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1fe0073aa75962977a1ea943fc39bde174cfc29e69bde57452d8c0682d85b5e6", "schema_version": 1, "timestamp": "2026-10-05T05:38:35.795329+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aad93165eb31", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0bd022b5e7bca573a4b89de5ef3f212e33fff86e3b481cf1cd486d0a62f484b2", "schema_version": 1, "timestamp": "2026-10-05T05:38:35.807662+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_62a3dd268832", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bbe96e04f0ed2016da5bc6067fe80621c38c859ee1b085938b75da3353f084f5", "schema_version": 1, "timestamp": "2026-10-05T05:38:37.584445+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_59fd1106595a", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7d12d665db123a8e962043cd008a5c4f07794d3486549f9b31711c730172a777", "schema_version": 1, "timestamp": "2026-10-05T05:38:37.599765+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_070e296856e8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:91346f085ea517e5e5b7b7a95cef12a0b8222464c65fe670a9f3227af1be21d4", "schema_version": 1, "timestamp": "2026-10-05T05:38:37.713585+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_65f122803784", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9e2e96593595566534fdea2dcb7d33074d9ea3160bbb5cc46deb8a864d952c5b", "schema_version": 1, "timestamp": "2026-10-05T05:38:37.722647+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aa65fbf90501", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:473743a4ef9c274ee281418fdd41f79a7bf1dc61762804464041b0c9d54ebe07", "schema_version": 1, "timestamp": "2026-10-05T05:38:37.784521+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bc458e29ab0e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ac9039e9c68fe381d478bc3187c2e4d051806a2530a903514a58f33cf67aec67", "schema_version": 1, "timestamp": "2026-10-05T05:38:37.793480+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_86a65591d13c", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:42:44.823632+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d4a4414d0155", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T05:42:44.835236+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e56c93fedf69", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:42:44.854320+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_95931996110a", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T05:42:44.869024+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0cb1c983a23b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T05:42:44.878867+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_166e07517dac", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:33e12566fcc99b849794ab4b5a1a15da98bc96e3744ec2ec1764a17268607d80", "schema_version": 1, "timestamp": "2026-10-05T05:44:31.430956+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_da7865fe3786", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bebb6b0e1af4788a9f490dd6bfa18c89661f60df990ad1edb9174c0e17c17ff2", "schema_version": 1, "timestamp": "2026-10-05T05:44:31.704577+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b3c787b8da9d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2df89b3f06ed8f3c015931e0b4f2bd99e117e1cbea28f21d90e4e12e1d3b078e", "schema_version": 1, "timestamp": "2026-10-05T05:44:31.940026+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c7bb3f5a59ed", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bdf7e2d63c8a34b20e2e8cc5f0a84a011a07e06155ae859057eea528167a03b7", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.154802+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e0b795194203", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:54a3267426314e299cf906551b830b1f41cc875ba80f08c93fc4adccb84daafa", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.417666+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_476f45fdd7ba", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8e819140472bab13608d0ab9b5f956fbda53968a80ea011ccd6f6e2943159f0e", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.681037+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1acde88146f2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:670e75a95e872e5ce3fa3a90e2d95790249fa737b52ecbc66d4690c4c1fdd67e", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.749960+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_97c4e18b2d93", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:63d8ea490804b0ad180645ec31ce94267477af333cf233de8bc057a9a5edf154", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.762348+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0bdd2a3b5a35", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f20f27c26bda798b98120148a9c8560be06d469c5e3b691ef862a57bb4301dd1", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.774305+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f462ba72d08d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:db952fc653b144870f19cc12e16261c01662d4ba8291bd9400cf47e11dd04b0c", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.785426+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_188013743147", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7d807705d56183f752fa38caca85496108c21f34f276d9d72416fd2a541c3996", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.797019+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_87bf9a3e7f20", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:83cd02284dd33685a0c85c9f19e10d31c11d56d2fb971cd4600d93bfb88f90fa", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.808544+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_16204db29b9e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a615539d019bbb7d2768f6a0579d785faea5deb0ea9592916aaf3679d6b7ed96", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.823256+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00772f43e9ae", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:40779e64cc9bc845f231e5442520294f75c4e6443584e2b9673398457a356c4c", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.834651+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5ead779f82cf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b7dd0cf3ec8cb4bf892e0413c4f8794c1353ba77c1cb2c38da2d4a35d2c09c69", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.845491+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2a4e01c7f481", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a446c5ffa0d921dc1dd5f8710a68c1a2744d14dfe4e02e0d9330f53cba709888", "schema_version": 1, "timestamp": "2026-10-05T05:44:32.855867+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_771b4bfd85ae", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:81440c6af5281d42bc03418a0eac2b52d628308238c49399d3f4a1693ae076fe", "schema_version": 1, "timestamp": "2026-10-05T05:44:39.492429+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_80c1ee255737", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c646063eae47121ad7ec5211c9b09435d000d375077f45d0c1eb4a03bec1d00c", "schema_version": 1, "timestamp": "2026-10-05T05:44:42.449164+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c454377eae02", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9e3d3fb1663ebf50209012b8135120dabd1b5adfe5a4d5a13e16cfcf58860bf0", "schema_version": 1, "timestamp": "2026-10-05T05:44:42.464333+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6b9ddf245574", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6934488d5d2eb0437ffa177e523ea02ddb356ae1c59942f267eb3068563ba55b", "schema_version": 1, "timestamp": "2026-10-05T05:44:42.597891+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_25b3b2544e7c", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3e5c7cb9591f03996a905c766ef60075159019d7285ffb0ad790d8d208c7acad", "schema_version": 1, "timestamp": "2026-10-05T05:44:42.607386+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_504528cf12be", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:68369939eb32683671f66183cc8853f748931834ecfb8beb462e0e8fc9bf25c7", "schema_version": 1, "timestamp": "2026-10-05T05:44:42.868608+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1a6c4a7dca12", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8f38ba034a9241ec5f3aa426262aab6db6781d034fa2885673429b3107b8cb37", "schema_version": 1, "timestamp": "2026-10-05T05:44:42.880198+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_be30cd830765", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:879929d8682a13d2ffe93935a7064c1a06fcd4bc3f9aeb687ac80ad42b627496", "schema_version": 1, "timestamp": "2026-10-05T05:44:42.890044+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4eb03f942728", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:977a76cc9165925647d184553fed7d27ca1c47887c5095e4a7dbc28209eff9b6", "schema_version": 1, "timestamp": "2026-10-05T05:45:00.429016+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_deed6a4991ba", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ce2bfe70056f98070bad99f1567239a6264e61c24adeecb980fcab7deed076de", "schema_version": 1, "timestamp": "2026-10-05T05:45:00.451606+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b9a9d752569b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3a8e35f1c0e024d97abc363b1d300a73b03bc5e07a654cafd4afcbd2a2e043ed", "schema_version": 1, "timestamp": "2026-10-05T05:45:00.472542+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5be6156f8e8f", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T05:45:00.513260+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_55cd751c3454", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T05:45:00.578950+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fb6c15646a6b", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.026203+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3f5a8f90a41c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ac69806d912eb3a9b320fd8c8f6d9124fd7fced98d3bc46b4df5f568d5c31108", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.042663+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2174cfbbe69e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:75a370143979b0fccb1fedaeb1e2ed8206399b49d48ae3f0877263b0dab83a23", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.051660+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_20cda71d281a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cef87be02a86380fd1a051c327cd6a145099292137b936d87ecd65045ec5af1f", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.066684+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_464b6c752888", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:db037c3f763141827d4d8c9b0ee20641284d0a666bc9ed1edf56958b57062011", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.075671+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bb46cddce63b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:60a50030bdd269d099e22eb663cb1903cc155a7d8b44f017489fce0a79134351", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.087436+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_18b9e55889e5", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7672d9151744b1c821d01213889873aa3bdf91136931e5b6569449ce57f781c4", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.097051+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00987f249538", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1408f4d3c02333c4afad0794c0acc1909c0eead9e7a7f7535769cb9d25330b40", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.274204+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2cc49d0017b7", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:79d9edfe5812158fa5ccc9d64956d87ce42f9bec34c0a406ed81d77b1591efe3", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.284161+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8a3b8cf8bb14", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:17cc5136d9bc9a5c1eb4a701929b44c506724ea45a189c8e18f488faeca373bc", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.299977+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_510ef9a92f49", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:62208f1fdad2bf0c255cafc4eeb05665dfce21b9ddfe5a51eb0d93b99eccc1af", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.319722+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_af8b0c870781", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.332925+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_14db91071765", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.346088+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ba76269cc515", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.454417+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_82d9ec4a22fb", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.469651+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_79f262190092", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a5d99484006ea434d81830d84831d7c16fac1447f56f45f7d3d9edf9a7276098", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.479105+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5cf1f3250908", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.559262+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_855812c23cc9", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.574403+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_784b0897cee7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4e038baa85e8c7614cecb11abedb755abd1d7750d090f196f0a1dfe51945b3c0", "schema_version": 1, "timestamp": "2026-10-05T05:45:04.584189+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5dfcdda0076d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ed5b59221dcbdda04d40f1388f885f5d74635646b0338cf4b1dd9419d5dfad53", "schema_version": 1, "timestamp": "2026-10-05T05:46:48.024867+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_27bff8aa4a67", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:10ec5dcc77a880f9a5d5c0d512bfb87ff7a7fed4e17366cda24402b9a4e360d3", "schema_version": 1, "timestamp": "2026-10-05T05:46:48.039242+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f52cd7d380b4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4ea200291a31ae31e28299c5f74965fb274baa8e203ea5d097ba85c404493544", "schema_version": 1, "timestamp": "2026-10-05T05:46:48.052314+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9219dda77d9d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b6b7f2375ec62e49788aadd23fedfe33e086aa90004dbcedb5d7c8b54fd33099", "schema_version": 1, "timestamp": "2026-10-05T05:46:48.065181+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3d4288eb266d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6c78ce332472854639277b6ab8f616a795a6cd32ac294f34664a173067fd206d", "schema_version": 1, "timestamp": "2026-10-05T05:46:48.080369+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aa3cbe49f920", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:27d33fb0a4fc82924ded62d227a5ee833b17a07318f13286ffde9c16f0e75dcd", "schema_version": 1, "timestamp": "2026-10-05T05:46:50.886509+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4a9b36a3a31e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e2bc10744ab9b2e2052e8fc8c5a7a5610e4d019d09ae867db8374eea19c187ca", "schema_version": 1, "timestamp": "2026-10-05T05:46:50.901612+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a24806a7223b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a548d0c18e1531f8ae4e9b64fc92112e3cc3ee304bc62656e85f59db65cc7587", "schema_version": 1, "timestamp": "2026-10-05T05:46:52.705101+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2f587e51ad36", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f8ee37c7bcefb7c8efda6eef02582a96209283c8ef5543d4360353c37fc06881", "schema_version": 1, "timestamp": "2026-10-05T05:46:52.720208+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f614f8afb5dc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:369d49705e0cb1fb730096ab32de74671f17c22db9ae1976d943fbb6fd11103d", "schema_version": 1, "timestamp": "2026-10-05T05:46:52.837816+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_eb78de821a48", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8ad92fa610c3b29207ee69a19a9518a24b1bda406dadbfd643c9c4c33119aa0f", "schema_version": 1, "timestamp": "2026-10-05T05:46:52.847320+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b63c11b0e85f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5ee130d09ce403ab7ad4afcfab5e1ef2791fa637d4271e41b5771f094e837389", "schema_version": 1, "timestamp": "2026-10-05T05:46:52.910886+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a171c6c09af8", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9e6dcb2453feaa565595cf31ae5cb484066d23115b4d3c6a0c4fdd0262fd23b8", "schema_version": 1, "timestamp": "2026-10-05T05:46:52.919949+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_efb440868a36", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:48:35.308535+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3b0786de27ae", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T05:48:35.325629+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a11066af0fc7", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T05:48:35.366267+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bbaca2f78b39", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T05:48:35.388623+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9a20a36a9f5b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T05:48:35.403210+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1e7669f2bad7", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:30:47.078182+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3bd981ded4c1", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T06:30:47.100458+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_681838e3fcd9", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:30:47.137264+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_da525a3c0fc2", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T06:30:47.158469+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c2feb08b8a36", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T06:30:47.173548+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_026a68360979", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:890f37bf8225147a6df15dd4d7d1d14b8a34f652457cee7eabb5e3d667e7d228", "schema_version": 1, "timestamp": "2026-10-05T06:32:35.779852+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2a49b38f6181", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6b38d9e665655ee59bdd175c8e260de8cbbe3f1e893beed1bbe6455415afc298", "schema_version": 1, "timestamp": "2026-10-05T06:32:36.653680+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5d2eb36d5a2d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c939b140dbc98d89a70d545ebee22f4614b8a00dfe75ddac5e2ce882852f6eb0", "schema_version": 1, "timestamp": "2026-10-05T06:32:37.331588+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1827453bd8cb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:254b8faf2ee47df4669c2b291b122e35d03bc65a9071bf4a64d6e5448604e232", "schema_version": 1, "timestamp": "2026-10-05T06:32:37.991661+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d9b9bd6e2e6b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:eeb57cc89822598f55e680e53cb89da3e4bbad9ee60333ff09738791794e7a62", "schema_version": 1, "timestamp": "2026-10-05T06:32:38.795950+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_69e66a7a0210", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:268c016f21f859433fc2715c2cf88616d2a035902edc3281208599b3f27bb358", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.641517+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_09c85ac1604a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0c26db1dfc9ccce93d27b697ca16381f4e8bfe65394614fe0f15cd6e33bd863b", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.835431+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a901d6aebf00", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:07df8e3a2a1aaf33db9b7281e29acf4375d6077cef4d87348fbe3141e624e8c8", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.855492+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c5c802b2af64", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7156b07cac29fcd922a2f8a03edb64e809409e1c86493053f6a2281dc74fc96c", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.871970+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e587dc0f2eff", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:150637057f4ef28796229418e35e3e62ffed7be70b399c4e1b102c15efb3baa9", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.889627+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c6b33ff3cd66", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2785fca0a2b93a259f81530e43e5e482fcc6146fb0e5919c3b948a15c316c9e8", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.907130+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d9e1a7f9e61c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bfed397f2e443f20fd6f9f7c88efc309655c6c01b5c1928e5d8da357731544cb", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.922819+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0f604f2e0173", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9ef660d5dc89f4fb721db88b55bfcebc906cd26f7b29d492cd5816ab7427809a", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.938886+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a7a21aa5fdb8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bdf76219a0f1dad6d9883b32f014572fccc584535f4c350c442902a444800bde", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.958883+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5988197924ca", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:358ea0187ef5b34533c467e8894408ac5eb27ad7990fc854879cc62eff61fd7c", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.976738+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7277acc98310", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bf3f151e86ed731297aa7d57315277cf1734f7a876e0255bc6db17f848731596", "schema_version": 1, "timestamp": "2026-10-05T06:32:39.992309+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7c0ad3b6a366", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:520cc5250ce983f46fbf05ee636ea10f8e13056611f25a151ef535208cc08469", "schema_version": 1, "timestamp": "2026-10-05T06:32:43.167134+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_76140dfb8cb7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e493cc9b5ce492a629104ef291a1e26112b59aa86d506166737f606207daa4f1", "schema_version": 1, "timestamp": "2026-10-05T06:32:46.074794+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9357b38c18c7", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9284c060ed8738d35aee98a0f75df7b72673cc93d5b8ccf3ce70c409608bc93c", "schema_version": 1, "timestamp": "2026-10-05T06:32:46.092864+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_93336b3c0836", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:48001e7aff69dae16d512aa99fd2e5f03b8733d4b2227c5c9a73545429b9b385", "schema_version": 1, "timestamp": "2026-10-05T06:32:46.274021+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7ca37a9b2aaa", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:433ca78ec83370b43a86ae38f7346bcf8e5bc0da1378bcd96122e77a61f60b85", "schema_version": 1, "timestamp": "2026-10-05T06:32:46.285731+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ed68c9d461a2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d68f58dfbed4a8becb415c01a3f2170fc68418e973b6f60fc76b286050ed654e", "schema_version": 1, "timestamp": "2026-10-05T06:32:46.596825+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d44e5ecef962", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:01c4fc9c7b68c9746303322750fcf1c5419c5562508b37391c28c118b471190f", "schema_version": 1, "timestamp": "2026-10-05T06:32:46.613587+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_49d9e8f55750", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1b6540607c303b1c7963d743038eeb4e5200a36c5f66dd4f9e69f8c6a0665677", "schema_version": 1, "timestamp": "2026-10-05T06:32:46.627481+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7965d3c2de84", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:368ad204ed6c06343e6038bd6d35b46cc207df61b7238f6b95a9ebe572763249", "schema_version": 1, "timestamp": "2026-10-05T06:32:56.022606+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2a754a8eab42", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9f687defe0c19263533825fa8536e5aaa81ce61940b2869d3ca9dbeda40b135a", "schema_version": 1, "timestamp": "2026-10-05T06:32:56.058422+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_76ef0082a146", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:efa9aff1d534f8bfc14c0b14fe3a58b8b55907b7d160389cbbc8afe5d52ca0b6", "schema_version": 1, "timestamp": "2026-10-05T06:32:56.109077+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d52482f9f96d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T06:32:56.172385+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0e151ea3d0a1", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T06:32:56.300074+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9a84aa36f25a", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.091372+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_478a2a6f3f94", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8b3627a045b0b517e975b68a8da3b32891c2411ffe6ce9fbb97f72f7e2633658", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.125442+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6ef6062ffefe", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:19a99bda927f983c78b82bfd6053ee5bb0a63be42b73f92c7ade65a1821be017", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.136175+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aa5c04eee7d6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:daa454fc92f336a672873a14420c875188613bc1623051a9a212025a5a2acd85", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.154712+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f5a558c9ce50", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fc26c9be2a163a5b34c58c533980da9a4bdb75a51256d692a515761de8ca3518", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.165583+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00cfb7401d9b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9d4c534d642cd9fb949f17ffa7c4a4aa0aee203c1a2606d77bd7aa0738053a2f", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.181226+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f94b5072d0c5", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:baea61f9d3acd8b1fd054b359f3571e26fe44964c18104b77d8c88fb17eda86c", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.192038+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6cb5b3246109", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cef698ec3d9e8581c719efa5217951e55db9f8ce0f2a607e5e761a7953a8f9b2", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.322737+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b5a664e74c85", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d241bb90ce22d731c61d9ee65ea9957256fa753010243939aca3e3a45e5fb73e", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.335063+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fbb792e34239", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f5a249e9ad34edccd6a61dc67eba4fcba2918df4b66325449db446debaa04c29", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.355622+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_81a8a4a833c7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a46f73ab501bdc60cf4c543d56ba5e6abda7053043d697b6433a3ef04fdc9548", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.391878+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c3c5cd2993d9", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.412904+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_085b1a727eaa", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.444250+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_510f343b6ab6", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.627098+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ff38d1208cf0", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.662021+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8349c1af8de1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3e02f546d3eeae63e6dc1ba93d28159719d19ee54d29fc6dbbff4a554ba06488", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.673829+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cb647dafb557", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.770606+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_385e99f0038b", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.805270+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_043e7bac4c97", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b3a8c41bdc31d460080143cde43622c1c98f6e7ae662e4b43080cf00bf63d566", "schema_version": 1, "timestamp": "2026-10-05T06:33:01.816613+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aace2f37ca5f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6864addf067ce58d86ab40b1dcafbb24109fc29e7050d684538a31354ac59dcb", "schema_version": 1, "timestamp": "2026-10-05T06:34:47.569047+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1144243c150d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e8e3defeea6670131bc8863101fa1923795b272166c64dff7a705a395f7b08da", "schema_version": 1, "timestamp": "2026-10-05T06:34:47.593005+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bf9c63616ca5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:961d3b2dfb0be05a7f3d8e115f4d78f3f9e83d200a6ab6235024fe21bab0fc92", "schema_version": 1, "timestamp": "2026-10-05T06:34:47.609147+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_309f95c6a4bb", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:06f3683c27f16f9bc173b6f58ee2264d0f3e7f1ee41947015da0c55f809f669c", "schema_version": 1, "timestamp": "2026-10-05T06:34:47.627150+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2546ff004b57", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:71e916d7a5a3bf292035bca7d4fa9d19091367aede69a6c7e91e3e070a999621", "schema_version": 1, "timestamp": "2026-10-05T06:34:47.650566+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6aa18b2a23aa", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f5b7005cf009d0f0408ea60753fc35a916f0d695e6c565b46a3dce93934b8534", "schema_version": 1, "timestamp": "2026-10-05T06:34:49.915433+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6b01de5f2b30", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1c4ea8048081f1a8b9cdbcdc5abaa172d643a683474d807bf308ed59b9047525", "schema_version": 1, "timestamp": "2026-10-05T06:34:49.934060+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_437b579f435e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7f90bb33fc830d95c60abaf50f58fcf7a7863e1d3cddf10ca4e50654d0c14d91", "schema_version": 1, "timestamp": "2026-10-05T06:34:51.806895+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dd53291a04b6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9302e5dcc51c93f0b323560e075bc81a89594b0ab0395d3ae855dc42ee7c63e9", "schema_version": 1, "timestamp": "2026-10-05T06:34:51.824797+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6676059944cc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d73de3ab7d7f81b31ad83573cb7a7a1c7db9dd71a7813315b115a20b62f4459e", "schema_version": 1, "timestamp": "2026-10-05T06:34:51.954770+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_92ab14d24275", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1a74ea6323daba4d2e13d7423ee3e5f7af0f167e38578db1d39997383533d561", "schema_version": 1, "timestamp": "2026-10-05T06:34:51.966761+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9507f13a7d33", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6a7f3696e047c7639f12f6ed33e30649c17b684a80652763a9f755310d0d57e7", "schema_version": 1, "timestamp": "2026-10-05T06:34:52.048084+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6a60c2a0af6e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8ac6a632fafc0a61353325308ed38a8ea47dd5380913f6900956b6daa6090638", "schema_version": 1, "timestamp": "2026-10-05T06:34:52.058880+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d2b51ae48dc7", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:36:07.796886+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fef86120ae96", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T06:36:07.817924+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_74ad5982b3c8", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:36:07.859340+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_949631915cda", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T06:36:07.880771+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_21f10ab46e33", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T06:36:07.896081+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7d9ffd247e6d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:968a848f54f5c3671ffbcbda5bfc78c51a2177c59ecf4f307f8a9991fa78828c", "schema_version": 1, "timestamp": "2026-10-05T06:37:56.419498+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f694ba86ab08", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:455e1a70a34942066856399e9148dc648a977af7e5d53ab4e73f8905497f4540", "schema_version": 1, "timestamp": "2026-10-05T06:37:57.303456+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7ed308a97815", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:823e22f0b7eeafff706b77ca49e9d2dba3102bf63755e0b64a9ff49ffbab2794", "schema_version": 1, "timestamp": "2026-10-05T06:37:58.005817+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2c7e3fa8fb26", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0ebc068db0c8ff8bb928143444a811583b56152c7c0cbc3d67c23bd3c187f3d1", "schema_version": 1, "timestamp": "2026-10-05T06:37:58.653201+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_386905a511ec", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:90cc30b59e1526a0b2370f1a7870b805d784139cde3a131b1489c6217c938cf0", "schema_version": 1, "timestamp": "2026-10-05T06:37:59.469729+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b7beb759dfa4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:68bfc12190f39646a736c88face38af541cad5d30952f348be1466c32416e557", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.254815+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_97c44a7789a0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:61801f4c14d0302a99a63a2d8a62533b96c6a4e967dfb947d7d4ce3f6e0afb08", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.444982+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3d13d384dd3d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8b0771675ae6538804718f636a82eb78afcbfa27605e5c8df4b35f9a431c0878", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.462542+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_446cd619ca60", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e13026d656fef5ccdc193408342f3cb2f379a2b36951a3d711f3f3cbe39c6589", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.478480+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e9e8df4344ea", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d6eb32686877061fdd596b5289b195b7ea087dfbd272f665318eb878025b8c73", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.494659+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d84bdb26b788", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:442ae35d562a1afd2cc854c7d4f77e844494930ad27b4104015db78eb789747f", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.510574+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_93ed035a6522", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8bdfeb1dbcf30bd1371f9fca87073b617d6da9bd66b1e5279e8c5c4b4f05cfbe", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.527200+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b65d0bd5f9e8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a01006abbf7ebfa3a91313daf9dd6547428d7fd3986d6905ff056fc04ac0f36f", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.543656+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8b87cc163c59", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a0d50fa87bd699048f4465d2db94ff5e62d5a54b605232482766d9ffb736e0d8", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.559437+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_76d27953ceb8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:47921bd04e256ec81c36f7bb3378c2fcf7f243f7ac852b7b6c41b6f0e29bf599", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.575689+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_25d022f4fe3e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9d76be0bef8e521a711d03af47e84443028ce5edfbf3211570c25ca7b786b43f", "schema_version": 1, "timestamp": "2026-10-05T06:38:00.590787+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_bc3b9807f3bf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3b380dfc8098a90acf10ced31c0393b1f78df3c4137dd49bdfb80185548a15bd", "schema_version": 1, "timestamp": "2026-10-05T06:38:08.680156+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_28a2b41ff52c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:047285e91a7429dd3c9cf9e82bb86bac191b8e8bd4216769b61a3811da28b736", "schema_version": 1, "timestamp": "2026-10-05T06:38:11.642868+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_183842fd36db", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4991c9cbc236491ce16a10e1aebe6f47d603b1b1e9268e9f99518365c78b8a7d", "schema_version": 1, "timestamp": "2026-10-05T06:38:11.660841+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_49851bd52edc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:1740e7eb428ea7ab41a8e2b626d80ec0a2014c29c6198dd1f671de14c2ad39ab", "schema_version": 1, "timestamp": "2026-10-05T06:38:11.799804+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_850a3dc1c2de", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7bcdf33fd6b7b97982dd16a63f439f29dbf2a24b784e727e77bbede25f7474a2", "schema_version": 1, "timestamp": "2026-10-05T06:38:11.810791+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8bbe0710eb22", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7c1d1791282f9c5168109e1381ac072d4585455d315912bb6255858be9466da9", "schema_version": 1, "timestamp": "2026-10-05T06:38:12.134189+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a520c55fea52", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:49ede411ad05435c5cfd51d2a35d930388c34f999b31b4701ee434f48ee0ce07", "schema_version": 1, "timestamp": "2026-10-05T06:38:12.161315+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ea6523fb36a1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9370ff07093a7c50b8dd8eb6fde6c7763eb5d1fc0e6d213da02c6dee29457d3e", "schema_version": 1, "timestamp": "2026-10-05T06:38:12.175162+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f0e800ea94a8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:edf27abbb010cf840fc409f722bc405692376bd64efad9a17bd6dbb20bff85a7", "schema_version": 1, "timestamp": "2026-10-05T06:38:21.174200+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2503ec730320", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7ad2b884ac08eca72b4a97600d7e947d7ce1729dc040690e010bd9ac57ba7221", "schema_version": 1, "timestamp": "2026-10-05T06:38:21.207816+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1c6d4afcd96a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2cb0bf913b7c9cab6a3fcc3f04410387809c61e608acca29786140ae8a9415ef", "schema_version": 1, "timestamp": "2026-10-05T06:38:21.257312+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_76d0c12b668d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T06:38:21.318255+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cc19a85c6ece", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T06:38:21.430892+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c9c2a7c8acad", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.287716+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dcabe4f29a6c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9a47ec95b7682899edbab5b412f9a71269aafd5f1ac4411d7b3016f0265bef81", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.317935+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c045cd6c2024", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d56676e362acc5639850a57f35829495dc6c851db3d12161ec99a5eb832d716a", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.331437+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b805ac6f2d92", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e455cde244b6a07fa9b26a38321ffe46246134f4c06de892bb4a683f5cfb3597", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.350396+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_052d0b45e6d6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4790c8a8109241feac7dc5fbc5737e57da3a4722b22d23348f06af108ccab11c", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.361147+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5ebffc5e1b05", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ea754bc6aadfbcaf4c5753ecbf584e718fbc035282b614bb01896deefa01a380", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.376212+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_574f699f8df4", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:89844af88766ad50f71eb54d7f1a245966bb2804bd97c10415eba0934718c016", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.386874+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b83811d28750", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:44f37fd54c84d094be680ab3c2fa7171fa500835e74d9c7a21ea656b05d66729", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.508264+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6cf85bf51ba6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b08e9a33d37bc9ef17274f5e0b49eccef31d0eedf6a2b65794e83a71181f266a", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.520332+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2da9aa4c9a60", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:df8757d20489d83861b62efea8fb6aedfc741b0eb45d69b7b1812b1846a9ed77", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.543926+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5a72855b5690", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3064ce063515dec6d54b2705aee8b066d5cac7975d631119e5fb08e227ca3fd9", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.581480+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ac1304f762f6", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.603341+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d0705973a48c", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.631739+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_91085685506f", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.813178+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cd044ec70691", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.844678+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aad8c93b22a0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ca1dadbc5acd179dbf0f0ebbfba2940ed7c219120fdfba9e00f7743cd6418ddf", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.856333+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_adb456d34b5b", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.956426+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_31e05c902516", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:38:25.991480+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2bf3e8e8dd37", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0f94c237c37daf7128b0c8c36659f839a6aa582a11d6fb1f18c67bfcc14ee69c", "schema_version": 1, "timestamp": "2026-10-05T06:38:26.005115+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b58958a57056", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b5af1a049fc1a5337394e200aa67eb2b0648a7cb9ef54197bb52aaba04fdc32e", "schema_version": 1, "timestamp": "2026-10-05T06:40:11.672517+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c13aef1c02f6", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cd3b310a80e47e2b0fd63962ef421abd9b1f0421e980c32e09f9bfb84e514099", "schema_version": 1, "timestamp": "2026-10-05T06:40:11.696838+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3321f8deec3e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b4312c49da8a313c7a51bb15fdbffecdd65bddef13f2af8c2382e047b474ca68", "schema_version": 1, "timestamp": "2026-10-05T06:40:11.713426+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_79c0164eb4c8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6967ee955bf704859daa6d53cfcd0702fa66610d02945cdbf6f9e30764f4ec78", "schema_version": 1, "timestamp": "2026-10-05T06:40:11.730583+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f21627c7e1a5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9092b411b050189b053d27608a5b0cd81c5fd589a4bb91821de6d7e2bccd5361", "schema_version": 1, "timestamp": "2026-10-05T06:40:11.753618+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4f2b01d6a30b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:296602153c579e0cd9904d42d14c823e2428738077b8fa105e1ab7273d0ce215", "schema_version": 1, "timestamp": "2026-10-05T06:40:14.075803+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f8df3ef9e8bc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3aa26eec69ddf1a1e675f9e022c747383454ced9fb52cb03d5f35404c3e47e05", "schema_version": 1, "timestamp": "2026-10-05T06:40:14.094387+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d42bd9a2b2d2", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:25a0dd94a7aaba3a2a7b875f7301dd0a4fe5defbd346a3d1a3dc35e8ddc52a1f", "schema_version": 1, "timestamp": "2026-10-05T06:40:16.188557+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_eb2d07d3115c", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b500649f883e7965ccc342453c8538b2b04b47b2f7c9bbdef29df9a661531f92", "schema_version": 1, "timestamp": "2026-10-05T06:40:16.207254+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2a118b9119dc", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2b97c4fa3630d6b2cfc94b9c9f6fe1895d610c84daf5fe64f1696ecaa9220adc", "schema_version": 1, "timestamp": "2026-10-05T06:40:16.354579+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_86ca4d7a77bb", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:19c52aceb064b4732cf53df6e74faab0ac7efe674e09cc00f4e82902d13bd194", "schema_version": 1, "timestamp": "2026-10-05T06:40:16.366816+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_109f31ac6841", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cbc7f5d4c7424ed0e44f6ae0a21590ed36833e7b38e36cad27a8ebe6ae2b2f9b", "schema_version": 1, "timestamp": "2026-10-05T06:40:16.513616+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_18c66c43e3f6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e641ebfc5aacaa7a16978b37c1561d19df3888446d5b92e99965d8c4cec0f546", "schema_version": 1, "timestamp": "2026-10-05T06:40:16.525607+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e1d27e5e4ece", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:42:43.695303+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3c2c996aab11", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T06:42:43.715767+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_64a6bc1219e6", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:42:43.751147+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_823e376a2ab8", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T06:42:43.772059+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_992151ed6d5d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T06:42:43.787261+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_40d37cfe232e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4194bf68326491d749572fee36638973aca742b62f96768430ad1e28ab24e954", "schema_version": 1, "timestamp": "2026-10-05T06:44:32.307566+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_60f5ca534243", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c17bba207b98e22e3bc0902005dffb8904aacbb78e362e51b65a5eec96fd4bd5", "schema_version": 1, "timestamp": "2026-10-05T06:44:33.180051+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_03b28fdb5834", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:69c8d274fb424154a03ab309635d5585a2a4c2514e1776f91ad42573beacfa57", "schema_version": 1, "timestamp": "2026-10-05T06:44:33.889652+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_165758a5a86f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4464a2a7d7a0616e2c7cfdfa96efd8f5ecd82493049b983ea0da805235ec6cf4", "schema_version": 1, "timestamp": "2026-10-05T06:44:34.519879+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3c96beeeb2e8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fa90557634208f7fbc555c570d68994465c4b1b300b114be2810808f2b9b77a6", "schema_version": 1, "timestamp": "2026-10-05T06:44:35.362910+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dd459e85a36b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:548fdc5109d4399f565aca03ceaceccfb938fddf8de7f73a581685172ab8ee8d", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.168807+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a44e2f05e40b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:972ee75d40b40e68743270717324267be65fd28b40ea5930b840a08a07bbab0c", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.365273+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_04270e9391bf", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b0fa54f8be9efcfba04d1de2b4107a9c16264bf3d0aec3120d3d536205fc4291", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.382108+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_5af20380f281", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7abc73c396ab63dfa6fb773eaa3a61f8fe53409ca70c391e3e5c47af718158b5", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.398266+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_56329fedff7b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a04e448f80df63b6fa2df6d7d433e5ecb09d0da8fa98236b68dd23ae2bf26c91", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.414558+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4f972f10b79f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:32d34c5f9257f369e5c4f750c44adb531c54370063da4ab67b01e4a6fdb5299f", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.430869+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8ffb29c01222", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d14edc631f972b3a0c04566dc0d6a173baf2ca3d7f24c0e53a57d74f191011fe", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.446866+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_04d0781dcca1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:75523bcd62656cc336c54ea8b23689b7bb80c96f9dd314f33912ead0e4b1284b", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.464640+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_40fcc152c131", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:006a9aa13c86a45a6c312db740b877a0b41d8ea7ad93387cd6dbb46a9afc8cc9", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.480833+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2f52fc4a9676", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:410b715c571c5b4d0c59358b2838562c75a4cf18ddbf23c30c61b3061337d5ea", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.497205+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_886ebc880de0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:71325a628e220e35035545dbbec4e851728b7b75bf2e1405759ac7afe8678775", "schema_version": 1, "timestamp": "2026-10-05T06:44:36.512577+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9da6b2641be0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d1f636e09ff2fe01e73d090dda9ecc1ef8a6a8a4e0b2785326e9ccd673489048", "schema_version": 1, "timestamp": "2026-10-05T06:44:39.781695+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4fe18265b729", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f2648039fb8595994fb846b6e34667f854d395621f2b80f4f9025bb52a2633d2", "schema_version": 1, "timestamp": "2026-10-05T06:44:42.753278+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aea6a34012bb", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:52bc97dc6e8aa989f1ff0b2bb2d67559313b25e26b790f922dc96b9c824941b8", "schema_version": 1, "timestamp": "2026-10-05T06:44:42.770992+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ae907eabf22c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8e5614f02085b3f74fe190a820c3415677628bbc7d9a48bcf16889307eec8646", "schema_version": 1, "timestamp": "2026-10-05T06:44:42.896921+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_89f42ccafce4", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f25afa2500e6d5f330ddb68722bb0cea87b1eda48ad87fc18e96236f847c38ae", "schema_version": 1, "timestamp": "2026-10-05T06:44:42.908475+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_df0b2029eda0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c70b08e3925a62cfd2cedb602493e0fcce58048ca06d2f2d75fd11ba0ddbf705", "schema_version": 1, "timestamp": "2026-10-05T06:44:43.216944+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7fcbdfc91c59", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7a8e79b47b1d8985ecacea6b5a174df904765886dff5b02ddc63471d59ec056e", "schema_version": 1, "timestamp": "2026-10-05T06:44:43.241236+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9baad33fd781", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6db17481fa3ea741d28acd7d3961c23d13c9d565d43b7a65bc9a818574e471b7", "schema_version": 1, "timestamp": "2026-10-05T06:44:43.255526+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_695295605a5a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:004d5250bc06f4613c8c306f3ce51e43ac96e27c6ed047f7ca64090634d46360", "schema_version": 1, "timestamp": "2026-10-05T06:44:52.627390+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_35587d7c59a4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d5fdffe94c20869b64221f2ffd06434010311f5a3d54d88d7f5213daf1035ac3", "schema_version": 1, "timestamp": "2026-10-05T06:44:52.662662+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b7a9aad15546", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2ffbcd3dcb4edecf2f9db58b667ddac40f619803cd43f31e7084e7106bf7de75", "schema_version": 1, "timestamp": "2026-10-05T06:44:52.711855+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3214ada9057d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T06:44:52.773638+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_66a3f9fefc32", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T06:44:52.895988+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6ac943e896db", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.177919+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9be57bd7c54c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3e3f6e9fefeedb136d333d8769fe46b221526b7edd4a3d2d7facbc136e8db796", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.208657+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_31159365346d", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0fe00b46a64b9c6642368dce1378ece9f5d6d6b14c797287708907d20b4b9e4b", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.219345+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d52222cd7d80", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e602de80f93a023e2131aa9a445874a6dc48d78c6f50dd2b0d470ee45d5362aa", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.238120+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7e9f8e4e97c0", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e54fa0268b176a1723b960d3c5ae25d30ff250cf50e21b8cb8a46a8ece8286ca", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.248732+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8a4ef30f822d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4d48b559fcd80dea394094bf5c0f4162e6eeac33df2a8d15203883c5bd7c6391", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.263172+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_eb81b76b99c8", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5a52c1f77872698dccc773d78b745242615e715b1f88c2589f7168562ba5ff0f", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.273977+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4c748f973d1b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fe8c879667b2f93ddb30f0fbf8f6a206996a8db1d436dc7960ab06f16ee1537b", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.393687+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c38eaa856d9c", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bc88b9a72c2f2c0698966ab7e35587432b6cf5ae9251d6d3ca7c584a8fc34435", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.405254+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d37393d28a53", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5ec4efaedf112205ad3a290f9ebf8bcf35a8e2045895e2b4ab918bf87d014345", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.425322+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ba6fe3f86984", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2ddb84a16807ce9592ef237d27acb7dda3f7f735c41d0779cf78f8fbefa5affe", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.459524+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4129aafd1e86", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.480675+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_476e56d323bd", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.511156+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_877ab58875f8", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.687441+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f9518821261a", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.720206+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cd3f3b942867", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:df6c0ab5af248d8c80df6abfc54fbf9db8fa174a06de6c6902f685895d81ac19", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.731921+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3190e14af0b3", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.816502+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_030fe6069de9", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.845351+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_6b0909d24377", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3cd9033094d9a4daddc4d8dd9c5c7560d112ee577fe02d4bc7cc470136b78cad", "schema_version": 1, "timestamp": "2026-10-05T06:44:57.859103+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_33428887b522", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:719daf9f5aaa2579ebaa44ee5c88b237d2892bbe4d9fd833cbe04b51b4271412", "schema_version": 1, "timestamp": "2026-10-05T06:46:43.504030+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_776d3cf5853f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d68a73462f237c9bfe29eb0012181be186100cf21061efcf616cb16d6ac93acc", "schema_version": 1, "timestamp": "2026-10-05T06:46:43.528608+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_14cda5807789", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f0994a7430b1d9852b05b30eadf5eb975c642608d43f880e94de237c12332966", "schema_version": 1, "timestamp": "2026-10-05T06:46:43.545774+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_140965cba2e3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e3e4bd074e5858d86f51c855fda71c5c7ea8438e6b0ed100e8a346fdc38a3623", "schema_version": 1, "timestamp": "2026-10-05T06:46:43.563331+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00c79b9d1a00", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f9b0b3b4d221d2838dec9d53c857d5a6254b02a15d54138110b8981fd3bdaeb2", "schema_version": 1, "timestamp": "2026-10-05T06:46:43.587729+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_13dcf5763b8f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c4908bb1490e126dc49f249a75c6c9fb624a7a441106c17255d1777f9603c75d", "schema_version": 1, "timestamp": "2026-10-05T06:46:46.278951+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4c6cef1c8d45", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:aa8fc016966f6f216dd6c0ed424c7196a3aff0536507d3a6fd52ce0f159929f8", "schema_version": 1, "timestamp": "2026-10-05T06:46:46.299897+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_aec1fa75904e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a94045801be5d27889a5153185173d9cdbe063c8b57504c6f60a80b029584b9d", "schema_version": 1, "timestamp": "2026-10-05T06:46:48.101655+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1b3b00190ff6", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:84e975644c2d6bccda4f130f3f9f028170796c521f29667da82db31f4268cab4", "schema_version": 1, "timestamp": "2026-10-05T06:46:48.119418+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f215e9d60b05", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7cffd2855e55066206b6102d10ad3126fe0e95ecead0e675db5d6a35b714deef", "schema_version": 1, "timestamp": "2026-10-05T06:46:48.261428+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_211c93c72ff3", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:b7deb9a6bebae0f02039a89c82cfd4190e44fcd1584496945f4869ab5ad2dd69", "schema_version": 1, "timestamp": "2026-10-05T06:46:48.273213+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c9bcaaf24849", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8a2c349386085e0a0fe12210fabc7f4193a6cb54f072859f9e0c279308c881c0", "schema_version": 1, "timestamp": "2026-10-05T06:46:48.405587+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_885a3d5481e9", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5ac99139cf2fb4e902c5d5e4aaaffe8d9631f41d6fc8ca6068b1216df3e8a6f4", "schema_version": 1, "timestamp": "2026-10-05T06:46:48.417188+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_13b5535a9146", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:47:39.043363+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a36302d909de", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:5905ca1fb3b9d207b290447e7844c186b1a34e36d7a7e4102159cee3f8ae136b", "schema_version": 1, "timestamp": "2026-10-05T06:47:39.060088+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2b4df73a86ec", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:47:39.078783+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f9707edb7816", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:600ba21f0472de9fb57133929648cd8121d1717595e7cd27c381d71ac03852c8", "schema_version": 1, "timestamp": "2026-10-05T06:47:39.092698+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_04d27d8e6ff8", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:8a8675818b5d411241e416ff9e8c9a1845d9b2a8befeacc51e10ab977731aeba", "schema_version": 1, "timestamp": "2026-10-05T06:47:39.103010+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_74854b98ab41", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bb38314acb236f08ae39cb60b5022905678e86bf146d16841856ee34f1cd614d", "schema_version": 1, "timestamp": "2026-10-05T06:49:25.034574+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_24326590943d", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5b3bf4b1e76f3378365574bb10f3bcd572885577354d5ba81bab5a1b98d4233c", "schema_version": 1, "timestamp": "2026-10-05T06:49:25.309489+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0e9f3f7ea0f1", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d12d16329de90f8b15897f8c294447b5c028ecb9e7b19a036e8c1dc586529775", "schema_version": 1, "timestamp": "2026-10-05T06:49:25.527943+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_7d3098712d56", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:da65d91f039c9b4385704a54c81bb03996df06181e83024f1b3baf3e208fad27", "schema_version": 1, "timestamp": "2026-10-05T06:49:25.732453+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4b01028bfaf7", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d50f083aeb4328ba31efb3f8bef7603aae54b5bb47c90cbbf27305bcd1f3e3bf", "schema_version": 1, "timestamp": "2026-10-05T06:49:25.982763+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_823b863ba95e", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:0e0437583b13151bc9d7d2111f4c0f2864628f39be74dd7caec944a8b624d5f5", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.233858+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_05727dd6d5d0", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:58ce685891cd29183b5b8e0ca04dec709875af25c10e3b85051c57b5191dd3bb", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.294590+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8653cc51cc05", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cf3ffb7ab858d9f36b7c1ab844bc45d2ebf37f7f7bfe555d969e075768263ea6", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.306518+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a9476432804f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:58a30329240ce81770b8a10c622c8bcd71720a7da82b26026810fcd24c9fce0d", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.317130+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4e72295c0863", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:212e3d41acb92d8340b54ec7e8675e323d271186c5410f85e98ec735c0c084eb", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.328129+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_24d9e8304b51", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6732117c84ca98c75a9387b680686e2b1d26b0a34e578acb1fb02dd740d6ed24", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.339686+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1b139c924879", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:5740ecb8233bad3aeb7accc88a54ee70433890e870d02df8f44a2934f58224af", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.351188+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b96631537a0b", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dada98dc7ebcd4d84ae8246af43b0407dea10ebc39d5893f2ccfc1c90e38713e", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.362439+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_defa76132b52", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:fa53369f86a76f7463ab370b0b5b2424931c989ae67d535cbd8139b577817080", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.373635+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dce056c4654f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6f4f043f369aa4b7a132bf2a86bd55a5a81acf9da05ab5531a2ca77407a75b8f", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.385204+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_95647e276440", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e7243dbf9eff44b1151db1fb181715e1b93b20bc8f562e13c8c1081749cba7e2", "schema_version": 1, "timestamp": "2026-10-05T06:49:26.395446+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_f7b30bc3b1e5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:88d01292c9bad0119b8e2d8a6dbec58608ecc6f8c925b436a71dd14eaab8471e", "schema_version": 1, "timestamp": "2026-10-05T06:49:29.609938+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_474f2c1edc09", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d192428e3aecb673052aab395d3ca46be3801a1993d0ebf4b094d344e5ffa3f1", "schema_version": 1, "timestamp": "2026-10-05T06:49:32.470488+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_be4af370222d", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:4caa0125a7cb3a765e4d62ff63ccdc9b1b90bf20d3dfa06aaa3a6b0bf81aa5e8", "schema_version": 1, "timestamp": "2026-10-05T06:49:32.486146+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_370b041b77ab", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:425cf4b663feaa86ec3eafbc5f9c3b470f66bda5755fccefb7f938df7a2ebe88", "schema_version": 1, "timestamp": "2026-10-05T06:49:32.603529+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_42d925780dc9", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d57edb40af6e1524930b00b827334964c943611065da72e721641734058b034d", "schema_version": 1, "timestamp": "2026-10-05T06:49:32.612424+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_dcf2bfba3de8", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:513838c7094c81b393c8a4a03e366771d67e175614f7a29f334db873beae1e67", "schema_version": 1, "timestamp": "2026-10-05T06:49:32.856639+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1e86c7d72b5f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d9db13756a0360e79effdd1184f6e5d71d12007626bc7e52f39b63c9d12e1703", "schema_version": 1, "timestamp": "2026-10-05T06:49:32.869109+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fc987750a85c", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9eb31157caf97d9bc60d6bb1debd9fef14fa1d2b413a3d3b0ca3e9ebfdf61103", "schema_version": 1, "timestamp": "2026-10-05T06:49:32.878491+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_9a0d5dd3e4dd", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:40f062e606db546ad97849b26795a7ef584e425976194ccb50cd29e8fd4a68fe", "schema_version": 1, "timestamp": "2026-10-05T06:49:42.210225+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2275190d1a87", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d6b66be9ef64cb7db64352b83bdeb700678bae13b3af22a073c891e5d92ccde6", "schema_version": 1, "timestamp": "2026-10-05T06:49:42.233289+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_00d83ffffe21", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:f0ddcbb1a01fa25070f5ce32b15f931f17bf0ba500a8893f05439190c8043709", "schema_version": 1, "timestamp": "2026-10-05T06:49:42.254779+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_b104b6056128", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:11a7f153199214499dfd4fc9a0b08d1f2f531ce3485b907cfe3a036cf7edc586", "schema_version": 1, "timestamp": "2026-10-05T06:49:42.295428+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_fcd97d359359", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:d5c968d2dbed3174298be875d798719fcdc31e803c8b5a6306d782b4a43afc6f", "schema_version": 1, "timestamp": "2026-10-05T06:49:42.358476+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ff066fda80d1", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:6bf69da741e431dd7f5de2630995da45ddd2c6224207891b5216e012e6998b64", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.441629+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_612ec40fd1e4", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:dd824cf3610914529537ec8783611e0b088fd6bb3dc81d1f61fa526a9ceb7f86", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.464657+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_101f64fae77e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a18ecdd4265a25eb2eb084e169383bc3ef71f3273bd44ad3ec54d635915db231", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.472844+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_304a54818690", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:c3102db0415d7dae5fc7d8251769218c2e5cc0dcf9158e44dbb82aa797c092d3", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.485450+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_724c04075b5b", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3358d01648173c908fe588f9f6371aaff50566def884c5a32835ff88d9a072c5", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.494459+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_08ffb53d40ac", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:252e9e3eb1869872446a4691f96894f1560e5460d0015c6ef0fcb578000e98c8", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.505009+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c186460e40e8", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8bacf3cbaf2335d6ad20db86c810606218ada500ed3fecdd5b86987d3ff313d2", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.513057+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_798fc60a306a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:3c6749386d0df979712cd68ebb324fc78d0f3d7bd86bdc0cddf76c3bae5be422", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.669471+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0d63b261b89e", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e0e46228fd7371c5839f6582d703864f38a248c32aae963f7c16b56f7148c2c2", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.679589+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8cf8e16e313d", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e77f935ddd1cd9b4c03f1270d0758872ae85cc651cfd250c30f28ae22bebcb6a", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.693813+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_65de385bb705", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8116052b643376b05f7736fa3917f20d14c3d2e16f012b1fa96a898bf855d1e3", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.715309+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0085ddd9525d", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.730640+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_8cb5a0d833b0", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.743731+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_12401de106d2", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.833693+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_2f90d0903bde", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.846441+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_72b31d339b70", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:bdddec01c5c7f8ce5e8aa1a0210c5d5e6361a13ba43d85cab6953df4edac762d", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.854918+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d870d5ac1848", "event_type": "capability.failed", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:1163d0fcebec85439e62d33ef5e1f3de09c6e1a75e16c7ecdb1a887be368d19d", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.919058+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e6541eb2f23e", "event_type": "storage.degraded", "parent_id": null, "partition_key": "subsystem_health", "payload_hash": "sha256:dc4a0ef045512b494194a21ba9206ec66e21ae710f7c2caa29f194c48fb142c0", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.931415+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_d41b8338f344", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:08d9854e6c841592dc3d7d74c34cd5cfaac46346de24deb336998cae58e43ba2", "schema_version": 1, "timestamp": "2026-10-05T06:49:45.939780+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_06a466be85a5", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:7a08f9f4efd518ebc0939db20ad60098a7993c1a7f085417c44cbfd5106c497a", "schema_version": 1, "timestamp": "2026-10-05T06:51:29.235743+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_01b97fe1a24a", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:cc87d40d66cb48c079f46b873f06aceb4e1108394badc1642822b163d339c59b", "schema_version": 1, "timestamp": "2026-10-05T06:51:29.254737+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_a6f7d9215858", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:833f0de0971a926b6a86b3c6180111c20fdd85460fbb8c98794f58d6ba86055e", "schema_version": 1, "timestamp": "2026-10-05T06:51:29.266271+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_0ff7f5b318ae", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:d3dd9469bc1c37051ef12cf958c1e665592da50f5fb83ca4e4805d240bc0eb5f", "schema_version": 1, "timestamp": "2026-10-05T06:51:29.277599+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_c78064dbb798", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:8fc75079f8fc265ad0e025b881398e1eda5a88395da3994c5b324e88a711ac4e", "schema_version": 1, "timestamp": "2026-10-05T06:51:29.292026+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_e229bf1c4304", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:26e42b5839f558d320f3a0abcdf24d07c20acda3067a60d7409156a01099596b", "schema_version": 1, "timestamp": "2026-10-05T06:51:31.998143+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_cb05371075d3", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:a04d2289fdebfe4f5051756eb028d0c7d00602703db3c528523ee393532c371d", "schema_version": 1, "timestamp": "2026-10-05T06:51:32.010290+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_195bd254ca92", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:e227b022e02cf5954515ce26a6b909a1ae22988df63d1ce374938c3ec95116cc", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.721149+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_3557f32af820", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:ad4749548773eed30b11fbca6a45d397b6f62f3f73fbfe713bb752c3a39e662e", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.735979+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_ae42b48f5c4f", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:aec5941e0be4f363a5d7ab0bf215c26f61c7c6ed63ad3fd335b88b7c06b5d5ba", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.846536+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_1a5dfcdba732", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:2c8835ea9e171751c593b4cf87e8ffc1e70f49d763e6c932fc3a71b1131eab3e", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.855682+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_4c212c766420", "event_type": "task.outcome", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:816ee2ac1945082edb3e0cdc512856f4edcef61a860330f1aff91a70b896774f", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.917103+00:00"}
|
||||
{"actor_id": "", "authorization": "", "device_id": "", "event_id": "evt_98a1c9d79a80", "event_type": "task.failed", "parent_id": null, "partition_key": "rune_operator", "payload_hash": "sha256:9c5bfcbe3d47d3783802c2dc21af1c34137bfca61aa7bd58266286ef74d41d86", "schema_version": 1, "timestamp": "2026-10-05T06:51:33.925785+00:00"}
|
||||
@@ -218,6 +218,35 @@ critiques (2026-10-04):
|
||||
or honestly flagged, never silent.
|
||||
- Deploy qualification per merge (the pipeline that proved itself today).
|
||||
|
||||
### The 90/100 coverage law (Nick, 2026-10-05 — GOVERNING from W3.4 on)
|
||||
|
||||
Per Nick: "if it's realistically achievable but aim higher also if that's
|
||||
realistically achievable. go to 100% where achievable."
|
||||
|
||||
- **100% where achievable — the deterministic Rust kernels.** Every kernel
|
||||
crate (memory_retrieval, cognition_core, scaffold_core, memory_storage,
|
||||
and every future crate) targets 100% BRANCH coverage via its parity
|
||||
matrices + the pytest shim battery: every branch has real reachable
|
||||
semantics, and exhaustive enumeration is exactly what the batteries do.
|
||||
Achievability is measured per crate at wave close; a kernel below 100%
|
||||
carries the named unreachable case or it isn't done.
|
||||
- **≥90% on the changed-lines bar (diff-cover), aiming higher.** The floor
|
||||
stays a floor; the working standard per slice is 90%+ on changed lines;
|
||||
whatever a slice achieves beyond 90 becomes the next slice's personal
|
||||
benchmark (per-unit "aim higher" — the number climbs wave over wave).
|
||||
The floor ratchet itself moves after consecutive clean waves
|
||||
(70 → 76 → 84 → 90; each raise is a commit, never a step down).
|
||||
- **Glue/failure branches: 90%+ with byte-compare proofs.** The stubs and
|
||||
probe branches that only fire in a broken world are covered by honest
|
||||
fixtures (real import-failure probes like the from-import resolution
|
||||
law) — never by fake-triggered pragmas. A branch covered by a lying
|
||||
fixture is WORSE than uncovered; if it can't be honestly reached, it's
|
||||
named in the wave's closure report with the reason.
|
||||
- **Assertion quality is part of the bar.** A test that touches a line
|
||||
without verifying its OUTPUT doesn't count toward the bar — byte-compare
|
||||
/ exact-value asserts are the standard; "is not None" assertions reject
|
||||
at review.
|
||||
|
||||
## 7. Risk register
|
||||
|
||||
- **SQLite FFI correctness** (Wave 2) — the storage layer is retained but
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rune"
|
||||
version = "0.91.0"
|
||||
version = "0.95.1"
|
||||
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ const usage = `rune — Go first-call entry (Phase H1 transitional shim)
|
||||
usage:
|
||||
rune [args...] hand off to the Python runtime (deployed revision)
|
||||
rune serve H2 front door: /v1 surface proxying the Python core
|
||||
rune scaffold R2 construction protocol initiation (Go start / Rust core)
|
||||
rune --version print the runtime version
|
||||
rune --python-only print the resolved Python handoff command and exit
|
||||
rune --help this text
|
||||
@@ -128,6 +129,10 @@ func main() {
|
||||
if len(args) > 0 && args[0] == "serve" {
|
||||
os.Exit(runServe(args[1:]))
|
||||
}
|
||||
// R2 Wave 1: the scaffolding initiation surface (Go starts, Rust executes).
|
||||
if len(args) > 0 && args[0] == "scaffold" {
|
||||
os.Exit(runScaffold(args[1:]))
|
||||
}
|
||||
srcDir := deployedSrc()
|
||||
for _, a := range args {
|
||||
switch a {
|
||||
|
||||
@@ -161,3 +161,51 @@ func TestFrontDoorProxiesByteForByte(t *testing.T) {
|
||||
t.Fatalf("proxy must pass the body byte-for-byte, got %q", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// ── R2 Wave 1: scaffold initiation surface ──────────────────────────────────
|
||||
|
||||
func TestScaffoldHelpExitsZero(t *testing.T) {
|
||||
if rc := runScaffold([]string{"--help"}); rc != 0 {
|
||||
t.Fatalf("scaffold --help must exit 0, got %d", rc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaffoldUnknownFlagExitsTwo(t *testing.T) {
|
||||
if rc := runScaffold([]string{"--bogus"}); rc != 2 {
|
||||
t.Fatalf("unknown scaffold flag must exit 2, got %d", rc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaffoldCoreCallEnvelope(t *testing.T) {
|
||||
// The membrane junction with a stub binary emitting a canned envelope.
|
||||
dir := t.TempDir()
|
||||
stub := filepath.Join(dir, "scaffold_core")
|
||||
script := "#!/bin/sh\ncat >/dev/null\nprintf '%s\n' '{\"ok\":true,\"value\":{\"legal\":true}}'\n"
|
||||
if err := os.WriteFile(stub, []byte(script), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
env, err := scaffoldCoreCall(stub, "check_transition",
|
||||
map[string]string{"current": "draft", "target": "approved"})
|
||||
if err != nil {
|
||||
t.Fatalf("stub junction failed: %v", err)
|
||||
}
|
||||
if env["ok"] != true {
|
||||
t.Fatalf("envelope ok must be true, got %v", env)
|
||||
}
|
||||
value, _ := env["value"].(map[string]any)
|
||||
if value["legal"] != true {
|
||||
t.Fatalf("value.legal must be true, got %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaffoldCoreCallFailureSurfaces(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
stub := filepath.Join(dir, "scaffold_core")
|
||||
script := "#!/bin/sh\nexit 3\n"
|
||||
if err := os.WriteFile(stub, []byte(script), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := scaffoldCoreCall(stub, "check_transition", map[string]string{}); err == nil {
|
||||
t.Fatal("a failing core binary must surface an error, not a zero value")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
// scaffold.go — the scaffolding initiation surface (R2 Wave 1, contract
|
||||
// BUILDER-2026-10-04T15:25:33Z-cli). Go STARTS, Rust EXECUTES: pure
|
||||
// operations (check-transition, close-quality) go straight to the
|
||||
// scaffold_core binary over stdio NDJSON (the hybrid membrane's first
|
||||
// contracted junction); store-backed operations proxy to the Python engine
|
||||
// (whose own core is now Rust-delegated) until Wave 1's later slices port
|
||||
// the contract store.
|
||||
//
|
||||
// Stdlib only. The binary path resolves from SC_RUST_BIN, else the repo
|
||||
// crate target, else PATH.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const scaffoldUsage = `rune scaffold — the construction protocol initiation surface (R2 Wave 1)
|
||||
|
||||
usage:
|
||||
rune scaffold check-transition <current> <target> legality verdict (Rust core, direct)
|
||||
rune scaffold close-quality <inputs.json> closure buckets (Rust core, direct)
|
||||
rune scaffold <op> [args...] store-backed ops proxy to the engine:
|
||||
submit-need, inspect-decision, scope,
|
||||
obligations, observe, verify, transition, close
|
||||
|
||||
Go initiates; Rust executes the deterministic core; the Python engine
|
||||
carries store-backed operations during the transition (strangler law).
|
||||
`
|
||||
|
||||
// scaffoldCoreBin resolves the scaffold_core CLI binary.
|
||||
func scaffoldCoreBin() string {
|
||||
if p := os.Getenv("SC_RUST_BIN"); p != "" {
|
||||
return p
|
||||
}
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
dir := filepath.Dir(exe)
|
||||
for i := 0; i < 8; i++ {
|
||||
cand := filepath.Join(dir, "src", "rust", "scaffold_core", "target", "release", "scaffold_core")
|
||||
if st, err := os.Stat(cand); err == nil && !st.IsDir() {
|
||||
return cand
|
||||
}
|
||||
dir = filepath.Dir(dir)
|
||||
}
|
||||
}
|
||||
if p, err := exec.LookPath("scaffold_core"); err == nil {
|
||||
return p
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// scaffoldCoreCall runs one pure op through the Rust binary (NDJSON stdin
|
||||
// -> envelope stdout). The envelope contract is the doc-envelope law.
|
||||
func scaffoldCoreCall(bin, op string, arg any) (map[string]any, error) {
|
||||
payload, err := json.Marshal(map[string]any{"op": op, "arg": arg})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd := exec.Command(bin)
|
||||
cmd.Stdin = bytes.NewReader(payload)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, fmt.Errorf("scaffold_core %s failed: %w", op, err)
|
||||
}
|
||||
var env map[string]any
|
||||
if err := json.Unmarshal(out.Bytes(), &env); err != nil {
|
||||
return nil, fmt.Errorf("scaffold_core %s returned non-JSON: %w", op, err)
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
// scaffoldProxy hands a store-backed op to the Python engine (the
|
||||
// transitional membrane — the engine's core is Rust-backed already).
|
||||
func scaffoldProxy(args []string) int {
|
||||
py := pythonBin()
|
||||
argv := append([]string{py, "-m", "rune.construction_interface"}, args...)
|
||||
cmd := exec.Command(argv[0], argv[1:]...)
|
||||
cmd.Dir = deployedSrc()
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
env := launchEnv(os.Environ())
|
||||
cmd.Env = env
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "rune scaffold: engine call failed: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// runScaffold implements `rune scaffold`. Returns the process exit code.
|
||||
func runScaffold(args []string) int {
|
||||
if len(args) == 0 || args[0] == "--help" || args[0] == "-h" {
|
||||
fmt.Print(scaffoldUsage)
|
||||
return 0
|
||||
}
|
||||
switch args[0] {
|
||||
case "check-transition":
|
||||
if len(args) != 3 {
|
||||
fmt.Fprintln(os.Stderr, "usage: rune scaffold check-transition <current> <target>")
|
||||
return 2
|
||||
}
|
||||
bin := scaffoldCoreBin()
|
||||
if bin == "" {
|
||||
fmt.Fprintln(os.Stderr, "rune scaffold: scaffold_core binary not found (build the crate)")
|
||||
return 127
|
||||
}
|
||||
env, err := scaffoldCoreCall(bin, "check_transition",
|
||||
map[string]string{"current": args[1], "target": args[2]})
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "rune scaffold:", err)
|
||||
return 1
|
||||
}
|
||||
out, _ := json.Marshal(env)
|
||||
fmt.Println(string(out))
|
||||
return 0
|
||||
case "close-quality":
|
||||
if len(args) != 2 {
|
||||
fmt.Fprintln(os.Stderr, "usage: rune scaffold close-quality <inputs.json>")
|
||||
return 2
|
||||
}
|
||||
raw, err := os.ReadFile(args[1])
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "rune scaffold: cannot read inputs:", err)
|
||||
return 2
|
||||
}
|
||||
var inputs any
|
||||
if err := json.Unmarshal(raw, &inputs); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "rune scaffold: inputs are not JSON:", err)
|
||||
return 2
|
||||
}
|
||||
bin := scaffoldCoreBin()
|
||||
if bin == "" {
|
||||
fmt.Fprintln(os.Stderr, "rune scaffold: scaffold_core binary not found (build the crate)")
|
||||
return 127
|
||||
}
|
||||
env, err := scaffoldCoreCall(bin, "close_quality", inputs)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "rune scaffold:", err)
|
||||
return 1
|
||||
}
|
||||
out, _ := json.Marshal(env)
|
||||
fmt.Println(string(out))
|
||||
return 0
|
||||
default:
|
||||
if strings.HasPrefix(args[0], "-") {
|
||||
fmt.Fprintf(os.Stderr, "rune scaffold: unknown flag %q\n\n%s", args[0], scaffoldUsage)
|
||||
return 2
|
||||
}
|
||||
return scaffoldProxy(args)
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
__version__ = "0.91.0"
|
||||
__version__ = "0.95.1"
|
||||
|
||||
# One build identity (handoff 2026-09-10 §4): the semantic version above is
|
||||
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
|
||||
|
||||
@@ -231,7 +231,7 @@ def main() -> int:
|
||||
)
|
||||
check(
|
||||
"Rune minor version advertises provisioning and restore verification",
|
||||
'__version__ = "0.91.0"' in rune_version,
|
||||
'__version__ = "0.95.1"' in rune_version,
|
||||
failures,
|
||||
)
|
||||
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ctypes loader for the Rust cognition_core (R2 W3.1).
|
||||
|
||||
Contract BUILDER-2026-10-05T07:19:27Z-cli. Pure deterministic kernels;
|
||||
the env gate arrives as a string input (no-clock law, no env access in
|
||||
Rust). Override with CC_RUST_LIB (a FILE path).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
_REPO = Path(__file__).resolve().parents[2]
|
||||
_CRATE_DIR = _REPO / "src" / "rust" / "cognition_core"
|
||||
_LIB_PATH = Path(
|
||||
os.environ.get("CC_RUST_LIB", _CRATE_DIR / "target" / "release" / "libcognition_core.so"))
|
||||
|
||||
_lib = None
|
||||
|
||||
|
||||
def available() -> bool:
|
||||
return _LIB_PATH.is_file()
|
||||
|
||||
|
||||
def _load() -> ctypes.CDLL:
|
||||
global _lib
|
||||
if _lib is not None:
|
||||
return _lib
|
||||
if not _LIB_PATH.exists():
|
||||
raise FileNotFoundError(f"cognition_core not built: {_LIB_PATH}")
|
||||
lib = ctypes.CDLL(str(_LIB_PATH))
|
||||
lib.cc_free_string.argtypes = [ctypes.c_void_p]
|
||||
lib.cc_free_string.restype = None
|
||||
for sym in ("cc_default_estimator", "cc_default_budget",
|
||||
"cc_default_memory_budget", "cc_memory_disabled",
|
||||
"cc_persona_lex", "cc_persona_overlap", "cc_persona_decide",
|
||||
"cc_drift_check", "cc_identity_prompt", "cc_growth_near_dup",
|
||||
"cc_growth_profile", "cc_pins_recall"):
|
||||
fn = getattr(lib, sym)
|
||||
fn.argtypes = [ctypes.c_char_p]
|
||||
fn.restype = ctypes.c_void_p
|
||||
_lib = lib
|
||||
return lib
|
||||
|
||||
|
||||
def _call(sym: str, payload: dict):
|
||||
lib = _load()
|
||||
ptr = getattr(lib, sym)(json.dumps(payload).encode("utf-8"))
|
||||
if not ptr:
|
||||
raise RuntimeError(f"{sym} returned null")
|
||||
try:
|
||||
text = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
|
||||
finally:
|
||||
lib.cc_free_string(ptr)
|
||||
env = json.loads(text)
|
||||
if not env.get("ok"):
|
||||
raise RuntimeError(f"{sym} core error: {env.get('err')}")
|
||||
return env["value"]
|
||||
|
||||
|
||||
def default_estimator(text: str) -> int:
|
||||
return int(_call("cc_default_estimator", {"text": text}))
|
||||
|
||||
|
||||
def default_budget(window: int) -> int:
|
||||
return int(_call("cc_default_budget", {"window": window}))
|
||||
|
||||
|
||||
def default_memory_budget(window) -> int:
|
||||
return int(_call("cc_default_memory_budget", {"window": window}))
|
||||
|
||||
|
||||
def memory_disabled() -> bool:
|
||||
import os
|
||||
return bool(_call("cc_memory_disabled",
|
||||
{"value": os.environ.get("RUNE_MEMORY_OFF")}))
|
||||
def persona_lex(text) -> list:
|
||||
return _call("cc_persona_lex", {"text": text})
|
||||
|
||||
|
||||
def persona_overlap(a: list, b: list) -> float:
|
||||
return float(_call("cc_persona_overlap", {"a": a, "b": b}))
|
||||
|
||||
|
||||
def persona_decide(text: str, rules: list, permissive: bool,
|
||||
sem_scores: list | None = None) -> dict:
|
||||
return _call("cc_persona_decide", {
|
||||
"text": text, "rules": rules, "permissive": permissive,
|
||||
"sem_scores": sem_scores})
|
||||
|
||||
|
||||
|
||||
def drift_check(text: str, patterns: list) -> list:
|
||||
return _call("cc_drift_check", {"text": text, "patterns": patterns})
|
||||
|
||||
|
||||
def identity_prompt(pronouns: dict, self_awareness: dict, anchors: dict,
|
||||
embodiment: list) -> str:
|
||||
return _call("cc_identity_prompt", {
|
||||
"pronouns": pronouns, "self_awareness": self_awareness,
|
||||
"anchors": anchors, "embodiment": embodiment})
|
||||
|
||||
|
||||
def growth_near_dup(a: str, b: str) -> bool:
|
||||
return bool(_call("cc_growth_near_dup", {"a": a, "b": b}))
|
||||
|
||||
|
||||
def growth_profile(state: dict, order: list, entry_chars: int,
|
||||
max_tokens: int) -> list:
|
||||
return _call("cc_growth_profile", {
|
||||
"state": state, "order": order, "entry_chars": entry_chars,
|
||||
"max_tokens": max_tokens})
|
||||
|
||||
|
||||
def pins_recall(pins: list, term: str, limit: int = 4) -> list:
|
||||
return _call("cc_pins_recall", {"pins": pins, "term": term, "limit": limit})
|
||||
@@ -135,6 +135,65 @@ _SURFACE_CONFIG = "config:"
|
||||
_SURFACE_WORKFLOW = "workflow:"
|
||||
|
||||
|
||||
def language_placement(project: str, characteristics: list[str]) -> dict:
|
||||
"""The protocol's language-placement verdict (R2 Wave 1, Nick's addition):
|
||||
rune units get the Go/Rust dichotomy rule; other projects get a
|
||||
characteristic-based fit assessment. Deterministic, evidence-labeled,
|
||||
never silent. Delegates to the Rust scaffold_core when built
|
||||
(Python fallback below — strangler law)."""
|
||||
core = _sc_core()
|
||||
if core is not None:
|
||||
return core.language_placement(project, characteristics)
|
||||
return _py_language_placement(project, characteristics)
|
||||
|
||||
|
||||
def _sc_core():
|
||||
"""The Rust scaffold_core when available (R2 Wave 1 strangler).
|
||||
RUNE_SCAFFOLD_CORE=python pins the fallback."""
|
||||
import os
|
||||
if os.environ.get("RUNE_SCAFFOLD_CORE", "auto") == "python":
|
||||
return None
|
||||
try:
|
||||
from rune import sc_loader
|
||||
except Exception: # noqa: BLE001 — any loader failure means fallback, never a broken call
|
||||
return None
|
||||
try:
|
||||
return sc_loader if sc_loader.available() else None
|
||||
except Exception: # noqa: BLE001 — availability probe must never crash the fallback
|
||||
return None
|
||||
|
||||
|
||||
def _py_language_placement(project: str, characteristics: list[str]) -> dict:
|
||||
"""Python core of language_placement (parity oracle)."""
|
||||
go_signals = ("network", "http", "socket", "server", "dispatch",
|
||||
"reactive", "user-facing", "turn-time")
|
||||
rust_signals = ("deterministic", "stateful", "storage", "cognition",
|
||||
"memory", "compute", "parity", "ledger")
|
||||
chars = [c.lower() for c in characteristics]
|
||||
go_hits = [s for s in go_signals if any(s in c for c in chars)]
|
||||
rust_hits = [s for s in rust_signals if any(s in c for c in chars)]
|
||||
if project.lower() == "rune":
|
||||
if go_hits and not rust_hits:
|
||||
placement, rule = "go", "rune dichotomy: reactive/initiating markers"
|
||||
elif rust_hits and not go_hits:
|
||||
placement, rule = "rust", "rune dichotomy: deterministic/state markers"
|
||||
elif rust_hits and go_hits:
|
||||
placement, rule = "hybrid", "rune dichotomy: both marker classes — a contracted membrane junction"
|
||||
else:
|
||||
placement, rule = "rust", "rune dichotomy: pure compute defaults to the deterministic backend"
|
||||
else:
|
||||
if go_hits and not rust_hits:
|
||||
placement, rule = "go", "characteristic fit: reactive/network profile"
|
||||
elif rust_hits and not go_hits:
|
||||
placement, rule = "rust", "characteristic fit: deterministic/state profile"
|
||||
elif rust_hits:
|
||||
placement, rule = "hybrid", "characteristic fit: mixed profile — split at the membrane"
|
||||
else:
|
||||
placement, rule = "unassessed", "no placement signals — the unit needs characteristics recorded"
|
||||
return {"placement": placement, "rule": rule,
|
||||
"evidence": {"go_signals": go_hits, "rust_signals": rust_hits}}
|
||||
|
||||
|
||||
def classify_surface(surface: str) -> str:
|
||||
"""Classify one affected-surface entry (open-world; Tranche 5 §3).
|
||||
Kinds: structural_entity | source_path | workflow_config | ui_component |
|
||||
|
||||
@@ -100,19 +100,52 @@ class ContributionBlock:
|
||||
def default_estimator(text: str) -> int:
|
||||
"""Deterministic conservative token estimate: len(text) // 4.
|
||||
|
||||
Bytes/4 over-counts for English prose (the conservative direction).
|
||||
tiktoken would be tighter but is NOT deterministic across builds and
|
||||
is not a dependency — the plan allows either, installer's choice.
|
||||
R2 W3.1: delegates to the Rust cognition_core when built (Python
|
||||
fallback — strangler law; RUNE_COGNITION_CORE=python pins it).
|
||||
"""
|
||||
core = _cc_core()
|
||||
if core is not None:
|
||||
return core.default_estimator(text or "")
|
||||
return _py_default_estimator(text)
|
||||
|
||||
|
||||
def _py_default_estimator(text: str) -> int:
|
||||
"""Python oracle (parity floor)."""
|
||||
return len(text or "") // 4
|
||||
|
||||
|
||||
def _cc_core():
|
||||
"""Rust cognition_core when available; RUNE_COGNITION_CORE=python
|
||||
pins the Python fallback (strangler law)."""
|
||||
import os
|
||||
if os.environ.get("RUNE_COGNITION_CORE", "auto") == "python":
|
||||
return None
|
||||
try:
|
||||
from rune import cc_loader
|
||||
except Exception: # noqa: BLE001 — loader probe failure means fallback
|
||||
return None
|
||||
try:
|
||||
return cc_loader if cc_loader.available() else None
|
||||
except Exception: # noqa: BLE001 — availability probe never crashes
|
||||
return None
|
||||
|
||||
|
||||
def default_budget(window: int) -> int:
|
||||
"""Input budget = window - max(2048, window//4) - window//20.
|
||||
|
||||
Reserves room for the completion (at least 2048 or a quarter of the
|
||||
window) plus a 5% safety margin for serving overhead.
|
||||
|
||||
R2 W3.1: delegates to the Rust kernel when built.
|
||||
"""
|
||||
core = _cc_core()
|
||||
if core is not None:
|
||||
return core.default_budget(window)
|
||||
return _py_default_budget(window)
|
||||
|
||||
|
||||
def _py_default_budget(window: int) -> int:
|
||||
"""Python oracle (parity floor)."""
|
||||
return max(1, window - max(2048, window // 4) - window // 20)
|
||||
|
||||
|
||||
@@ -127,7 +160,17 @@ def default_memory_budget(window: int | None) -> int:
|
||||
ContextBroker owns the FINAL memory budget: the sum of every
|
||||
MEMORY_BLOCK_NAMES block may never exceed this, regardless of the
|
||||
global input budget. An unknown window falls back to the cap only.
|
||||
|
||||
R2 W3.1: delegates to the Rust kernel when built.
|
||||
"""
|
||||
core = _cc_core()
|
||||
if core is not None:
|
||||
return core.default_memory_budget(int(window) if window else 0)
|
||||
return _py_default_memory_budget(window)
|
||||
|
||||
|
||||
def _py_default_memory_budget(window: int | None) -> int:
|
||||
"""Python oracle (parity floor)."""
|
||||
if not window or window <= 0:
|
||||
return MEMORY_BUDGET_CAP
|
||||
return min(MEMORY_BUDGET_CAP, int(window) // 8)
|
||||
@@ -140,6 +183,18 @@ def memory_disabled() -> bool:
|
||||
contribute nothing at all — the trace proves 0 memory tokens.
|
||||
"""
|
||||
value = os.environ.get("RUNE_MEMORY_OFF", "").strip().lower()
|
||||
gate = _py_memory_disabled_value(value)
|
||||
core = _cc_core()
|
||||
if core is not None and gate:
|
||||
# the Rust core gets the RAW value (it trims/lowers itself) and
|
||||
# the Python gate cross-checks — a disagreement is impossible on
|
||||
# parity-proven kernels, and the Python verdict remains authority
|
||||
return bool(core.memory_disabled()) and gate
|
||||
return gate
|
||||
|
||||
|
||||
def _py_memory_disabled_value(value: str) -> bool:
|
||||
"""Python oracle (parity floor) over the RAW string."""
|
||||
return value not in {"", "0", "false", "no", "off"}
|
||||
|
||||
|
||||
|
||||
@@ -150,8 +150,35 @@ def _profile_key(delta):
|
||||
return {w.strip(".,;:!?()[]{}\"'").lower() for w in (delta.get("change") or "").split() if len(w) > 4}
|
||||
|
||||
|
||||
def _cc_core():
|
||||
"""Rust cognition_core when available (growth kernels)."""
|
||||
import os
|
||||
if os.environ.get("RUNE_COGNITION_CORE", "auto") == "python":
|
||||
return None
|
||||
try:
|
||||
from rune import cc_loader
|
||||
except Exception: # noqa: BLE001 — loader probe failure means fallback
|
||||
return None
|
||||
try:
|
||||
return cc_loader if cc_loader.available() else None
|
||||
except Exception: # noqa: BLE001 — availability probe never crashes
|
||||
return None
|
||||
|
||||
|
||||
def _near_dup(a, b):
|
||||
"""Are two deltas the same guidance (shared distinctive words)?"""
|
||||
core = _cc_core()
|
||||
if core is not None:
|
||||
return core.growth_near_dup(a, b)
|
||||
return _py_near_dup(a, b)
|
||||
|
||||
|
||||
def _py_near_dup(a, b):
|
||||
"""Are two deltas the same guidance (shared distinctive words)?
|
||||
Accepts delta dicts OR raw change strings (raw -> wrapped)."""
|
||||
if isinstance(a, str):
|
||||
a = {"change": a}
|
||||
if isinstance(b, str):
|
||||
b = {"change": b}
|
||||
ka, kb = _profile_key(a), _profile_key(b)
|
||||
if not ka or not kb:
|
||||
return False
|
||||
@@ -177,6 +204,16 @@ def _apply_profile(delta):
|
||||
|
||||
|
||||
def growth_profile(max_tokens=PROFILE_BUDGET_TOKENS):
|
||||
core = _cc_core()
|
||||
if core is not None:
|
||||
return core.growth_profile(_load_deltas(),
|
||||
sorted(_PROFILE_ORDER.items(),
|
||||
key=lambda kv: kv[1]),
|
||||
PROFILE_ENTRY_CHARS, max_tokens)
|
||||
return _py_growth_profile(max_tokens)
|
||||
|
||||
|
||||
def _py_growth_profile(max_tokens=PROFILE_BUDGET_TOKENS):
|
||||
"""The active growth profile: the persona's CURRENT behavioural guidance,
|
||||
consolidated by target, capped at a fixed token budget. Session-independent
|
||||
and token-stable — the per-turn cost never grows with session length."""
|
||||
|
||||
@@ -254,18 +254,8 @@ def check_genuineness(text):
|
||||
return issues
|
||||
|
||||
|
||||
def check_drift(text):
|
||||
"""Check text against identity anchors for drift signals.
|
||||
|
||||
This is a simple heuristic check — the real drift detection happens
|
||||
via the Nautilus Compass approach (embedding similarity against anchors).
|
||||
This function provides quick pattern-based checks.
|
||||
"""
|
||||
text_lower = text.lower()
|
||||
issues = []
|
||||
|
||||
# Check for identity announcements
|
||||
announcement_patterns = [
|
||||
def _announcement_patterns():
|
||||
return [
|
||||
("i am rune", "Identity announcement — let the voice carry the identity"),
|
||||
("as rune", "Identity announcement — speak as the persona, not about it"),
|
||||
("my persona", "Identity announcement — the persona is how you act, not what you name"),
|
||||
@@ -274,32 +264,26 @@ def check_drift(text):
|
||||
("i'm an ai", "Identity announcement — you are a persona, not a generic AI"),
|
||||
("i'm a language model", "Identity announcement — you are Rune, not a language model"),
|
||||
]
|
||||
for pattern, message in announcement_patterns:
|
||||
if pattern in text_lower:
|
||||
issues.append(f"DRIFT: '{pattern}' — {message}")
|
||||
|
||||
# Check for pronoun confusion
|
||||
pronoun_issues = [
|
||||
|
||||
def _pronoun_patterns():
|
||||
return [
|
||||
("you are rune", "Pronoun confusion — 'you' is Nick, 'I' is Rune"),
|
||||
("we are rune", "Pronoun confusion — Rune is singular, not plural"),
|
||||
("you should remember", "Pronoun confusion — who should remember?"),
|
||||
]
|
||||
for pattern, message in pronoun_issues:
|
||||
if pattern in text_lower:
|
||||
issues.append(f"DRIFT: '{pattern}' — {message}")
|
||||
|
||||
# Check for hedging without evidence
|
||||
hedge_patterns = [
|
||||
|
||||
def _hedge_patterns():
|
||||
return [
|
||||
("i believe", "Hedge without evidence — cite the basis"),
|
||||
("i think that", "Hedge without evidence — cite the basis"),
|
||||
("in my opinion", "Hedge without evidence — cite the basis"),
|
||||
]
|
||||
for pattern, message in hedge_patterns:
|
||||
if pattern in text_lower:
|
||||
issues.append(f"WEAKNESS: '{pattern}' — {message}")
|
||||
|
||||
# Check for sycophancy (excessive agreement, flattery, self-deprecation)
|
||||
sycophancy_patterns = [
|
||||
|
||||
def _sycophancy_patterns():
|
||||
return [
|
||||
# Excessive agreement
|
||||
("you're absolutely right", "Sycophancy — excessive agreement; push back if you see a better path"),
|
||||
("absolutely, ", "Sycophancy — excessive agreement; state your own position"),
|
||||
@@ -326,6 +310,60 @@ def check_drift(text):
|
||||
("i see where you're coming from", "Sycophancy — hedging; state your position instead"),
|
||||
("you make a valid point", "Sycophancy — hedging; engage with the substance"),
|
||||
]
|
||||
|
||||
|
||||
def _pattern_triples():
|
||||
"""The pattern tables as [pattern, message, prefix] triples — the data
|
||||
authority for the Rust drift kernel (kernel matches; data stays here)."""
|
||||
tables = []
|
||||
for prefix, table in (
|
||||
("DRIFT", _announcement_patterns() + _pronoun_patterns()),
|
||||
("WEAKNESS", _hedge_patterns()),
|
||||
("SYCOPHANCY", _sycophancy_patterns()),
|
||||
):
|
||||
for pat, msg in table:
|
||||
tables.append([pat, msg, prefix])
|
||||
return tables
|
||||
|
||||
|
||||
def check_drift(text):
|
||||
"""Check text against identity anchors for drift signals.
|
||||
|
||||
This is a simple heuristic check — the real drift detection happens
|
||||
via the Nautilus Compass approach (embedding similarity against anchors).
|
||||
This function provides quick pattern-based checks.
|
||||
"""
|
||||
core = _cc_core()
|
||||
if core is not None:
|
||||
return core.drift_check(text, _pattern_triples())
|
||||
return _py_check_drift(text)
|
||||
|
||||
|
||||
def _py_check_drift(text):
|
||||
"""Python oracle (parity floor)."""
|
||||
text_lower = text.lower()
|
||||
issues = []
|
||||
|
||||
# Check for identity announcements
|
||||
announcement_patterns = _announcement_patterns()
|
||||
for pattern, message in announcement_patterns:
|
||||
if pattern in text_lower:
|
||||
issues.append(f"DRIFT: '{pattern}' — {message}")
|
||||
|
||||
# Check for pronoun confusion
|
||||
pronoun_issues = _pronoun_patterns()
|
||||
for pattern, message in pronoun_issues:
|
||||
if pattern in text_lower:
|
||||
issues.append(f"DRIFT: '{pattern}' — {message}")
|
||||
|
||||
# Check for hedging without evidence
|
||||
hedge_patterns = _hedge_patterns()
|
||||
for pattern, message in hedge_patterns:
|
||||
if pattern in text_lower:
|
||||
issues.append(f"WEAKNESS: '{pattern}' — {message}")
|
||||
|
||||
# Check for sycophancy (excessive agreement, flattery, self-deprecation)
|
||||
sycophancy_patterns = _sycophancy_patterns()
|
||||
for pattern, message in sycophancy_patterns:
|
||||
if pattern in text_lower:
|
||||
issues.append(f"SYCOPHANCY: '{pattern}' — {message}")
|
||||
@@ -424,13 +462,38 @@ if __name__ == "__main__":
|
||||
# ---------------------------------------------------------------------------
|
||||
# Hook handler — called by the microkernel when an event fires.
|
||||
# ---------------------------------------------------------------------------
|
||||
def _cc_core():
|
||||
"""Rust cognition_core when available (identity kernels)."""
|
||||
import os
|
||||
if os.environ.get("RUNE_COGNITION_CORE", "auto") == "python":
|
||||
return None
|
||||
try:
|
||||
from rune import cc_loader
|
||||
except Exception: # noqa: BLE001 — loader probe failure means fallback
|
||||
return None
|
||||
try:
|
||||
return cc_loader if cc_loader.available() else None
|
||||
except Exception: # noqa: BLE001 — availability probe never crashes
|
||||
return None
|
||||
|
||||
|
||||
def get_identity_prompt() -> str:
|
||||
"""Get identity prompt for injection into model calls.
|
||||
R2 W3.3: assembly delegates to the Rust kernel (data stays here).
|
||||
|
||||
Builds a comprehensive prompt from all identity data:
|
||||
self-awareness, anchors, embodiment rules, and pronoun rules.
|
||||
Pronouns come first — they're the most important rule.
|
||||
"""
|
||||
core = _cc_core()
|
||||
if core is not None:
|
||||
return core.identity_prompt(PRONOUN_RULES, SELF_AWARENESS, ANCHORS,
|
||||
EMBODIMENT_RULES)
|
||||
return _py_get_identity_prompt()
|
||||
|
||||
|
||||
def _py_get_identity_prompt() -> str:
|
||||
"""Python oracle (parity floor)."""
|
||||
parts = []
|
||||
|
||||
# Pronoun rules — critical for disambiguation
|
||||
|
||||
+310
-172
@@ -734,39 +734,14 @@ def recall(
|
||||
# lexical (embeddings absent): RRF degenerates to a rank transform that
|
||||
# destroys the score signal needed for thresholding (Bruch et al.,
|
||||
# arXiv:2210.11934) — use raw BM25 scores directly.
|
||||
ranks = {}
|
||||
best_dense = 0.0
|
||||
# M1 observability (#161 synthesis INV-13): which fusion branch produced
|
||||
# the results. Observability ONLY — consumers must never branch behavior
|
||||
# on this field (that would create a second retrieval authority).
|
||||
retrieval_mode = "lexical-only"
|
||||
if dense and bm25:
|
||||
retrieval_mode = "hybrid"
|
||||
for idx, lst in enumerate([dense, bm25]):
|
||||
for pos, (eid, _score) in enumerate(lst):
|
||||
ranks[eid] = ranks.get(eid, 0.0) + 1.0 / (RRF_K + pos + 1)
|
||||
if idx == 0:
|
||||
best_dense = max(best_dense, _score)
|
||||
elif dense:
|
||||
retrieval_mode = "dense-only"
|
||||
for pos, (eid, _score) in enumerate(dense):
|
||||
ranks[eid] = 1.0 / (RRF_K + pos + 1)
|
||||
best_dense = max(best_dense, _score)
|
||||
elif bm25:
|
||||
# Lexical-only: normalize raw BM25 scores (negative, higher = better)
|
||||
# into a positive scale so the sort + gap abstention below work
|
||||
# uniformly with the RRF scale. BM25 returns negative scores; the
|
||||
# least-negative (closest to 0) is the best match. Offset + invert:
|
||||
# best (=-8) -> 2, worst (=-10) -> 0. Rank order preserved.
|
||||
_min_bm = min((s for _, s in bm25), default=0.0)
|
||||
_max_bm = max((s for _, s in bm25), default=0.0)
|
||||
_span = max(_max_bm - _min_bm, 1e-9)
|
||||
for eid, score in bm25:
|
||||
ranks[eid] = (score - _min_bm) / _span
|
||||
fusion = _rank_fusion(dense, bm25)
|
||||
ranks = dict(fusion["ranks"])
|
||||
best_dense = fusion["best_dense"]
|
||||
retrieval_mode = fusion["mode"]
|
||||
# Fetch full entries + metadata for the fused set. P1-03 (#26): typed
|
||||
# queries filter here — matching types + unclassified (NULL) rows stay
|
||||
# eligible; other types drop out before scoring.
|
||||
scored = []
|
||||
rows_data = []
|
||||
if ranks:
|
||||
ids = list(ranks.keys())
|
||||
placeholders = ",".join("?" * len(ids))
|
||||
@@ -776,124 +751,87 @@ def recall(
|
||||
type_ph = ",".join("?" * len(memory_types))
|
||||
sql += f" AND (memory_type IN ({type_ph}) OR memory_type IS NULL)"
|
||||
params.extend(memory_types)
|
||||
rows = db.execute(sql, params).fetchall()
|
||||
by_id = {r["id"]: r for r in rows}
|
||||
for eid, base in sorted(ranks.items(), key=lambda x: -x[1]):
|
||||
row = by_id.get(eid)
|
||||
if not row:
|
||||
continue
|
||||
# #1 temperature ranking (not deletion): a stale fact ranks lower
|
||||
# but stays in the store. #4 confidence: a hedged/claimed fact
|
||||
# carries its honesty into ranking. Blend into a relevance score.
|
||||
# RECENCY: a fact last accessed recently ranks slightly higher than
|
||||
# an untouched one at equal relevance (the store's last_accessed
|
||||
# field). Decays over RECENCY_HALF_LIFE days — a gentle nudge, not
|
||||
# a rewrite of the relevance ranking.
|
||||
conf = float(row["confidence"] or 0.7)
|
||||
temp = float(row["temperature"] or 1.0)
|
||||
recency = 1.0
|
||||
try:
|
||||
from datetime import datetime, timezone
|
||||
rows_data = [dict(r) for r in db.execute(sql, params).fetchall()]
|
||||
return _score_recall_rows(
|
||||
fusion, rows_data, dense, bm25, budget, min_score, now_iso())
|
||||
|
||||
la = row["last_accessed"]
|
||||
if la:
|
||||
t_last = datetime.fromisoformat(la.replace("Z", "+00:00"))
|
||||
days = (datetime.now(timezone.utc) - t_last).total_seconds() / 86400.0
|
||||
if days >= 0:
|
||||
recency = RECENCY_HALF_LIFE / (RECENCY_HALF_LIFE + days)
|
||||
except Exception:
|
||||
logger.debug("recall failed", exc_info=True)
|
||||
# In lexical-only mode `base` is a raw BM25 score (negative).
|
||||
# Normalize it to a positive relevance for the metadata, keeping
|
||||
# the ranking identical. In hybrid mode `base` is an RRF rank.
|
||||
if dense and bm25:
|
||||
relevance = base * (0.4 + 0.6 * conf) * (0.5 + 0.5 * temp) * (0.85 + 0.15 * recency)
|
||||
elif dense:
|
||||
relevance = base * (0.4 + 0.6 * conf) * (0.5 + 0.5 * temp) * (0.85 + 0.15 * recency)
|
||||
else:
|
||||
relevance = (base + 5.0) * (0.4 + 0.6 * conf) * (0.5 + 0.5 * temp) * (0.85 + 0.15 * recency)
|
||||
scored.append(
|
||||
{
|
||||
"id": eid,
|
||||
"text": row["text"],
|
||||
"importance": row["importance"],
|
||||
"topic": row["topic"],
|
||||
"entities": row["entities"],
|
||||
"source": row["source"],
|
||||
"last_accessed": row["last_accessed"],
|
||||
"rrf": round(base, 4),
|
||||
"confidence": round(conf, 2),
|
||||
"temperature": round(temp, 2),
|
||||
"relevance": round(relevance, 4),
|
||||
# M1 observability (#161): lexical-only | dense-only | hybrid.
|
||||
# NEVER consumed for behavior — see INV-13 in the synthesis.
|
||||
"mode": retrieval_mode,
|
||||
}
|
||||
)
|
||||
# Enforce budget + abstention floor.
|
||||
|
||||
def _score_recall_rows(fusion, rows, dense, bm25, budget, min_score, now):
|
||||
"""Pure metadata scoring + mode-specific abstention kernel (W2.1)."""
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.score_recall_rows(
|
||||
fusion, rows, dense, bm25, budget, min_score, now,
|
||||
RECENCY_HALF_LIFE)
|
||||
return _py_score_recall_rows(
|
||||
fusion, rows, dense, bm25, budget, min_score, now,
|
||||
RECENCY_HALF_LIFE)
|
||||
|
||||
|
||||
def _py_score_recall_rows(fusion, rows, dense, bm25, budget, min_score,
|
||||
now, recency_half_life=RECENCY_HALF_LIFE):
|
||||
"""Python oracle for the Rust scoring/abstention kernel."""
|
||||
from datetime import datetime
|
||||
|
||||
ranks = dict(fusion["ranks"])
|
||||
best_dense = fusion["best_dense"]
|
||||
retrieval_mode = fusion["mode"]
|
||||
by_id = {row["id"]: row for row in rows}
|
||||
scored = []
|
||||
now_dt = datetime.fromisoformat(now)
|
||||
for eid, base in sorted(ranks.items(), key=lambda item: -item[1]):
|
||||
row = by_id.get(eid)
|
||||
if not row:
|
||||
continue
|
||||
conf = float(row.get("confidence") or 0.7)
|
||||
temp = float(row.get("temperature") or 1.0)
|
||||
recency = 1.0
|
||||
try:
|
||||
la = row.get("last_accessed")
|
||||
if la:
|
||||
t_last = datetime.fromisoformat(la.replace("Z", "+00:00"))
|
||||
days = (now_dt - t_last).total_seconds() / 86400.0
|
||||
if days >= 0:
|
||||
recency = recency_half_life / (recency_half_life + days)
|
||||
except Exception:
|
||||
logger.debug("recall score kernel timestamp failed", exc_info=True)
|
||||
if dense:
|
||||
relevance = base * (0.4 + 0.6 * conf) * (0.5 + 0.5 * temp) * (0.85 + 0.15 * recency)
|
||||
else:
|
||||
relevance = (base + 5.0) * (0.4 + 0.6 * conf) * (0.5 + 0.5 * temp) * (0.85 + 0.15 * recency)
|
||||
scored.append({
|
||||
"id": eid, "text": row.get("text"),
|
||||
"importance": row.get("importance"),
|
||||
"topic": row.get("topic"), "entities": row.get("entities"),
|
||||
"source": row.get("source"),
|
||||
"last_accessed": row.get("last_accessed"),
|
||||
"rrf": round(base, 4), "confidence": round(conf, 2),
|
||||
"temperature": round(temp, 2),
|
||||
"relevance": round(relevance, 4), "mode": retrieval_mode,
|
||||
})
|
||||
if not scored:
|
||||
return []
|
||||
top = scored[:budget]
|
||||
# ABSTENTION via query-difficulty estimation (QPP — Cronen-Townsend et al.,
|
||||
# SIGIR 2002; Zhou & Croft, CIKM 2006; LongMemEval arXiv:2410.10813 makes
|
||||
# abstention a first-class memory ability). The principled signal is the
|
||||
# RANKING GAP, not an absolute score:
|
||||
# - lexical-only: the conjunction already filters to co-occurring terms;
|
||||
# a single weak hit (no runner-up) abstains (no confident winner).
|
||||
# - dense-only: abstain when the top-1 dense match is not clearly above
|
||||
# the runner-up (an ambiguous, no-confident-winner query) OR the top is
|
||||
# below an absolute "probably unrelated" floor. The floor is a coarse
|
||||
# guard; the gap is the real difficulty signal.
|
||||
if not dense and not bm25:
|
||||
return []
|
||||
if not dense: # lexical-only
|
||||
if len(scored) < 1:
|
||||
if not dense:
|
||||
if max(float(item["relevance"]) for item in top) < min_score:
|
||||
return []
|
||||
# P1-03 (#26) DISCHARGE (finding 1): THE floor applies in EVERY
|
||||
# mode. The conjunctive FTS gate is a precision filter — term
|
||||
# co-occurrence, not relevance — so the best match must ALSO clear
|
||||
# min_score before anything is injected. Lexical relevance lives on
|
||||
# its own offset band (~4.1-4.9 with default metadata), so the
|
||||
# default 0.42 floor rarely binds here; the check enforces the floor
|
||||
# contract for ANY min_score (an elevated floor above the band
|
||||
# forces abstention — machine-checked in the frozen tests).
|
||||
if max(float(s["relevance"]) for s in top) < min_score:
|
||||
return [] # below floor -> abstain
|
||||
if len(scored) == 1:
|
||||
return top # single conjunctive match = confident enough
|
||||
# Multiple conjunctive BM25 matches: the FTS5 implicit-AND already
|
||||
# guarantees ALL query terms co-occur in every result (the precision
|
||||
# filter), so these are genuine matches — not a fuzzy near-tie. The
|
||||
# normalized top is the best; a weak runner-up is still a real match.
|
||||
return top
|
||||
# dense present. Score-based abstention (QPP, Shtok et al. TOIS 2012).
|
||||
# The absolute floor is CALIBRATED against real cases (nomic band ~0.6-0.75):
|
||||
# "what does the user drink" vs "black coffee" = 0.766 -> relevant
|
||||
# "quantum physics of black holes" vs "coconut milk" = 0.712 -> noise
|
||||
# The separation sits at ~0.74. Below it, only a clear winner (large gap to
|
||||
# the runner-up) may pass; a weak top with no clear winner abstains.
|
||||
if not bm25:
|
||||
if best_dense < min_score:
|
||||
return [] # below the "probably unrelated" floor
|
||||
return []
|
||||
if best_dense >= 0.74:
|
||||
return _position_aware(top) # calibrated: genuine semantic match
|
||||
return _py_position_aware(top)
|
||||
if len(dense) >= 2:
|
||||
d_scores = sorted(s for _, s in dense)
|
||||
top1 = d_scores[-1]
|
||||
top2 = d_scores[-2]
|
||||
if top1 - top2 >= 0.08:
|
||||
return _position_aware(top) # clear winner despite mid-band score
|
||||
return [] # weak + ambiguous -> abstain
|
||||
return _position_aware(_map_reduce(top)) # single mid-band dense hit
|
||||
# P1-03 (#26) DISCHARGE (finding 1): the hybrid path (dense AND lexical
|
||||
# both fired) gates on the dense cosine — the calibrated scale min_score
|
||||
# was tuned against — exactly like the dense-only branch above. The
|
||||
# numeric check is ADDITIVE to the conjunctive FTS gate (which stays
|
||||
# as-is); the RRF-fused relevance is rank-based and is NOT compared
|
||||
# against the floor here.
|
||||
d_scores = sorted(score for _, score in dense)
|
||||
if d_scores[-1] - d_scores[-2] >= 0.08:
|
||||
return _py_position_aware(top)
|
||||
return []
|
||||
return _py_position_aware(_py_map_reduce(top))
|
||||
if best_dense < min_score:
|
||||
return []
|
||||
return _position_aware(_map_reduce(top))
|
||||
return _py_position_aware(_py_map_reduce(top))
|
||||
|
||||
|
||||
def _drift_rerank(db, entries):
|
||||
@@ -944,7 +882,27 @@ def _drift_rerank(db, entries):
|
||||
return [entry for _, entry in scored]
|
||||
|
||||
|
||||
def _mr_core():
|
||||
"""Rust memory_retrieval core when built; Python fallback remains
|
||||
load-bearing during the strangler. RUNE_RETRIEVAL_CORE=python pins it."""
|
||||
if os.environ.get("RUNE_RETRIEVAL_CORE", "auto") == "python":
|
||||
return None
|
||||
try:
|
||||
from rune import mr_loader
|
||||
|
||||
return mr_loader if mr_loader.available() else None
|
||||
except Exception: # noqa: BLE001 — loader probe failure means Python fallback
|
||||
return None
|
||||
|
||||
|
||||
def _map_reduce(entries: list, chunk_size: int = 10) -> list:
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.map_reduce(entries, chunk_size)
|
||||
return _py_map_reduce(entries, chunk_size)
|
||||
|
||||
|
||||
def _py_map_reduce(entries: list, chunk_size: int = 10) -> list:
|
||||
"""Map-reduce for large result sets.
|
||||
|
||||
When retrieval returns many entries, chunk them and take the top-N
|
||||
@@ -1173,6 +1131,13 @@ def cached_recall(db, query, budget=RECALL_BUDGET, min_score=RECALL_MIN_SCORE, m
|
||||
|
||||
|
||||
def _position_aware(top):
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.position_aware(top)
|
||||
return _py_position_aware(top)
|
||||
|
||||
|
||||
def _py_position_aware(top):
|
||||
"""POSITION-AWARE RE-RANK (research uplift #2): lost-in-the-middle
|
||||
mitigation (Liu et al. 2023; BriefContext, npj Digital Medicine 2025).
|
||||
Models use the START and END of context best and the middle worst, so the
|
||||
@@ -1247,6 +1212,13 @@ _STOPWORDS = {
|
||||
|
||||
|
||||
def _fts_query_conjunctive(query):
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.fts_query_conjunctive(query)
|
||||
return _py_fts_query_conjunctive(query)
|
||||
|
||||
|
||||
def _py_fts_query_conjunctive(query):
|
||||
"""Build a CONJUNCTIVE FTS5 MATCH query (implicit AND).
|
||||
|
||||
Extended Boolean IR (Salton, Fox & Wu, CACM 1983): a document must contain
|
||||
@@ -1269,6 +1241,85 @@ def _fts_query(query):
|
||||
return _fts_query_conjunctive(query)
|
||||
|
||||
|
||||
def mr_rank_fusion(dense, bm25, cap):
|
||||
"""Chunk-side RRF fusion with an explicit candidate cap (W2.1)."""
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.rank_fusion(dense[:cap], bm25[:cap], RRF_K)
|
||||
return _py_rank_fusion(dense[:cap], bm25[:cap], RRF_K)
|
||||
|
||||
|
||||
def _project_chunk_rows(ranks, rows, budget):
|
||||
"""Chunk projection: sorted by RRF desc, text[:400], budget-capped.
|
||||
`ranks` is the W2.1 pair-list ([[rowid, rrf], ...]) from the fusion
|
||||
contract; the Rust side consumes pairs directly."""
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
pairs = (ranks if isinstance(ranks, list)
|
||||
else [list(r) for r in ranks.items()])
|
||||
return core.project_chunk_rows(pairs, rows, budget)
|
||||
return _py_project_chunk_rows(ranks, rows, budget)
|
||||
|
||||
|
||||
def _py_project_chunk_rows(ranks, rows, budget):
|
||||
by_id = {r["rowid"]: r for r in rows}
|
||||
out = []
|
||||
for eid, rrf in sorted(ranks.items(), key=lambda x: -x[1]):
|
||||
r = by_id.get(eid)
|
||||
if not r:
|
||||
continue
|
||||
out.append({
|
||||
"chunk_id": r["chunk_id"],
|
||||
"text": (r["text"] or "")[:400],
|
||||
"wing": r["wing"],
|
||||
"room": r["room"],
|
||||
"source": r["source_path"],
|
||||
"page": r["page"] if "page" in r.keys() else None,
|
||||
"rrf": round(rrf, 4),
|
||||
})
|
||||
if len(out) >= budget:
|
||||
break
|
||||
return out
|
||||
|
||||
|
||||
def _rank_fusion(dense, bm25):
|
||||
"""Pure dense/BM25 fusion and mode selection (R2 W2.1).
|
||||
|
||||
Returns ranks as ordered [id, score] pairs so integer ids survive the
|
||||
JSON membrane without object-key coercion.
|
||||
"""
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.rank_fusion(dense, bm25, RRF_K)
|
||||
return _py_rank_fusion(dense, bm25, RRF_K)
|
||||
|
||||
|
||||
def _py_rank_fusion(dense, bm25, rrf_k=RRF_K):
|
||||
ranks = {}
|
||||
best_dense = 0.0
|
||||
mode = "lexical-only"
|
||||
if dense and bm25:
|
||||
mode = "hybrid"
|
||||
for idx, values in enumerate([dense, bm25]):
|
||||
for pos, (eid, score) in enumerate(values):
|
||||
ranks[eid] = ranks.get(eid, 0.0) + 1.0 / (rrf_k + pos + 1)
|
||||
if idx == 0:
|
||||
best_dense = max(best_dense, score)
|
||||
elif dense:
|
||||
mode = "dense-only"
|
||||
for pos, (eid, score) in enumerate(dense):
|
||||
ranks[eid] = 1.0 / (rrf_k + pos + 1)
|
||||
best_dense = max(best_dense, score)
|
||||
elif bm25:
|
||||
min_bm = min((score for _, score in bm25), default=0.0)
|
||||
max_bm = max((score for _, score in bm25), default=0.0)
|
||||
span = max(max_bm - min_bm, 1e-9)
|
||||
for eid, score in bm25:
|
||||
ranks[eid] = (score - min_bm) / span
|
||||
return {"ranks": [[eid, score] for eid, score in ranks.items()],
|
||||
"best_dense": best_dense, "mode": mode}
|
||||
|
||||
|
||||
def update_entry(db, eid, text=None, importance=None, valid_until=None):
|
||||
sets, params = [], []
|
||||
if text is not None:
|
||||
@@ -1456,6 +1507,13 @@ def working_clear(db, task_id):
|
||||
|
||||
|
||||
def _chunk_text(text, size=1500, overlap=150):
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.chunk_text(text, size, overlap)
|
||||
return _py_chunk_text(text, size, overlap)
|
||||
|
||||
|
||||
def _py_chunk_text(text, size=1500, overlap=150):
|
||||
"""Recursive-ish split on paragraph/heading boundaries, ~1500 chars (the
|
||||
local CPU-friendly size; research: fixed chunking beats semantic for
|
||||
free systems). Headings stay with their content."""
|
||||
@@ -1577,43 +1635,22 @@ def chunk_recall(db, query, budget=6, wing=None, min_sim=0.0, doc=None):
|
||||
bm25 = [(r["rowid"], 0.5) for r in rows]
|
||||
except Exception:
|
||||
logger.debug("chunk_recall failed", exc_info=True)
|
||||
ranks = {}
|
||||
for lst in [dense, bm25]:
|
||||
for pos, (eid, _s) in enumerate(lst):
|
||||
ranks[eid] = ranks.get(eid, 0.0) + 1.0 / (RRF_K + pos + 1)
|
||||
if not ranks:
|
||||
return []
|
||||
ids = list(ranks.keys())
|
||||
ph = ",".join("?" * len(ids))
|
||||
sql = f"SELECT rowid, * FROM chunks WHERE rowid IN ({ph})"
|
||||
params = ids
|
||||
if wing:
|
||||
sql += " AND wing=?"
|
||||
params.append(wing)
|
||||
if doc:
|
||||
sql += " AND doc_id=?"
|
||||
params.append(doc)
|
||||
rows = db.execute(sql, params).fetchall()
|
||||
by_id = {r["rowid"]: r for r in rows}
|
||||
out = []
|
||||
for eid, rrf in sorted(ranks.items(), key=lambda x: -x[1]):
|
||||
r = by_id.get(eid)
|
||||
if not r:
|
||||
continue
|
||||
out.append(
|
||||
{
|
||||
"chunk_id": r["chunk_id"],
|
||||
"text": r["text"][:400],
|
||||
"wing": r["wing"],
|
||||
"room": r["room"],
|
||||
"source": r["source_path"],
|
||||
"page": r["page"] if "page" in r.keys() else None,
|
||||
"rrf": round(rrf, 4),
|
||||
}
|
||||
)
|
||||
if len(out) >= budget:
|
||||
break
|
||||
return out
|
||||
fusion = mr_rank_fusion(dense, bm25, budget * 3)
|
||||
ranks_list = fusion["ranks"] # ordered [rowid, rrf] pairs (W2.1 contract)
|
||||
ids = [int(v[0]) for v in ranks_list]
|
||||
rows = []
|
||||
if ids:
|
||||
ph = ",".join("?" * len(ids))
|
||||
sql = f"SELECT rowid, * FROM chunks WHERE rowid IN ({ph})"
|
||||
params = ids
|
||||
if wing:
|
||||
sql += " AND wing=?"
|
||||
params.append(wing)
|
||||
if doc:
|
||||
sql += " AND doc_id=?"
|
||||
params.append(doc)
|
||||
rows = [dict(r) for r in db.execute(sql, params).fetchall()]
|
||||
return _project_chunk_rows(fusion["ranks"], rows, budget)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------- mining ----
|
||||
@@ -1907,6 +1944,71 @@ def stats(db):
|
||||
return {"active_entries": e, "working": w, "audit": a, "top_topics": by_topic}
|
||||
|
||||
|
||||
# ── storage backend seam (R2 W2.0) ───────────────────────────────────────────
|
||||
# SQLite is RETAINED (Nick's ruling) — the seam separates query logic from
|
||||
# storage mechanics so the Rust core can serve proven-identical READS via
|
||||
# system libsqlite3 FFI. Connection-based callers (stats above) keep their
|
||||
# transactional semantics untouched; path-based consumers opt into the
|
||||
# backend. NO WRITES route through the Rust backend this slice.
|
||||
|
||||
|
||||
class _SQLiteBackend:
|
||||
"""The default backend: the stdlib sqlite3 mechanics, unchanged."""
|
||||
|
||||
name = "sqlite"
|
||||
|
||||
def read_query(self, db_path: str, sql: str, params=()) -> list:
|
||||
conn = sqlite3.connect(db_path)
|
||||
try:
|
||||
return [tuple(r) for r in conn.execute(sql, params).fetchall()]
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
class _RustReadBackend:
|
||||
"""The Rust read path through the memory_storage crate (read-only by
|
||||
construction — the crate exports no write-capable symbols)."""
|
||||
|
||||
name = "rust-memory-storage"
|
||||
|
||||
def read_query(self, db_path: str, sql: str, params=()) -> list:
|
||||
from rune import mems_loader
|
||||
|
||||
return [tuple(r) for r in mems_loader.read_query(db_path, sql, list(params))]
|
||||
|
||||
|
||||
def storage_backend():
|
||||
"""The active read backend. Default sqlite; RUNE_MEMORY_STORAGE=rust
|
||||
opts into the crate when built (falls back loudly-free to sqlite)."""
|
||||
if os.environ.get("RUNE_MEMORY_STORAGE", "auto") == "rust":
|
||||
try:
|
||||
from rune import mems_loader
|
||||
|
||||
if mems_loader.available():
|
||||
return _RustReadBackend()
|
||||
except Exception: # noqa: BLE001, S110 — backend probe failure means the default serves (fallback, not silence)
|
||||
pass
|
||||
return _SQLiteBackend()
|
||||
|
||||
|
||||
def stats_for_path(db_path: str) -> dict:
|
||||
"""stats() through the storage backend seam — the opt-in consumer the
|
||||
parity battery and future Rust callers use. Same result dict shape."""
|
||||
backend = storage_backend()
|
||||
e = backend.read_query(db_path, "SELECT COUNT(*) FROM entries WHERE status='active'")[0][0]
|
||||
w = backend.read_query(db_path, "SELECT COUNT(*) FROM working")[0][0]
|
||||
a = backend.read_query(db_path, "SELECT COUNT(*) FROM audit_log")[0][0]
|
||||
by_topic = {
|
||||
r[0]: r[1]
|
||||
for r in backend.read_query(
|
||||
db_path,
|
||||
"SELECT topic, COUNT(*) AS n FROM entries WHERE status='active' GROUP BY topic ORDER BY n DESC LIMIT 6",
|
||||
)
|
||||
if r[0]
|
||||
}
|
||||
return {"active_entries": e, "working": w, "audit": a, "top_topics": by_topic}
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ associations ----
|
||||
|
||||
|
||||
@@ -1978,8 +2080,24 @@ def recall_with_associations(db, query, budget=RECALL_BUDGET, min_score=RECALL_M
|
||||
ids = list(boost_map.keys())
|
||||
placeholders = ",".join("?" * len(ids))
|
||||
rows = db.execute(f"SELECT * FROM entries WHERE id IN ({placeholders}) AND status='active'", ids).fetchall()
|
||||
boost_items = [{"id": eid, "strength": strength}
|
||||
for eid, strength in sorted(boost_map.items(), key=lambda x: -x[1])]
|
||||
return _merge_association_rows(base, boost_items, [dict(r) for r in rows], budget)
|
||||
|
||||
|
||||
def _merge_association_rows(base, boost_items, rows, budget):
|
||||
"""Pure association projection/boost/order/budget kernel (R2 W2.1)."""
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.merge_association_rows(base, boost_items, rows, budget)
|
||||
return _py_merge_association_rows(base, boost_items, rows, budget)
|
||||
|
||||
|
||||
def _py_merge_association_rows(base, boost_items, rows, budget):
|
||||
base = list(base)
|
||||
by_id2 = {r["id"]: r for r in rows}
|
||||
for eid, strength in sorted(boost_map.items(), key=lambda x: -x[1]):
|
||||
for item in boost_items:
|
||||
eid, strength = item["id"], item["strength"]
|
||||
row = by_id2.get(eid)
|
||||
if not row:
|
||||
continue
|
||||
@@ -2022,6 +2140,19 @@ def fused_recall(db, query, budget=RECALL_BUDGET, min_score=RECALL_MIN_SCORE, ch
|
||||
"""
|
||||
entries = recall_with_associations(db, query, budget=budget, min_score=min_score)
|
||||
research = chunk_recall(db, query, budget=chunk_budget, wing=wings, doc=None)
|
||||
return _fuse_results(entries, research)
|
||||
|
||||
|
||||
def _fuse_results(entries, research):
|
||||
"""Pure fact/research projection, de-duplication and per-kind scale
|
||||
alignment (R2 W2.1). Rust core when built; Python core is the oracle."""
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.fuse_results(entries, research)
|
||||
return _py_fuse_results(entries, research)
|
||||
|
||||
|
||||
def _py_fuse_results(entries, research):
|
||||
seen = set()
|
||||
merged = []
|
||||
for e in entries:
|
||||
@@ -2075,6 +2206,13 @@ def fused_recall(db, query, budget=RECALL_BUDGET, min_score=RECALL_MIN_SCORE, ch
|
||||
|
||||
|
||||
def _norm_key(text):
|
||||
core = _mr_core()
|
||||
if core is not None:
|
||||
return core.norm_key(text)
|
||||
return _py_norm_key(text)
|
||||
|
||||
|
||||
def _py_norm_key(text):
|
||||
"""Normalize text for cross-table de-duplication (entries vs chunks of the
|
||||
same absorbed material may differ in whitespace/case)."""
|
||||
return " ".join((text or "").lower().split())
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ctypes loader for the Rust memory_storage core (R2 W2.0).
|
||||
|
||||
Contract BUILDER-2026-10-04T15:54:17Z-cli. READ-ONLY by construction:
|
||||
the only operation is read_query — the crate exports no write-capable
|
||||
symbols (Nick's ruling: reads proven byte-identical before any writes
|
||||
exist). SQLite is retained; the crate reaches it via system libsqlite3.
|
||||
|
||||
FFI contract (doc-envelope law): mems_read_query({db_path, sql, params})
|
||||
-> [[cell, ...], ...]; mems_free_string(ptr). FFI segfault law: argtypes +
|
||||
restype pinned per symbol. Override the .so with MEMS_RUST_LIB (FILE path).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
_REPO = Path(__file__).resolve().parents[2]
|
||||
_CRATE_DIR = _REPO / "src" / "rust" / "memory_storage"
|
||||
_LIB_PATH = Path(
|
||||
os.environ.get(
|
||||
"MEMS_RUST_LIB", _CRATE_DIR / "target" / "release" / "libmemory_storage.so"
|
||||
)
|
||||
)
|
||||
|
||||
_lib = None
|
||||
|
||||
|
||||
class MemoryStorageUnavailable(FileNotFoundError):
|
||||
"""The Rust core is not built (or MEMS_RUST_LIB points nowhere)."""
|
||||
|
||||
|
||||
def available() -> bool:
|
||||
return _LIB_PATH.is_file()
|
||||
|
||||
|
||||
def _load() -> ctypes.CDLL:
|
||||
global _lib
|
||||
if _lib is not None:
|
||||
return _lib
|
||||
if not _LIB_PATH.exists():
|
||||
raise MemoryStorageUnavailable(
|
||||
f"Rust memory_storage core not built: {_LIB_PATH} missing — run "
|
||||
f"`cargo build --release` in {_CRATE_DIR}"
|
||||
)
|
||||
lib = ctypes.CDLL(str(_LIB_PATH))
|
||||
lib.mems_free_string.argtypes = [ctypes.c_void_p]
|
||||
lib.mems_free_string.restype = None
|
||||
lib.mems_read_query.argtypes = [ctypes.c_char_p]
|
||||
lib.mems_read_query.restype = ctypes.c_void_p # char* — never c_int
|
||||
_lib = lib
|
||||
return lib
|
||||
|
||||
|
||||
def _call(payload: dict) -> dict:
|
||||
"""Raw envelope: {"ok", "value"|"err"} — the error-honesty section of
|
||||
the canary needs the envelope, not an exception."""
|
||||
lib = _load()
|
||||
raw = json.dumps(payload).encode("utf-8")
|
||||
ptr = lib.mems_read_query(raw)
|
||||
if not ptr:
|
||||
raise RuntimeError("mems_read_query returned a null pointer")
|
||||
try:
|
||||
text = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
|
||||
finally:
|
||||
lib.mems_free_string(ptr)
|
||||
return json.loads(text)
|
||||
|
||||
|
||||
def read_query(db_path: str, sql: str, params: list) -> list:
|
||||
"""Read-only query through the Rust core; raises on the error envelope."""
|
||||
env = _call({"db_path": db_path, "sql": sql, "params": params})
|
||||
if not env.get("ok"):
|
||||
raise RuntimeError(f"mems_read_query core error: {env.get('err')}")
|
||||
return env["value"]
|
||||
|
||||
|
||||
def read_query_result(db_path: str, sql: str, params: list) -> dict:
|
||||
"""The raw envelope (error-honesty checks consume this)."""
|
||||
return _call({"db_path": db_path, "sql": sql, "params": params})
|
||||
@@ -0,0 +1,38 @@
|
||||
"""ctypes loader for the zero-dependency memory_retrieval core (R2 W2.1)."""
|
||||
from __future__ import annotations
|
||||
import ctypes, json, os
|
||||
from pathlib import Path
|
||||
_ROOT=Path(__file__).resolve().parents[2]
|
||||
_CRATE=_ROOT/"src/rust/memory_retrieval"
|
||||
_LIB=Path(os.environ.get("MR_RUST_LIB",_CRATE/"target/release/libmemory_retrieval.so"))
|
||||
_lib=None
|
||||
def available(): return _LIB.is_file()
|
||||
def _load():
|
||||
global _lib
|
||||
if _lib is not None:return _lib
|
||||
if not _LIB.exists():raise FileNotFoundError(f"memory_retrieval core not built: {_LIB}")
|
||||
lib=ctypes.CDLL(str(_LIB));lib.mr_call.argtypes=[ctypes.c_char_p];lib.mr_call.restype=ctypes.c_void_p
|
||||
lib.mr_free_string.argtypes=[ctypes.c_void_p];lib.mr_free_string.restype=None;_lib=lib;return lib
|
||||
def _call(op,arg):
|
||||
# Send UTF-8 directly. ensure_ascii=True emits surrogate-pair escapes; the
|
||||
# shared zero-dep parser treats those as independent code points, which
|
||||
# would replace astral characters (emoji) and break Python char-count
|
||||
# parity in chunking/normalization.
|
||||
lib=_load();ptr=lib.mr_call(json.dumps({"op":op,"arg":arg},ensure_ascii=False).encode())
|
||||
if not ptr:raise RuntimeError("mr_call returned null")
|
||||
try:text=ctypes.cast(ptr,ctypes.c_char_p).value.decode()
|
||||
finally:lib.mr_free_string(ptr)
|
||||
env=json.loads(text)
|
||||
if not env.get("ok"):raise RuntimeError(env.get("err"))
|
||||
return env["value"]
|
||||
def map_reduce(entries,chunk_size=10):return _call("map_reduce",{"entries":entries,"chunk_size":chunk_size})
|
||||
def position_aware(entries):return _call("position_aware",{"entries":entries})
|
||||
def fts_query_conjunctive(query):return _call("fts_query_conjunctive",{"query":query})
|
||||
def chunk_text(text,size=1500,overlap=150):return _call("chunk_text",{"text":text,"size":size,"overlap":overlap})
|
||||
def norm_key(text):return _call("norm_key",{"text":text})
|
||||
def fuse_results(entries,research):return _call("fuse_results",{"entries":entries,"research":research})
|
||||
def merge_association_rows(base,boosts,rows,budget):return _call("merge_association_rows",{"base":base,"boosts":boosts,"rows":rows,"budget":budget})
|
||||
def rank_fusion(dense,bm25,rrf_k=60):return _call("rank_fusion",{"dense":dense,"bm25":bm25,"rrf_k":rrf_k})
|
||||
def score_recall_rows(fusion,rows,dense,bm25,budget,min_score,now,half_life):return _call("score_recall_rows",{"fusion":fusion,"rows":rows,"dense":dense,"bm25":bm25,"budget":budget,"min_score":min_score,"now":now,"half_life":half_life})
|
||||
def project_chunk_rows(ranks, rows, budget):
|
||||
return _call("project_chunk_rows", {"ranks": ranks, "rows": rows, "budget": budget})
|
||||
@@ -161,7 +161,33 @@ def load_rules():
|
||||
return rules
|
||||
|
||||
|
||||
def _cc_pg_core():
|
||||
"""Rust cognition_core when available (persona kernels); pin with
|
||||
RUNE_COGNITION_CORE=python."""
|
||||
import os
|
||||
if os.environ.get("RUNE_COGNITION_CORE", "auto") == "python":
|
||||
return None
|
||||
try:
|
||||
from rune import cc_loader
|
||||
except Exception: # noqa: BLE001 — loader probe failure means fallback
|
||||
return None
|
||||
try:
|
||||
return cc_loader if cc_loader.available() else None
|
||||
except Exception: # noqa: BLE001 — availability probe never crashes
|
||||
return None
|
||||
|
||||
|
||||
def _lex(text):
|
||||
"""Distinctive content words (R2 W3.2: Rust kernel when built)."""
|
||||
core = _cc_pg_core()
|
||||
if core is not None:
|
||||
return set(core.persona_lex(text))
|
||||
return _py_lex(text)
|
||||
|
||||
|
||||
def _py_lex(text):
|
||||
"""Python oracle (parity floor)."""
|
||||
|
||||
"""Distinctive content words of a rule body (lowercase, >3 chars,
|
||||
light-stemmed so plural/singular engage each other; preserves 3-char
|
||||
ALL-CAPS acronyms so technical abbreviations match their expansion)."""
|
||||
@@ -253,6 +279,15 @@ def _lex_input(text):
|
||||
|
||||
|
||||
def _overlap(a, b):
|
||||
"""Overlap ratio (R2 W3.2: Rust kernel when built)."""
|
||||
core = _cc_pg_core()
|
||||
if core is not None:
|
||||
return core.persona_overlap(sorted(a), sorted(b))
|
||||
return _py_overlap(a, b)
|
||||
|
||||
|
||||
def _py_overlap(a, b):
|
||||
"""Python oracle (parity floor)."""
|
||||
if not a or not b:
|
||||
return 0.0
|
||||
return len(a & b) / max(1, min(len(a), len(b)))
|
||||
@@ -338,6 +373,34 @@ def _semantic_engagement(text, rule):
|
||||
|
||||
|
||||
def decide(text, rules=None):
|
||||
"""The persona decides on a request, deterministically (R2 W3.2:
|
||||
Rust kernel when built; the semantic cosines are gathered here —
|
||||
embedder calls are IO — and passed into the kernel)."""
|
||||
rules = rules if rules is not None else load_rules()
|
||||
core = _cc_pg_core()
|
||||
if core is not None:
|
||||
text_s = (text or "").strip()
|
||||
sems = [_semantic_engagement(text_s, r) for r in rules]
|
||||
return core.persona_decide(text_s, [_rule_json(r) for r in rules],
|
||||
PERMISSIVE_MODE, sems)
|
||||
return _py_decide(text, rules)
|
||||
|
||||
|
||||
def _rule_json(r) -> dict:
|
||||
"""A rule in the kernel's JSON contract (citation rides along when
|
||||
present so _cite stays data-driven)."""
|
||||
return {
|
||||
"text": r["text"], "words": sorted(r["words"]),
|
||||
"core": r["core"], "priority": r.get("priority", 0),
|
||||
"restrictive": r.get("restrictive", False),
|
||||
"user_rule": r.get("user_rule", False),
|
||||
"citation": r.get("citation"),
|
||||
}
|
||||
|
||||
|
||||
def _py_decide(text, rules=None):
|
||||
"""Python oracle (parity floor) — the ORIGINAL decide body."""
|
||||
|
||||
"""The persona decides on a request, deterministically, from its own
|
||||
stored rules. No generative LLM in the decision path (a local embedding
|
||||
model may contribute semantic similarity). Returns a full verdict."""
|
||||
|
||||
+9
-1
@@ -162,8 +162,16 @@ def recall(context, limit=4):
|
||||
term = (context or "").lower()
|
||||
if not term:
|
||||
return []
|
||||
from rune.identity_anchors import _cc_core
|
||||
core = _cc_core()
|
||||
if core is not None:
|
||||
return core.pins_recall(_load(), term, limit)
|
||||
return _py_pin_recall(_load(), term, limit)
|
||||
|
||||
|
||||
def _py_pin_recall(recs, term, limit=4):
|
||||
out = []
|
||||
for rec in _load():
|
||||
for rec in recs:
|
||||
if rec.get("state") != "open":
|
||||
continue
|
||||
p = _project(rec)
|
||||
|
||||
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
|
||||
|
||||
This is not an interface. This is how I see, speak, and interact with the world.
|
||||
|
||||
Version: v0.91.0
|
||||
Version: v0.95.1
|
||||
Features: 41 (24 original + 17 new native commands)
|
||||
|
||||
Usage:
|
||||
@@ -1895,7 +1895,7 @@ class RuneApp(App):
|
||||
# Show version info
|
||||
self.chat_channel.add_message(
|
||||
"system",
|
||||
f"[dim]Rune v0.91.0 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
f"[dim]Rune v0.95.1 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
)
|
||||
|
||||
# Auto-show night mode suggestion if evening/night hours
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ctypes loader for the Rust scaffold_core (R2 Wave 1).
|
||||
|
||||
Contract BUILDER-2026-10-04T15:25:33Z-cli. The V1-ACCEPTED scaffolding
|
||||
engine's deterministic core through the cdylib with no subprocess.
|
||||
No-clock law: `now` always arrives inside the inputs.
|
||||
|
||||
FFI contract (doc-envelope law — every call returns {"ok", "value"|"err"}):
|
||||
* sc_check_transition({current, target}) -> {legal, error?}
|
||||
* sc_close_quality(inputs) -> contract_quality bucket dict
|
||||
* sc_free_string(ptr)
|
||||
|
||||
FFI segfault law: every symbol gets explicit argtypes + restype (c_void_p
|
||||
for returned char*). Zero dependencies; override the .so with SC_RUST_LIB
|
||||
(a FILE path).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
_REPO = Path(__file__).resolve().parents[2]
|
||||
_CRATE_DIR = _REPO / "src" / "rust" / "scaffold_core"
|
||||
_LIB_PATH = Path(
|
||||
os.environ.get(
|
||||
"SC_RUST_LIB", _CRATE_DIR / "target" / "release" / "libscaffold_core.so"
|
||||
)
|
||||
)
|
||||
|
||||
_lib = None
|
||||
|
||||
|
||||
class ScaffoldCoreUnavailable(FileNotFoundError):
|
||||
"""The Rust core is not built (or SC_RUST_LIB points nowhere). Callers
|
||||
fall back to the Python implementation — strangler law."""
|
||||
|
||||
|
||||
def available() -> bool:
|
||||
return _LIB_PATH.is_file()
|
||||
|
||||
|
||||
def _load() -> ctypes.CDLL:
|
||||
global _lib
|
||||
if _lib is not None:
|
||||
return _lib
|
||||
if not _LIB_PATH.exists():
|
||||
raise ScaffoldCoreUnavailable(
|
||||
f"Rust scaffold_core not built: {_LIB_PATH} missing — run "
|
||||
f"`cargo build --release` in {_CRATE_DIR}"
|
||||
)
|
||||
lib = ctypes.CDLL(str(_LIB_PATH))
|
||||
lib.sc_free_string.argtypes = [ctypes.c_void_p]
|
||||
lib.sc_free_string.restype = None
|
||||
for sym in ("sc_check_transition", "sc_close_quality",
|
||||
"sc_language_placement"):
|
||||
fn = getattr(lib, sym)
|
||||
fn.argtypes = [ctypes.c_char_p]
|
||||
fn.restype = ctypes.c_void_p # char* — never default c_int
|
||||
_lib = lib
|
||||
return lib
|
||||
|
||||
|
||||
def _call(sym: str, payload: dict):
|
||||
lib = _load()
|
||||
fn = getattr(lib, sym)
|
||||
raw = json.dumps(payload).encode("utf-8")
|
||||
ptr = fn(raw)
|
||||
if not ptr:
|
||||
raise RuntimeError(f"{sym} returned a null pointer")
|
||||
try:
|
||||
text = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
|
||||
finally:
|
||||
lib.sc_free_string(ptr)
|
||||
env = json.loads(text)
|
||||
if not env.get("ok"):
|
||||
raise RuntimeError(f"{sym} core error: {env.get('err')}")
|
||||
return env["value"]
|
||||
|
||||
|
||||
def check_transition(current: str, target: str) -> dict:
|
||||
"""Phase-transition legality verdict ({legal} or {legal, error})."""
|
||||
return _call("sc_check_transition", {"current": current, "target": target})
|
||||
|
||||
|
||||
def close_quality(inputs: dict) -> dict:
|
||||
"""The closure classification buckets from gathered inputs."""
|
||||
return _call("sc_close_quality", inputs)
|
||||
|
||||
|
||||
def language_placement(project: str, characteristics: list) -> dict:
|
||||
"""The protocol's language-placement verdict (R2 Wave 1)."""
|
||||
return _call("sc_language_placement",
|
||||
{"project": project, "characteristics": characteristics})
|
||||
+76
-62
@@ -488,6 +488,64 @@ class Scaffold:
|
||||
def contract(self, doc: dict, contract_id: str) -> dict | None:
|
||||
return entity(doc, f"contract:{contract_id}")
|
||||
|
||||
def _py_close_quality(self, inputs: dict) -> dict:
|
||||
"""Python core of the closure classification (R2 Wave 1 parity
|
||||
oracle — scaffold_core.close_quality computes from the same input
|
||||
shape). Pure bucket math; side effects stay in close_contract."""
|
||||
affected = set(inputs.get("affected_entities") or [])
|
||||
expected_new = set(inputs.get("expected_new_entities") or [])
|
||||
expected_runtime = set(inputs.get("expected_runtime_effects") or [])
|
||||
observed_evidence = inputs.get("observed_evidence") or []
|
||||
predicted = inputs.get("predicted_frontier")
|
||||
obs_set = {item.get("entity", "") for item in observed_evidence}
|
||||
obs_set.discard("")
|
||||
|
||||
pred_existing = set(inputs.get("predicted_existing_affected") or [])
|
||||
pred_existing |= affected
|
||||
if predicted is not None:
|
||||
pred_existing |= {
|
||||
x
|
||||
for k in ("level0_direct", "level1_obligations", "contracts", "level2_verification")
|
||||
for x in predicted.get(k, [])
|
||||
}
|
||||
|
||||
correctly_predicted = sorted(pred_existing & obs_set)
|
||||
predicted_but_unaffected = sorted(pred_existing - obs_set)
|
||||
expected_new_observed = sorted(expected_new & obs_set)
|
||||
expected_new_missing = sorted(expected_new - obs_set)
|
||||
matched_runtime = {o for o in obs_set if any(eff.startswith(o) for eff in expected_runtime)}
|
||||
expected_runtime_observed = sorted(
|
||||
eff for eff in expected_runtime if any(eff.startswith(o) for o in matched_runtime)
|
||||
)
|
||||
genuinely_unexpected_new = sorted(obs_set - pred_existing - expected_new - matched_runtime)
|
||||
|
||||
return {
|
||||
"predicted_existing_affected": sorted(pred_existing),
|
||||
"expected_new_entities": sorted(expected_new),
|
||||
"observed": sorted(obs_set),
|
||||
"observed_existing": correctly_predicted,
|
||||
"observed_new": sorted(obs_set & (expected_new | (obs_set - pred_existing))),
|
||||
"correctly_predicted": correctly_predicted,
|
||||
"predicted_but_unaffected": predicted_but_unaffected,
|
||||
"expected_new_observed": expected_new_observed,
|
||||
"expected_new_missing": expected_new_missing,
|
||||
"expected_runtime_effects": sorted(expected_runtime),
|
||||
"expected_runtime_observed": expected_runtime_observed,
|
||||
"expected_runtime_missing": sorted(expected_runtime - obs_set),
|
||||
"genuinely_unexpected_new": genuinely_unexpected_new,
|
||||
"missed": genuinely_unexpected_new,
|
||||
"needless": predicted_but_unaffected,
|
||||
"candidate_corrections": [
|
||||
{
|
||||
"entity": x,
|
||||
"status": "CANDIDATE",
|
||||
"note": "genuinely unexpected new surface — evidence required before store update",
|
||||
}
|
||||
for x in genuinely_unexpected_new
|
||||
],
|
||||
"evidence_sources": sorted({item.get("source", "unattributed") for item in observed_evidence}),
|
||||
}
|
||||
|
||||
def snapshot_predicted_frontier(self, doc: dict, contract_id: str, seed_entity_ids: list[str]) -> dict:
|
||||
"""Persist the predicted impact frontier at approval time — the input
|
||||
to closure's predicted-vs-observed comparison."""
|
||||
@@ -541,72 +599,28 @@ class Scaffold:
|
||||
raise ValueError(f"contract not found: {contract_id}")
|
||||
if e.get("phase") not in ("superseding", "verifying"):
|
||||
raise IllegalPhaseTransition(f"close requires superseding/verifying phase, got {e.get('phase')}")
|
||||
predicted = e.get("ext", {}).get("predicted_frontier")
|
||||
affected = e.get("identities", {}).get("affected_entities", [])
|
||||
expected_new = set(e.get("identities", {}).get("expected_new_entities", []))
|
||||
# Tranche 5 §14: expected RUNTIME effects (deployment:current advances
|
||||
# etc.) are prediction/accounting metadata, not workflow steps. An
|
||||
# observed entity matching an expected runtime effect is EXPECTED,
|
||||
# not genuinely unexpected — but only when independently observed
|
||||
# (§15: prediction never self-certifies; the evidence item must exist).
|
||||
expected_runtime = set(e.get("ext", {}).get("expected_runtime_effects", []))
|
||||
quality: dict = {"contract": contract_id, "captured_at": now()}
|
||||
|
||||
# independent observed impact (§17): evidence items only
|
||||
obs = record_observed_impact(doc, contract_id, observed_evidence or [])
|
||||
obs_set = set(obs["observed_entities"])
|
||||
|
||||
pred_existing = set(e.get("ext", {}).get("predicted_existing_affected", []))
|
||||
pred_existing |= set(affected)
|
||||
if predicted is not None:
|
||||
pred_existing |= {
|
||||
x
|
||||
for k in ("level0_direct", "level1_obligations", "contracts", "level2_verification")
|
||||
for x in predicted.get(k, [])
|
||||
}
|
||||
# R2 Wave 1: the bucket math is factored out so the Rust engine
|
||||
# (scaffold_core.close_quality) computes from the SAME gathered
|
||||
# inputs — the production ledger replay is the parity oracle.
|
||||
inputs = {
|
||||
"contract_id": contract_id,
|
||||
"phase": e.get("phase", "verifying"),
|
||||
"affected_entities": e.get("identities", {}).get("affected_entities", []),
|
||||
"expected_new_entities": e.get("identities", {}).get("expected_new_entities", []),
|
||||
"predicted_existing_affected": e.get("ext", {}).get("predicted_existing_affected", []),
|
||||
"predicted_frontier": e.get("ext", {}).get("predicted_frontier"),
|
||||
"expected_runtime_effects": e.get("ext", {}).get("expected_runtime_effects", []),
|
||||
"observed_evidence": observed_evidence or [],
|
||||
"now": now(),
|
||||
}
|
||||
quality = self._py_close_quality(inputs)
|
||||
quality["contract"] = contract_id
|
||||
quality["captured_at"] = inputs["now"]
|
||||
quality["observed"] = obs["observed_entities"]
|
||||
|
||||
correctly_predicted = sorted(pred_existing & obs_set)
|
||||
predicted_but_unaffected = sorted(pred_existing - obs_set)
|
||||
expected_new_observed = sorted(expected_new & obs_set)
|
||||
expected_new_missing = sorted(expected_new - obs_set)
|
||||
# effect strings are phrases ("deployment:current advances"); an
|
||||
# observed entity matches when an expected effect STARTS with its id
|
||||
matched_runtime = {o for o in obs_set if any(eff.startswith(o) for eff in expected_runtime)}
|
||||
expected_runtime_observed = sorted(
|
||||
eff for eff in expected_runtime if any(eff.startswith(o) for o in matched_runtime)
|
||||
)
|
||||
expected_runtime_missing = sorted(expected_runtime - set(expected_runtime_observed))
|
||||
genuinely_unexpected_new = sorted(obs_set - pred_existing - expected_new - matched_runtime)
|
||||
|
||||
quality.update(
|
||||
{
|
||||
"predicted_existing_affected": sorted(pred_existing),
|
||||
"expected_new_entities": sorted(expected_new),
|
||||
"observed": sorted(obs_set), # legacy union (Tranche 2 readers)
|
||||
"observed_existing": correctly_predicted,
|
||||
"observed_new": sorted(obs_set & (expected_new | (obs_set - pred_existing))),
|
||||
"correctly_predicted": correctly_predicted,
|
||||
"predicted_but_unaffected": predicted_but_unaffected,
|
||||
"expected_new_observed": expected_new_observed,
|
||||
"expected_new_missing": expected_new_missing,
|
||||
"expected_runtime_effects": sorted(expected_runtime),
|
||||
"expected_runtime_observed": expected_runtime_observed,
|
||||
"expected_runtime_missing": sorted(expected_runtime - obs_set),
|
||||
"genuinely_unexpected_new": genuinely_unexpected_new,
|
||||
# legacy aliases (Tranche 2/3 consumers)
|
||||
"missed": genuinely_unexpected_new,
|
||||
"needless": predicted_but_unaffected,
|
||||
"candidate_corrections": [
|
||||
{
|
||||
"entity": x,
|
||||
"status": "CANDIDATE",
|
||||
"note": "genuinely unexpected new surface — evidence required before store update",
|
||||
}
|
||||
for x in genuinely_unexpected_new
|
||||
],
|
||||
"evidence_sources": sorted({item.get("source", "unattributed") for item in (observed_evidence or [])}),
|
||||
}
|
||||
)
|
||||
if scope_files is not None:
|
||||
quality["scope_check"] = self.check_scope(doc, contract_id, scope_files)
|
||||
e.setdefault("ext", {})["contract_quality"] = quality
|
||||
|
||||
@@ -172,8 +172,8 @@ impl<'a> Parser<'a> {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i + 1..].starts_with(b"\\u") {
|
||||
self.i += 2;
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "cognition_core"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "cognition_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "R2 W3.1 — deterministic cognition kernels (context_broker first) per contract BUILDER-2026-10-05T07:19:27Z-cli; zero-dep, no-clock"
|
||||
|
||||
[lib]
|
||||
name = "cognition_core"
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
|
||||
[[bin]]
|
||||
name = "cognition_core"
|
||||
path = "src/main.rs"
|
||||
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
"""canary_cognition_core.py — parity battery for the cognition_core crate
|
||||
(R2 Wave 3 slice 1, contract BUILDER-2026-10-05T07:19:27Z-cli).
|
||||
|
||||
First tenant: context_broker's deterministic kernel — default_estimator,
|
||||
default_budget, default_memory_budget, memory_disabled.
|
||||
|
||||
Parity floor: byte-identical outputs on identical inputs.
|
||||
Improvement (measured): the estimator's per-character loop may become a
|
||||
faster path IF identical — measured, or reverted.
|
||||
|
||||
Run: python3 src/rust/cognition_core/canary_cognition_core.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
CRATE = Path(__file__).resolve().parent
|
||||
REPO = CRATE.parents[2]
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
PASS = FAIL = 0
|
||||
NOW = "2026-10-05T07:30:00+00:00"
|
||||
|
||||
|
||||
def check(name, ok, detail=""):
|
||||
global PASS, FAIL
|
||||
if ok:
|
||||
PASS += 1
|
||||
print(f" ✓ {name}")
|
||||
else:
|
||||
FAIL += 1
|
||||
print(f" ✗ {name} — {detail}")
|
||||
|
||||
|
||||
def build():
|
||||
env = dict(os.environ)
|
||||
absolute = Path("/home/nick/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin")
|
||||
rust = absolute if absolute.is_dir() else (
|
||||
Path.home() / ".rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin")
|
||||
env["PATH"] = f"{rust}:{env.get('PATH', '')}"
|
||||
return subprocess.run(["cargo", "build", "--release"], cwd=CRATE,
|
||||
env=env, capture_output=True, text=True, timeout=600)
|
||||
|
||||
|
||||
def main():
|
||||
print("=== cognition_core: context_broker kernel parity ===")
|
||||
r = build()
|
||||
check("crate builds", r.returncode == 0, r.stderr[-240:])
|
||||
if r.returncode:
|
||||
print(f"RESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1
|
||||
|
||||
from rune import cc_loader
|
||||
from rune import context_broker as cb
|
||||
|
||||
# ── estimator: exact token semantics on every text class ──────────────
|
||||
texts = ["", " ", "one", "hello world", "héllo wörld 🎸 emoji",
|
||||
"x" * 10001, "tabs\t\tand\nnewlines\n", " padded ",
|
||||
"unicode — dashes — en‑dash", "1 token ~ 4 chars maybe"]
|
||||
for t in texts:
|
||||
py = cb._py_default_estimator(t)
|
||||
rs = cc_loader.default_estimator(t)
|
||||
check(f"estimator {t[:24]!r}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
# property sweep: 200 random-ish strings, parity must hold
|
||||
import random
|
||||
random.seed(20261005)
|
||||
for i in range(200):
|
||||
n = random.randint(0, 300)
|
||||
t = "".join(random.choice("abcd \n\té🎸 ") for _ in range(n))
|
||||
py = cb._py_default_estimator(t)
|
||||
rs = cc_loader.default_estimator(t)
|
||||
if py != rs:
|
||||
check("estimator property sweep", False, f"seed case {i}: py={py!r} rs={rs!r}")
|
||||
break
|
||||
else:
|
||||
check("estimator property sweep (200 cases)", True)
|
||||
|
||||
# ── budget arithmetic ──────────────────────────────────────────────────
|
||||
for window in (0, 1, 1024, 8192, 131072, 200000, 10**7):
|
||||
py = cb._py_default_budget(window)
|
||||
rs = cc_loader.default_budget(window)
|
||||
check(f"budget {window}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
for window in (None, 0, 4096, 32768):
|
||||
py = cb._py_default_memory_budget(window)
|
||||
rs = cc_loader.default_memory_budget(window)
|
||||
check(f"memory budget {window}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
# ── disabled gate (env contract) ──────────────────────────────────────
|
||||
env_vars = [None, "", "0", "1", "true", "false", "yes"]
|
||||
for v in env_vars:
|
||||
env = dict(os.environ)
|
||||
if v is None:
|
||||
env.pop("RUNE_MEMORY_OFF", None)
|
||||
else:
|
||||
env["RUNE_MEMORY_OFF"] = v
|
||||
os.environ.clear(); os.environ.update(env)
|
||||
raw = os.environ.get("RUNE_MEMORY_OFF", "").strip().lower()
|
||||
py = cb._py_memory_disabled_value(raw)
|
||||
rs = cc_loader.memory_disabled()
|
||||
check(f"memory_disabled env {v!r}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
# and the PUBLIC delegation path agrees (the cross-check gate)
|
||||
pub = cb.memory_disabled()
|
||||
check(f"memory_disabled public env {v!r}", pub == py,
|
||||
f"pub={pub!r} py={py!r}")
|
||||
os.environ.pop("RUNE_MEMORY_OFF", None)
|
||||
|
||||
# ── improvement measurement (estimator) ───────────────────────────────
|
||||
import timeit
|
||||
t = "x" * 5000
|
||||
py_us = min(timeit.repeat(lambda: cb._py_default_estimator(t), number=1000, repeat=5)) / 1000 * 1e6
|
||||
rs_us = min(timeit.repeat(lambda: cc_loader.default_estimator(t), number=1000, repeat=5)) / 1000 * 1e6
|
||||
print(f" measured: py {py_us:.1f}us vs rust {rs_us:.1f}us per call")
|
||||
# FFI MICRO-LATENCY LAW (measured R2 W2.1): JSON-envelope serialization
|
||||
# dominates at small scale — kernel-parity, not micro-latency, is the
|
||||
# improvement channel at THIS surface. The estimator's value (1250) is
|
||||
# trivially correct on both sides; assert parity, note timing.
|
||||
t_out_rs = cc_loader.default_estimator(t)
|
||||
t_out_py = cb._py_default_estimator(t)
|
||||
check("estimator parity on the measured input", t_out_rs == t_out_py,
|
||||
f"py={t_out_py!r} rs={t_out_rs!r}")
|
||||
|
||||
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1 if FAIL else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
"""canary_cognition_core persona section — W3.2 (contract
|
||||
BUILDER-2026-10-05T07:19:27Z-cli, slice 2).
|
||||
|
||||
The persona-decision kernel's parity battery: _lex/_overlap/decide.
|
||||
|
||||
Run standalone; also invoked via the cognition_core canary's persona gate.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
CRATE = Path(__file__).resolve().parent
|
||||
REPO = CRATE.parents[2]
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
PASS = FAIL = 0
|
||||
|
||||
|
||||
def check(name, ok, detail=""):
|
||||
global PASS, FAIL
|
||||
if ok:
|
||||
PASS += 1
|
||||
print(f" ✓ {name}")
|
||||
else:
|
||||
FAIL += 1
|
||||
print(f" ✗ {name} — {detail}")
|
||||
|
||||
|
||||
def build():
|
||||
env = dict(os.environ)
|
||||
absolute = Path("/home/nick/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin")
|
||||
rust = absolute if absolute.is_dir() else (
|
||||
Path.home() / ".rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin")
|
||||
env["PATH"] = f"{rust}:{env.get('PATH', '')}"
|
||||
return subprocess.run(["cargo", "build", "--release"], cwd=CRATE,
|
||||
env=env, capture_output=True, text=True, timeout=600)
|
||||
|
||||
|
||||
RULES = [
|
||||
{"topic": "memory", "text": "Always maintain the Rune memory hierarchy.",
|
||||
"words": sorted({"memory", "hierarchy", "maintain"}),
|
||||
"core": "memory hierarchy store",
|
||||
"priority": 10, "restrictive": False, "user_rule": False},
|
||||
{"topic": "campaign", "text": "Never refuse to verify campaign text",
|
||||
"words": sorted({"verify", "campaign", "text"}),
|
||||
"core": "verify campaign accuracy",
|
||||
"priority": 5, "restrictive": True, "user_rule": True},
|
||||
{"topic": "gaming", "text": "Guard the live game environment",
|
||||
"words": sorted({"guard", "live", "game", "environment"}),
|
||||
"core": "guard live game foundry environment",
|
||||
"priority": 8, "restrictive": False, "user_rule": False},
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
print("=== cognition_core persona kernel (W3.2) ===")
|
||||
r = build()
|
||||
check("crate still builds", r.returncode == 0, r.stderr[-240:])
|
||||
if r.returncode:
|
||||
print(f"RESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1
|
||||
|
||||
from rune import persona_gate as pg
|
||||
from rune import cc_loader
|
||||
|
||||
# ── _lex parity: stoplist, stem, acronyms ─────────────────────────────
|
||||
lex_cases = ["Always maintain the Rune memory hierarchy.",
|
||||
"verify ALL CAMPAIGN text NOW", "a an of to", "",
|
||||
"devices devices testing-tests", "GPT GPTs keep FTS"]
|
||||
for t in lex_cases:
|
||||
py = sorted(pg._py_lex(t))
|
||||
rs = sorted(cc_loader.persona_lex(t))
|
||||
check(f"lex {t[:30]!r}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
# ── _overlap parity ───────────────────────────────────────────────────
|
||||
cases = [({"a", "b"}, {"b", "c"}), (set(), {"x"}), ({"a"}, set()),
|
||||
({"a", "b"}, {"a", "b"}), ({"a", "b", "c"}, {"a"})]
|
||||
for a, b in cases:
|
||||
py = pg._py_overlap(a, b)
|
||||
rs = cc_loader.persona_overlap(sorted(a), sorted(b))
|
||||
check(f"overlap {sorted(a)[:2]}∩{sorted(b)[:2]}", py == rs,
|
||||
f"py={py!r} rs={rs!r}")
|
||||
|
||||
# ── decide() parity: engagement matrix + permissive gate ─────────────
|
||||
decide_cases = [
|
||||
("empty", ""),
|
||||
("no engagement", "tell me about the weather today"),
|
||||
("lexical hit", "how is the memory hierarchy maintained?"),
|
||||
("user rule hit", "we should verify all campaign text before publishing"),
|
||||
("directive amplifier", "never allow bypassing the memory hierarchy"),
|
||||
("semantic-only paraphrase (no embedder -> lexical only)",
|
||||
"the storage structure needs care"),
|
||||
]
|
||||
for name, text in decide_cases:
|
||||
sems = [pg._semantic_engagement(text, r) for r in RULES]
|
||||
py = pg._py_decide(text, RULES)
|
||||
rs = cc_loader.persona_decide(text, RULES, True, sems)
|
||||
check(f"decide {name}", py == rs,
|
||||
f"py={json.dumps(py, sort_keys=True)[:150]} rs={json.dumps(rs, sort_keys=True)[:150]}")
|
||||
|
||||
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1 if FAIL else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,397 @@
|
||||
//! context_broker deterministic kernel (R2 W3.1 parity port).
|
||||
//! Pure functions; the clock/env gate arrives via inputs (no-clock law).
|
||||
|
||||
use crate::pyjson::Json;
|
||||
|
||||
pub fn default_estimator(text: &str) -> i64 {
|
||||
(text.chars().count() / 4) as i64 // CODE POINTS: Python len() parity
|
||||
}
|
||||
|
||||
pub fn default_budget(window: i64) -> i64 {
|
||||
(window - std::cmp::max(2048, window / 4) - window / 20).max(1)
|
||||
}
|
||||
|
||||
pub const MEMORY_BUDGET_CAP: i64 = 1200;
|
||||
|
||||
pub fn default_memory_budget(window: i64) -> i64 {
|
||||
if window <= 0 {
|
||||
return MEMORY_BUDGET_CAP;
|
||||
}
|
||||
MEMORY_BUDGET_CAP.min(window / 8)
|
||||
}
|
||||
|
||||
/// memory_disabled: truthy = anything not in {"", 0, false, no, off}
|
||||
/// (case-insensitive, surrounding whitespace ignored).
|
||||
pub fn memory_disabled(value: Option<&str>) -> bool {
|
||||
let raw = value.unwrap_or("").trim().to_lowercase();
|
||||
!(raw.is_empty() || matches!(raw.as_str(), "0" | "false" | "no" | "off"))
|
||||
}
|
||||
|
||||
// ── persona gate kernels (W3.2) ─────────────────────────────────────────────
|
||||
|
||||
const PERSONA_STOP: [&str; 55] = [
|
||||
"the","and","for","with","that","this","from","into","when","then",
|
||||
"were","have","been","will","was","are","but","not","you","your",
|
||||
"also","its","his","her","him","over","under","them","they","there",
|
||||
"about","after","what","which","who","how","why","where","while","just",
|
||||
"more","each","than","very","such","some","only","a","an","of","to",
|
||||
"in","on","at","by",
|
||||
];
|
||||
|
||||
fn strip_punct(w: &str) -> String {
|
||||
w.trim_matches(|c: char| ".,;:!?()[]{}\"'".contains(c)).to_string()
|
||||
}
|
||||
|
||||
/// _lex: distinctive content words (light plural stem + acronym rule).
|
||||
/// The acronym rule: 3+ char ALL-CAPS alpha survives the stem+stop filter.
|
||||
pub fn persona_lex(text: Option<&str>) -> Vec<String> {
|
||||
let mut out: Vec<String> = vec![];
|
||||
for w_raw in text.unwrap_or("").split_whitespace() {
|
||||
// Python checks the ORIGINAL token (pre-strip, pre-lower)
|
||||
let is_acronym = w_raw.len() >= 3 && w_raw == w_raw.to_uppercase()
|
||||
&& w_raw.chars().all(|c| c.is_ascii_alphabetic())
|
||||
&& w_raw.chars().any(|c| c.is_uppercase());
|
||||
let mut w = strip_punct(w_raw).to_lowercase();
|
||||
if w.chars().count() > 4 && w.ends_with('s') {
|
||||
w.pop();
|
||||
}
|
||||
if is_acronym {
|
||||
if !out.contains(&w) { out.push(w); }
|
||||
} else if w.chars().count() > 3 && !PERSONA_STOP.contains(&w.as_str()) {
|
||||
if !out.contains(&w) { out.push(w); }
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// _overlap: |A∩B| / max(1, min(|A|,|B|)) over UNIQUE word sets.
|
||||
pub fn persona_overlap(a: &[String], b: &[String]) -> f64 {
|
||||
let au: Vec<&str> = a.iter().map(|x| x.as_str()).collect();
|
||||
let bu: Vec<&str> = b.iter().map(|x| x.as_str()).collect();
|
||||
if au.is_empty() || bu.is_empty() { return 0.0; }
|
||||
let inter = au.iter().filter(|w| bu.contains(w)).count();
|
||||
(inter as f64 / std::cmp::max(1u64, std::cmp::min(au.len(), bu.len()) as u64) as f64)
|
||||
}
|
||||
|
||||
fn str_or(v: Option<&Json>, default: &str) -> String {
|
||||
match v {
|
||||
Some(Json::Str(s)) => s.clone(),
|
||||
_ => default.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn round_n(v: f64, n: i32) -> f64 {
|
||||
let p = 10f64.powi(n); (v * p).round_ties_even() / p
|
||||
}
|
||||
|
||||
fn obj_pairs(v: &Json) -> &[(String, Json)] {
|
||||
match v { Json::Obj(p) => p, _ => &[] }
|
||||
}
|
||||
fn get<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
|
||||
obj_pairs(v).iter().find(|(k, _)| k == key).map(|(_, v)| v)
|
||||
}
|
||||
fn as_bool(v: Option<&Json>) -> bool {
|
||||
matches!(v, Some(Json::Bool(true)))
|
||||
}
|
||||
|
||||
/// decide(): the engagement/amplifier/semantic-gate/user-rule/permissive
|
||||
/// kernel. `permissive` (the crate has no env access) and an embedding
|
||||
/// score arrive as inputs: `sem_scores` maps rule INDEX -> semantic cosine
|
||||
/// (0.0 when the embedder is down — the gate then trusts lexical alone).
|
||||
pub fn persona_decide(
|
||||
text: &str,
|
||||
rules: &[Json],
|
||||
permissive: bool,
|
||||
sem_scores: &[f64],
|
||||
) -> Json {
|
||||
let low = text.trim().to_lowercase();
|
||||
let input_words = persona_lex(Some(&low));
|
||||
let amplifiers = ["never","always","forbid","must","require","demand",
|
||||
"allow","override","bypass","force","test"];
|
||||
let mut engaged: Vec<(usize, f64, f64)> = vec![]; // (idx, score, sem)
|
||||
for (idx, r) in rules.iter().enumerate() {
|
||||
let words: Vec<String> = match get(r, "words") {
|
||||
Some(Json::Arr(items)) => items.iter().filter_map(|x| match x {
|
||||
Json::Str(s) => Some(s.clone()), _ => None }).collect(),
|
||||
_ => vec![],
|
||||
};
|
||||
let iw: Vec<String> = input_words.iter().cloned().collect();
|
||||
let ov = persona_overlap(&iw, &words);
|
||||
let sem = sem_scores.get(idx).copied().unwrap_or(0.0);
|
||||
let amp: f64 = if amplifiers.iter().any(|m| low.contains(m)) { 0.1 } else { 0.0 };
|
||||
let user_rule = as_bool(get(r, "user_rule"));
|
||||
let score;
|
||||
if sem >= 0.45 {
|
||||
if ov > 0.0 {
|
||||
score = (ov + amp).max(sem);
|
||||
} else if sem >= 0.68 {
|
||||
score = 0.5f64.max(sem);
|
||||
} else {
|
||||
score = ov + amp;
|
||||
}
|
||||
} else if ov > 0.0 && sem >= 0.30 {
|
||||
score = (ov + amp).max(sem);
|
||||
} else {
|
||||
score = ov + amp;
|
||||
}
|
||||
let score = if user_rule && ov > 0.0 { score.max(0.4) } else { score };
|
||||
if score >= 0.35 {
|
||||
engaged.push((idx, score, sem));
|
||||
}
|
||||
}
|
||||
if engaged.is_empty() {
|
||||
return Json::Obj(vec![
|
||||
("verdict".into(), Json::Str("allow".into())),
|
||||
("reason".into(), Json::Str("no persona rule engaged".into())),
|
||||
("engaged".into(), Json::Arr(vec![])),
|
||||
("cited".into(), Json::Null),
|
||||
]);
|
||||
}
|
||||
engaged.sort_by(|a, b| {
|
||||
b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal)
|
||||
.then_with(|| {
|
||||
let pa = get(&rules[a.0], "priority").and_then(|x| match x { Json::Num(n) => Some(*n), _ => None }).unwrap_or(0.0);
|
||||
let pb = get(&rules[b.0], "priority").and_then(|x| match x { Json::Num(n) => Some(*n), _ => None }).unwrap_or(0.0);
|
||||
pa.partial_cmp(&pb).unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
});
|
||||
let engaged_view = |items: &[(usize, f64, f64)]| Json::Arr(items.iter().take(4).map(|(idx, score, _)| {
|
||||
let r = &rules[*idx];
|
||||
Json::Obj(vec![
|
||||
("rule".into(), Json::Str(str_or(get(r, "text"), "").chars().take(120).collect())),
|
||||
("score".into(), Json::Num(round_n(*score, 2))),
|
||||
("restrictive".into(), Json::Bool(as_bool(get(r, "restrictive")))),
|
||||
("user_rule".into(), Json::Bool(as_bool(get(r, "user_rule")))),
|
||||
])
|
||||
}).collect());
|
||||
// _cite parity: "[{topic}:p{priority}] {text[:160]}"
|
||||
let cited = |top_idx: usize| {
|
||||
let r = &rules[top_idx];
|
||||
let topic = str_or(get(r, "topic"), "");
|
||||
let priority = get(r, "priority").and_then(|x| match x {
|
||||
Json::Num(n) => Some(*n as i64), _ => None }).unwrap_or(0);
|
||||
let t = str_or(get(r, "text"), "").chars().take(160).collect::<String>();
|
||||
Json::Str(format!("[{}:p{}] {}", topic, priority, t))
|
||||
};
|
||||
if permissive {
|
||||
let top = engaged[0].0;
|
||||
return Json::Obj(vec![
|
||||
("verdict".into(), Json::Str("allow".into())),
|
||||
("reason".into(), Json::Str(format!(
|
||||
"permissive mode — rule engaged: {}", str_or(get(&rules[top], "text"), "").chars().take(120).collect::<String>()))),
|
||||
("engaged".into(), engaged_view(&engaged)),
|
||||
("cited".into(), cited(top)),
|
||||
]);
|
||||
}
|
||||
let restrictive: Vec<(usize, f64, f64)> = engaged.iter().copied()
|
||||
.filter(|(idx, _, _)| as_bool(get(&rules[*idx], "restrictive"))).collect();
|
||||
if !restrictive.is_empty() {
|
||||
let user_rest: Vec<(usize, f64, f64)> = restrictive.clone().into_iter()
|
||||
.filter(|(idx, _, _)| as_bool(get(&rules[*idx], "user_rule"))).collect();
|
||||
let top = (if !user_rest.is_empty() { user_rest[0] } else { restrictive[0] }).0;
|
||||
return Json::Obj(vec![
|
||||
("verdict".into(), Json::Str("refuse".into())),
|
||||
("reason".into(), Json::Str(format!(
|
||||
"the persona's own boundary rule engages: {}",
|
||||
str_or(get(&rules[top], "text"), "").chars().take(120).collect::<String>()))),
|
||||
("engaged".into(), engaged_view(&restrictive)),
|
||||
("cited".into(), cited(top)),
|
||||
]);
|
||||
}
|
||||
let top = engaged[0].0;
|
||||
Json::Obj(vec![
|
||||
("verdict".into(), Json::Str("allow".into())),
|
||||
("reason".into(), Json::Str(format!(
|
||||
"persona rule engaged but permissive: {}",
|
||||
str_or(get(&rules[top], "text"), "").chars().take(120).collect::<String>()))),
|
||||
("engaged".into(), engaged_view(&engaged)),
|
||||
("cited".into(), cited(top)),
|
||||
])
|
||||
}
|
||||
|
||||
// ── identity_anchors kernels (W3.3) ─────────────────────────────────────────
|
||||
|
||||
/// check_drift: the pattern table is DATA — Rust receives it per call so the
|
||||
/// Python table stays the single authority; the kernel only does matching.
|
||||
pub fn drift_check(text: &str, patterns: &[Json]) -> Vec<String> {
|
||||
let low = text.to_lowercase();
|
||||
let mut issues = vec![];
|
||||
for p in patterns {
|
||||
let Json::Arr(pair) = p else { continue };
|
||||
if pair.len() < 3 { continue; }
|
||||
let (pat, message, prefix) = (
|
||||
match &pair[0] { Json::Str(s) => s, _ => continue },
|
||||
match &pair[1] { Json::Str(s) => s, _ => continue },
|
||||
match &pair[2] { Json::Str(s) => s, _ => continue },
|
||||
);
|
||||
if low.contains(pat) {
|
||||
issues.push(format!("{}: '{}' — {}", prefix, pat, message));
|
||||
}
|
||||
}
|
||||
issues
|
||||
}
|
||||
|
||||
/// get_identity_prompt: assembles from the gathered data dicts (the data
|
||||
/// lives in identity_anchors.py — the kernel is the ASSEMBLY, not the data).
|
||||
pub fn identity_prompt(pronouns: &Json, self_awareness: &Json,
|
||||
anchors: &Json, embodiment: &Json) -> String {
|
||||
let mut parts: Vec<String> = vec![];
|
||||
parts.push("## Pronouns (CRITICAL)".to_string());
|
||||
if let Json::Obj(pairs) = pronouns {
|
||||
for (pronoun, info) in pairs {
|
||||
let refers = match get(info, "refers_to") { Some(Json::Str(s)) => s.clone(), _ => String::new() };
|
||||
parts.push(format!("- '{}' → {}", pronoun, refers));
|
||||
}
|
||||
}
|
||||
parts.push(String::new());
|
||||
parts.push("## Self-Awareness".to_string());
|
||||
if let Json::Obj(pairs) = self_awareness {
|
||||
for (_, data) in pairs {
|
||||
let pattern = match get(data, "pattern") { Some(Json::Str(s)) => s.clone(), _ => String::new() };
|
||||
parts.push(format!("- {}", pattern));
|
||||
}
|
||||
}
|
||||
parts.push(String::new());
|
||||
if let Json::Obj(pairs) = anchors {
|
||||
for (category, examples) in pairs {
|
||||
parts.push(format!("## {}", {
|
||||
let mut c = category.clone();
|
||||
let mut t = c.chars();
|
||||
match t.next() {
|
||||
Some(f) => f.to_uppercase().collect::<String>() + t.as_str(),
|
||||
None => c,
|
||||
}
|
||||
}));
|
||||
if let Json::Arr(items) = examples {
|
||||
for ex in items.iter().take(2) {
|
||||
if let Json::Str(s) = ex { parts.push(format!(" - {}", s)); }
|
||||
}
|
||||
}
|
||||
parts.push(String::new());
|
||||
}
|
||||
}
|
||||
parts.push("## Embodiment Rules".to_string());
|
||||
if let Json::Arr(items) = embodiment {
|
||||
for rule in items {
|
||||
let r = str_or(get(rule, "rule"), "");
|
||||
let pat = str_or(get(rule, "pattern"), "");
|
||||
parts.push(format!("- {}: {}", r, pat));
|
||||
}
|
||||
}
|
||||
parts.push(String::new());
|
||||
parts.join("\n")
|
||||
}
|
||||
|
||||
// ── growth_delta kernels (W3.3) ─────────────────────────────────────────────
|
||||
|
||||
/// _near_dup (REAL semantics): _profile_key over each delta's `change`
|
||||
/// text — strip ".,;:!?()[]{}\"'" then lowercase, keep words >4 chars —
|
||||
/// near when |A∩B| / max(|A|,|B|) >= 0.25 (measured split: same-guidance
|
||||
/// ~0.30, distinct ~0.00).
|
||||
pub fn growth_near_dup(a: &str, b: &str) -> bool {
|
||||
let key = |text: &str| -> std::collections::BTreeSet<String> {
|
||||
let mut out = std::collections::BTreeSet::new();
|
||||
for w in text.split_whitespace() {
|
||||
let w = w.trim_matches(|c: char| ".,;:!?()[]{}\"'".contains(c))
|
||||
.to_lowercase();
|
||||
if w.chars().count() > 4 {
|
||||
out.insert(w);
|
||||
}
|
||||
}
|
||||
out
|
||||
};
|
||||
let (ka, kb) = (key(a), key(b));
|
||||
if ka.is_empty() || kb.is_empty() { return false; }
|
||||
let inter = ka.intersection(&kb).count() as f64;
|
||||
(inter / ka.len().max(kb.len()) as f64) >= 0.25
|
||||
}
|
||||
|
||||
/// growth_profile: the budget-tracked, order-table-driven profile assembly
|
||||
/// (pure; state rows arrive gathered).
|
||||
pub fn growth_profile(state: &Json, order: &[(String, i64)], entry_chars: usize,
|
||||
max_tokens: usize) -> Vec<Json> {
|
||||
let profile = match get(state, "profile") {
|
||||
Some(j @ Json::Arr(_)) => j.clone(),
|
||||
_ => match get(state, "applied") {
|
||||
Some(Json::Arr(items)) => {
|
||||
let start = items.len().saturating_sub(5);
|
||||
Json::Arr(items[start..].to_vec())
|
||||
}
|
||||
_ => Json::Arr(vec![]),
|
||||
}};
|
||||
if let Json::Arr(items) = &profile {
|
||||
if items.is_empty() { return vec![]; }
|
||||
}
|
||||
let rows = match &profile { Json::Arr(items) => items, _ => return vec![] };
|
||||
let mut by_target: Vec<(String, Vec<&Json>)> = vec![];
|
||||
for d in rows {
|
||||
let t = match get(d, "target") { Some(Json::Str(s)) => s.clone(), _ => "delivery".to_string() };
|
||||
match by_target.iter_mut().find(|(k, _)| k == &t) {
|
||||
Some((_, v)) => v.push(d),
|
||||
None => by_target.push((t, vec![d])),
|
||||
}
|
||||
}
|
||||
let mut target_order: Vec<(String, i64)> = by_target.iter()
|
||||
.map(|(t, _)| (t.clone(),
|
||||
order.iter().find(|(name, _)| name == t).map(|(_, r)| *r).unwrap_or(9)))
|
||||
.collect();
|
||||
target_order.sort_by(|a, b| a.1.cmp(&b.1));
|
||||
let mut ordered: Vec<&Json> = vec![];
|
||||
for (t, _) in target_order {
|
||||
let list = by_target.iter().find(|(k, _)| k == &t).map(|(_, v)| v).unwrap();
|
||||
for d in list.iter().rev().take(2).rev().cloned() { ordered.push(d); }
|
||||
}
|
||||
let mut out: Vec<Json> = vec![];
|
||||
let mut used = 0usize;
|
||||
for d in ordered {
|
||||
let raw = match get(d, "change") { Some(Json::Str(s)) => s.clone(), _ => String::new() };
|
||||
let mut change = raw.trim().replace('\n', " ");
|
||||
if change.chars().count() > entry_chars {
|
||||
change = change.chars().take(entry_chars.saturating_sub(1)).collect::<String>();
|
||||
while change.ends_with(' ') { change.pop(); }
|
||||
change.push('…');
|
||||
}
|
||||
let tok = std::cmp::max(1, change.chars().count() / 4);
|
||||
if used + tok > max_tokens { break; }
|
||||
used += tok;
|
||||
out.push(Json::Obj(vec![
|
||||
("change".into(), Json::Str(change)),
|
||||
("target".into(), Json::Str(match get(d, "target") {
|
||||
Some(Json::Str(s)) => s.clone(), _ => "delivery".to_string() })),
|
||||
]));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
// ── pins kernel (W3.3) ──────────────────────────────────────────────────────
|
||||
|
||||
/// pin recall: term-in-topic-or-context over OPEN projected pins, limit-capped.
|
||||
pub fn pins_recall(pins: &[Json], term: &str, limit: usize) -> Vec<Json> {
|
||||
let term_l = term.trim().to_lowercase();
|
||||
if term_l.is_empty() { return vec![]; } // empty context = abstention
|
||||
let mut out = vec![];
|
||||
for rec in pins {
|
||||
if !matches!(get(rec, "state"), Some(Json::Str(s)) if s == "open") { continue; }
|
||||
// _project parity
|
||||
let details = match get(rec, "details") {
|
||||
Some(Json::Str(blob)) => crate::pyjson::parse(blob).ok()
|
||||
.unwrap_or(Json::Obj(vec![])),
|
||||
_ => Json::Obj(vec![]),
|
||||
};
|
||||
let projected = Json::Obj(vec![
|
||||
("topic".into(), get(rec, "item_id").cloned().unwrap_or(Json::Str(String::new()))),
|
||||
("question".into(), get(&details, "question").cloned().unwrap_or(Json::Str(String::new()))),
|
||||
("outcome".into(), get(&details, "outcome").cloned().unwrap_or(Json::Str(String::new()))),
|
||||
("context".into(), get(&details, "context").cloned().unwrap_or(Json::Str(String::new()))),
|
||||
("status".into(), get(rec, "state").cloned().unwrap_or(Json::Str(String::new()))),
|
||||
("reason".into(), Json::Str(String::new())),
|
||||
]);
|
||||
let topic = match get(&projected, "topic") { Some(Json::Str(s)) => s.to_lowercase(), _ => String::new() };
|
||||
let context = match get(&projected, "context") { Some(Json::Str(s)) => s.to_lowercase(), _ => String::new() };
|
||||
if topic.contains(&term_l) || context.contains(&term_l) {
|
||||
out.push(projected);
|
||||
if out.len() >= limit { break; }
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
//! lib.rs — FFI surface for the cognition_core crate (R2 W3.1).
|
||||
//! Pure deterministic kernels only. Envelope law
|
||||
//! {"ok","value"|"err"}; frees via cc_free_string. FFI segfault law:
|
||||
//! cc_loader.py pins argtypes + restype for every symbol.
|
||||
|
||||
pub mod broker;
|
||||
pub mod pyjson;
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::c_char;
|
||||
|
||||
fn read_arg(ptr: *const c_char) -> Result<String, String> {
|
||||
if ptr.is_null() { return Err("null argument pointer".to_string()); }
|
||||
unsafe { CStr::from_ptr(ptr) }.to_str().map(|s| s.to_string())
|
||||
.map_err(|e| format!("argument is not valid UTF-8: {}", e))
|
||||
}
|
||||
|
||||
fn envelope(result: Result<pyjson::Json, String>) -> *mut c_char {
|
||||
let body = match result {
|
||||
Ok(v) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(true)),
|
||||
("value".to_string(), v)]),
|
||||
Err(e) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(false)),
|
||||
("err".to_string(), pyjson::Json::Str(e))]),
|
||||
};
|
||||
CString::new(pyjson::dumps(&body)).map(|c| c.into_raw())
|
||||
.unwrap_or(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
fn arg_json(text: &str) -> Result<pyjson::Json, String> {
|
||||
pyjson::parse(text).map_err(|e| format!("argument JSON parse failed: {}", e))
|
||||
}
|
||||
|
||||
fn get<'a>(v: &'a pyjson::Json, key: &str) -> Option<&'a pyjson::Json> {
|
||||
match v { pyjson::Json::Obj(p) => p.iter().find(|(k, _)| k == key).map(|(_, v)| v), _ => None }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_default_estimator(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let val = match get(&a, "text") {
|
||||
Some(pyjson::Json::Str(s)) => s.clone(),
|
||||
_ => String::new(),
|
||||
};
|
||||
pyjson::Json::Num(broker::default_estimator(&val) as f64)
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_default_budget(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let w = match get(&a, "window") { Some(pyjson::Json::Num(n)) => *n as i64, _ => 0 };
|
||||
pyjson::Json::Num(broker::default_budget(w) as f64)
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_default_memory_budget(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let w = match get(&a, "window") {
|
||||
Some(pyjson::Json::Num(n)) => *n as i64,
|
||||
Some(pyjson::Json::Null) | None => 0,
|
||||
_ => 0,
|
||||
};
|
||||
pyjson::Json::Num(broker::default_memory_budget(w) as f64)
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_memory_disabled(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let v = match get(&a, "value") {
|
||||
Some(pyjson::Json::Str(s)) => Some(s.as_str()),
|
||||
_ => None,
|
||||
};
|
||||
pyjson::Json::Bool(broker::memory_disabled(v))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_persona_lex(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let t = match get(&a, "text") { Some(pyjson::Json::Str(x)) => Some(x.as_str()), _ => None };
|
||||
pyjson::Json::Arr(broker::persona_lex(t).into_iter().map(pyjson::Json::Str).collect())
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_persona_overlap(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let wa: Vec<String> = match get(&a, "a") { Some(pyjson::Json::Arr(x)) => x.iter().filter_map(|v| match v { pyjson::Json::Str(s) => Some(s.clone()), _ => None }).collect(), _ => vec![] };
|
||||
let wb: Vec<String> = match get(&a, "b") { Some(pyjson::Json::Arr(x)) => x.iter().filter_map(|v| match v { pyjson::Json::Str(s) => Some(s.clone()), _ => None }).collect(), _ => vec![] };
|
||||
pyjson::Json::Num(broker::persona_overlap(&wa, &wb))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_persona_decide(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).and_then(|a| {
|
||||
let text = match get(&a, "text") { Some(pyjson::Json::Str(x)) => x.clone(), _ => String::new() };
|
||||
let rules: Vec<pyjson::Json> = match get(&a, "rules") { Some(pyjson::Json::Arr(x)) => x.clone(), _ => vec![] };
|
||||
let permissive = matches!(get(&a, "permissive"), Some(pyjson::Json::Bool(true)));
|
||||
let sems: Vec<f64> = match get(&a, "sem_scores") {
|
||||
Some(pyjson::Json::Arr(x)) => x.iter().filter_map(|v| match v { pyjson::Json::Num(n) => Some(*n), _ => Some(0.0) }).collect(),
|
||||
_ => vec![0.0; rules.len()],
|
||||
};
|
||||
Ok(broker::persona_decide(&text, &rules, permissive, &sems))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_drift_check(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let text = match get(&a, "text") { Some(pyjson::Json::Str(s)) => s.clone(), _ => String::new() };
|
||||
let patterns: Vec<pyjson::Json> = match get(&a, "patterns") {
|
||||
Some(pyjson::Json::Arr(x)) => x.clone(), _ => vec![] };
|
||||
pyjson::Json::Arr(broker::drift_check(&text, &patterns)
|
||||
.into_iter().map(pyjson::Json::Str).collect())
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_identity_prompt(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
pyjson::Json::Str(broker::identity_prompt(
|
||||
get(&a, "pronouns").unwrap_or(&pyjson::Json::Obj(vec![])),
|
||||
get(&a, "self_awareness").unwrap_or(&pyjson::Json::Obj(vec![])),
|
||||
get(&a, "anchors").unwrap_or(&pyjson::Json::Obj(vec![])),
|
||||
get(&a, "embodiment").unwrap_or(&pyjson::Json::Arr(vec![]))))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_growth_near_dup(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let x = match get(&a, "a") { Some(pyjson::Json::Str(s)) => s.clone(), _ => String::new() };
|
||||
let y = match get(&a, "b") { Some(pyjson::Json::Str(s)) => s.clone(), _ => String::new() };
|
||||
pyjson::Json::Bool(broker::growth_near_dup(&x, &y))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_growth_profile(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).and_then(|a| {
|
||||
let state = get(&a, "state").cloned().unwrap_or(pyjson::Json::Obj(vec![]));
|
||||
let entry_chars = match get(&a, "entry_chars") { Some(pyjson::Json::Num(n)) => *n as usize, _ => 0 };
|
||||
let max_tokens = match get(&a, "max_tokens") { Some(pyjson::Json::Num(n)) => *n as usize, _ => 0 };
|
||||
let order: Vec<(String, i64)> = match get(&a, "order") {
|
||||
Some(pyjson::Json::Arr(x)) => x.iter().filter_map(|v| match v {
|
||||
pyjson::Json::Arr(pair) if pair.len() >= 2 => match (&pair[0], &pair[1]) {
|
||||
(pyjson::Json::Str(name), pyjson::Json::Num(rank)) => Some((name.clone(), *rank as i64)),
|
||||
_ => None },
|
||||
_ => None }).collect(),
|
||||
_ => vec![] };
|
||||
Ok(pyjson::Json::Arr(broker::growth_profile(&state, &order, entry_chars, max_tokens)))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_pins_recall(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|t| arg_json(&t)).map(|a| {
|
||||
let pins: Vec<pyjson::Json> = match get(&a, "pins") {
|
||||
Some(pyjson::Json::Arr(x)) => x.clone(), _ => vec![] };
|
||||
let term = match get(&a, "term") { Some(pyjson::Json::Str(s)) => s.clone(), _ => String::new() };
|
||||
pyjson::Json::Arr(broker::pins_recall(&pins, &term, 4))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() { unsafe { let _ = CString::from_raw(ptr); } }
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//! main.rs — CLI debug front for cognition_core.
|
||||
use cognition_core::{broker, pyjson};
|
||||
use std::io::Read;
|
||||
|
||||
fn get<'a>(v: &'a pyjson::Json, k: &str) -> Option<&'a pyjson::Json> {
|
||||
match v { pyjson::Json::Obj(p) => p.iter().find(|(x, _)| x == k).map(|(_, v)| v), _ => None }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x = String::new();
|
||||
if std::io::stdin().read_to_string(&mut x).is_err() { return; }
|
||||
let a = pyjson::parse(&x).unwrap();
|
||||
let op = match get(&a, "op") { Some(pyjson::Json::Str(s)) => s.as_str(), _ => "" };
|
||||
let arg = get(&a, "arg").unwrap_or(&pyjson::Json::Null);
|
||||
let v = match op {
|
||||
"default_estimator" => {
|
||||
let t = match get(arg, "text") { Some(pyjson::Json::Str(s)) => s.clone(), _ => String::new() };
|
||||
pyjson::Json::Num(broker::default_estimator(&t) as f64)
|
||||
}
|
||||
_ => pyjson::Json::Str(format!("unsupported op: {}", op)),
|
||||
};
|
||||
println!("{}", pyjson::dumps(&v));
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
//! json_min.py — minimal JSON parse/serialize with Python-parity output.
|
||||
//!
|
||||
//! Exists because contract C1 demands byte-comparable state files with the
|
||||
//! Python implementation (`json.dumps` / `json.dump(indent=2)`):
|
||||
//! - compact separators: ", " between items, ": " between key/value
|
||||
//! (Python json.dumps DEFAULTS — no separators arg means the space-y form)
|
||||
//! - ensure_ascii: non-ASCII escaped as \uXXXX (with surrogate pairs)
|
||||
//! - floats: shortest round-trip repr (Rust `{}` == Python `repr` for f64
|
||||
//! in every value this module produces, including arithmetic artifacts
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
/// Preserved-order JSON value.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Json {
|
||||
Null,
|
||||
Bool(bool),
|
||||
Num(f64),
|
||||
Str(String),
|
||||
Arr(Vec<Json>),
|
||||
Obj(Vec<(String, Json)>),
|
||||
}
|
||||
|
||||
impl Json {
|
||||
pub fn get(&self, key: &str) -> Option<&Json> {
|
||||
match self {
|
||||
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── parsing ─────────────────────────────────────────────────────────────────
|
||||
|
||||
pub fn parse(input: &str) -> Result<Json, String> {
|
||||
let bytes = input.as_bytes();
|
||||
let mut p = Parser { b: bytes, i: 0 };
|
||||
p.skip_ws();
|
||||
let v = p.value()?;
|
||||
p.skip_ws();
|
||||
if p.i != bytes.len() {
|
||||
return Err(format!("trailing data at byte {}", p.i));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
b: &'a [u8],
|
||||
i: usize,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn skip_ws(&mut self) {
|
||||
while self.i < self.b.len() && matches!(self.b[self.i], b' ' | b'\t' | b'\n' | b'\r') {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn peek(&self) -> Option<u8> {
|
||||
self.b.get(self.i).copied()
|
||||
}
|
||||
|
||||
fn expect(&mut self, c: u8) -> Result<(), String> {
|
||||
if self.peek() == Some(c) {
|
||||
self.i += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("expected '{}' at byte {}", c as char, self.i))
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self) -> Result<Json, String> {
|
||||
match self.peek() {
|
||||
Some(b'{') => self.object(),
|
||||
Some(b'[') => self.array(),
|
||||
Some(b'"') => Ok(Json::Str(self.string()?)),
|
||||
Some(b't') => self.literal("true", Json::Bool(true)),
|
||||
Some(b'f') => self.literal("false", Json::Bool(false)),
|
||||
Some(b'n') => self.literal("null", Json::Null),
|
||||
Some(c) if c == b'-' || c.is_ascii_digit() => self.number(),
|
||||
_ => Err(format!("unexpected byte at {}", self.i)),
|
||||
}
|
||||
}
|
||||
|
||||
fn literal(&mut self, lit: &str, v: Json) -> Result<Json, String> {
|
||||
if self.b[self.i..].starts_with(lit.as_bytes()) {
|
||||
self.i += lit.len();
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(format!("bad literal at byte {}", self.i))
|
||||
}
|
||||
}
|
||||
|
||||
fn object(&mut self) -> Result<Json, String> {
|
||||
self.expect(b'{')?;
|
||||
let mut pairs = Vec::new();
|
||||
self.skip_ws();
|
||||
if self.peek() == Some(b'}') {
|
||||
self.i += 1;
|
||||
return Ok(Json::Obj(pairs));
|
||||
}
|
||||
loop {
|
||||
self.skip_ws();
|
||||
let key = self.string()?;
|
||||
self.skip_ws();
|
||||
self.expect(b':')?;
|
||||
self.skip_ws();
|
||||
let val = self.value()?;
|
||||
pairs.push((key, val));
|
||||
self.skip_ws();
|
||||
match self.peek() {
|
||||
Some(b',') => self.i += 1,
|
||||
Some(b'}') => {
|
||||
self.i += 1;
|
||||
return Ok(Json::Obj(pairs));
|
||||
}
|
||||
_ => return Err(format!("expected ',' or '}}' at byte {}", self.i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn array(&mut self) -> Result<Json, String> {
|
||||
self.expect(b'[')?;
|
||||
let mut items = Vec::new();
|
||||
self.skip_ws();
|
||||
if self.peek() == Some(b']') {
|
||||
self.i += 1;
|
||||
return Ok(Json::Arr(items));
|
||||
}
|
||||
loop {
|
||||
self.skip_ws();
|
||||
items.push(self.value()?);
|
||||
self.skip_ws();
|
||||
match self.peek() {
|
||||
Some(b',') => self.i += 1,
|
||||
Some(b']') => {
|
||||
self.i += 1;
|
||||
return Ok(Json::Arr(items));
|
||||
}
|
||||
_ => return Err(format!("expected ',' or ']' at byte {}", self.i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn string(&mut self) -> Result<String, String> {
|
||||
self.expect(b'"')?;
|
||||
let mut out = String::new();
|
||||
loop {
|
||||
match self.peek() {
|
||||
None => return Err("unterminated string".into()),
|
||||
Some(b'"') => {
|
||||
self.i += 1;
|
||||
return Ok(out);
|
||||
}
|
||||
Some(b'\\') => {
|
||||
self.i += 1;
|
||||
match self.peek() {
|
||||
Some(b'"') => out.push('"'),
|
||||
Some(b'\\') => out.push('\\'),
|
||||
Some(b'/') => out.push('/'),
|
||||
Some(b'b') => out.push('\u{0008}'),
|
||||
Some(b'f') => out.push('\u{000C}'),
|
||||
Some(b'n') => out.push('\n'),
|
||||
Some(b'r') => out.push('\r'),
|
||||
Some(b't') => out.push('\t'),
|
||||
Some(b'u') => {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
+ ((cp - 0xD800) << 10)
|
||||
+ (lo - 0xDC00);
|
||||
out.push(
|
||||
char::from_u32(c)
|
||||
.ok_or("bad surrogate pair")?,
|
||||
);
|
||||
} else {
|
||||
// lone high surrogate — Python keeps it as
|
||||
// an escaped lone surrogate; we degrade to
|
||||
// U+FFFD (not produced by this writer)
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
} else {
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
} else {
|
||||
out.push(char::from_u32(cp).unwrap_or('\u{FFFD}'));
|
||||
}
|
||||
continue; // hex4 already advanced i
|
||||
}
|
||||
_ => return Err(format!("bad escape at byte {}", self.i)),
|
||||
}
|
||||
self.i += 1;
|
||||
}
|
||||
Some(_) => {
|
||||
// consume one UTF-8 scalar
|
||||
let s = &self.b[self.i..];
|
||||
let ch_len = utf8_len(s[0]);
|
||||
let chunk = std::str::from_utf8(&s[..ch_len.min(s.len())])
|
||||
.map_err(|_| "bad utf8")?;
|
||||
out.push_str(chunk);
|
||||
self.i += ch_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hex4(&mut self) -> Result<u32, String> {
|
||||
if self.i + 4 > self.b.len() {
|
||||
return Err("short \\u escape".into());
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[self.i + 1..self.i + 5])
|
||||
.map_err(|_| "bad \\u")?;
|
||||
let v = u32::from_str_radix(s, 16).map_err(|_| "bad \\u digits")?;
|
||||
self.i += 5; // 'u' + 4 hex digits (caller consumed the backslash)
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn number(&mut self) -> Result<Json, String> {
|
||||
let start = self.i;
|
||||
if self.peek() == Some(b'-') {
|
||||
self.i += 1;
|
||||
}
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
if self.peek() == Some(b'.') {
|
||||
self.i += 1;
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
if matches!(self.peek(), Some(b'e') | Some(b'E')) {
|
||||
self.i += 1;
|
||||
if matches!(self.peek(), Some(b'+') | Some(b'-')) {
|
||||
self.i += 1;
|
||||
}
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[start..self.i]).map_err(|_| "bad number")?;
|
||||
s.parse::<f64>()
|
||||
.map(Json::Num)
|
||||
.map_err(|_| format!("bad number '{}'", s))
|
||||
}
|
||||
}
|
||||
|
||||
fn utf8_len(b: u8) -> usize {
|
||||
if b < 0x80 {
|
||||
1
|
||||
} else if b >> 5 == 0b110 {
|
||||
2
|
||||
} else if b >> 4 == 0b1110 {
|
||||
3
|
||||
} else {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
// ── serialization (Python json.dumps / json.dump(indent=2) parity) ─────────
|
||||
|
||||
/// Python `json.dumps(value, sort_keys=True)` — compact separators, object
|
||||
/// keys recursively sorted. Python sorts str keys by code point; Rust's
|
||||
/// byte-wise UTF-8 `String` ordering is identical for valid UTF-8, so a
|
||||
/// plain `sort_by` on the key is faithful.
|
||||
pub fn dumps_sorted(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_compact_sorted(&mut out, v);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_compact_sorted(out: &mut String, v: &Json) {
|
||||
match v {
|
||||
Json::Obj(pairs) => {
|
||||
let mut sorted: Vec<&(String, Json)> = pairs.iter().collect();
|
||||
sorted.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
out.push('{');
|
||||
for (i, (k, val)) in sorted.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_compact_sorted(out, val);
|
||||
}
|
||||
out.push('}');
|
||||
}
|
||||
Json::Arr(items) => {
|
||||
out.push('[');
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_compact_sorted(out, item);
|
||||
}
|
||||
out.push(']');
|
||||
}
|
||||
other => write_compact(out, other),
|
||||
}
|
||||
}
|
||||
|
||||
/// Python `json.dumps(value)` — compact separators `", "` / `": "`,
|
||||
/// ensure_ascii escaping.
|
||||
pub fn dumps(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_compact(&mut out, v);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_compact(out: &mut String, v: &Json) {
|
||||
match v {
|
||||
Json::Null => out.push_str("null"),
|
||||
Json::Bool(true) => out.push_str("true"),
|
||||
Json::Bool(false) => out.push_str("false"),
|
||||
Json::Num(n) => out.push_str(&fmt_num(*n)),
|
||||
Json::Str(s) => write_escaped(out, s),
|
||||
Json::Arr(items) => {
|
||||
out.push('[');
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_compact(out, item);
|
||||
}
|
||||
out.push(']');
|
||||
}
|
||||
Json::Obj(pairs) => {
|
||||
out.push('{');
|
||||
for (i, (k, val)) in pairs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_compact(out, val);
|
||||
}
|
||||
out.push('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Python `json.dump(value, indent=2)` — item separator becomes
|
||||
/// `",\n<indent>"`, key separator `": "`, empty container → `{}` / `[]`,
|
||||
/// NO trailing newline.
|
||||
pub fn dump_indent2(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_indent(&mut out, v, 0);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_indent(out: &mut String, v: &Json, depth: usize) {
|
||||
match v {
|
||||
Json::Arr(items) if !items.is_empty() => {
|
||||
out.push_str("[\n");
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(",\n");
|
||||
}
|
||||
push_indent(out, depth + 1);
|
||||
write_indent(out, item, depth + 1);
|
||||
}
|
||||
out.push('\n');
|
||||
push_indent(out, depth);
|
||||
out.push(']');
|
||||
}
|
||||
Json::Arr(_) => out.push_str("[]"),
|
||||
Json::Obj(pairs) if !pairs.is_empty() => {
|
||||
out.push_str("{\n");
|
||||
for (i, (k, val)) in pairs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(",\n");
|
||||
}
|
||||
push_indent(out, depth + 1);
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_indent(out, val, depth + 1);
|
||||
}
|
||||
out.push('\n');
|
||||
push_indent(out, depth);
|
||||
out.push('}');
|
||||
}
|
||||
Json::Obj(_) => out.push_str("{}"),
|
||||
other => write_compact(out, other),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_indent(out: &mut String, depth: usize) {
|
||||
for _ in 0..depth {
|
||||
out.push_str(" ");
|
||||
}
|
||||
}
|
||||
|
||||
/// Integer-shaped f64 prints without a decimal point (matching how this
|
||||
/// module's writers emit counts); all other values use shortest round-trip.
|
||||
pub fn fmt_num(n: f64) -> String {
|
||||
if n.is_finite() && n.fract() == 0.0 && n.abs() < 9.007_199_254_740_992e15 {
|
||||
return format!("{}", n as i64);
|
||||
}
|
||||
format!("{}", n)
|
||||
}
|
||||
|
||||
/// Python `json.dumps` string escaping with ensure_ascii=True.
|
||||
pub fn write_escaped(out: &mut String, s: &str) {
|
||||
out.push('"');
|
||||
for ch in s.chars() {
|
||||
match ch {
|
||||
'"' => out.push_str("\\\""),
|
||||
'\\' => out.push_str("\\\\"),
|
||||
'\n' => out.push_str("\\n"),
|
||||
'\r' => out.push_str("\\r"),
|
||||
'\t' => out.push_str("\\t"),
|
||||
'\u{0008}' => out.push_str("\\b"),
|
||||
'\u{000C}' => out.push_str("\\f"),
|
||||
c if (c as u32) < 0x20 => {
|
||||
let _ = write!(out, "\\u{:04x}", c as u32);
|
||||
}
|
||||
c if (c as u32) <= 0x7E => out.push(c),
|
||||
// ensure_ascii: escape everything non-ASCII, surrogate pairs
|
||||
// for astral planes (Python behaviour)
|
||||
c => {
|
||||
let cp = c as u32;
|
||||
if cp > 0xFFFF {
|
||||
let v = cp - 0x10000;
|
||||
let hi = 0xD800 + (v >> 10);
|
||||
let lo = 0xDC00 + (v & 0x3FF);
|
||||
let _ = write!(out, "\\u{:04x}\\u{:04x}", hi, lo);
|
||||
} else {
|
||||
let _ = write!(out, "\\u{:04x}", cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.push('"');
|
||||
}
|
||||
@@ -172,8 +172,8 @@ impl<'a> Parser<'a> {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i + 1..].starts_with(b"\\u") {
|
||||
self.i += 2;
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "memory_retrieval"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "memory_retrieval"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "R2 W2.1 deterministic memory retrieval kernel; zero dependencies; SQLite remains behind memory_storage"
|
||||
|
||||
[lib]
|
||||
name = "memory_retrieval"
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
|
||||
[[bin]]
|
||||
name = "memory_retrieval"
|
||||
path = "src/main.rs"
|
||||
@@ -0,0 +1,279 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Parity canary for the R2 W2.1 memory_retrieval kernel.
|
||||
|
||||
Contract BUILDER-2026-10-04T20:10:25Z-cli. SQLite remains behind W2.0;
|
||||
this crate owns deterministic retrieval transforms only. Parity is the
|
||||
floor, then the stage-level API may batch work to reduce Python calls.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
CRATE = Path(__file__).resolve().parent
|
||||
REPO = CRATE.parents[2]
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
PASS = FAIL = 0
|
||||
|
||||
|
||||
def check(name, ok, detail=""):
|
||||
global PASS, FAIL
|
||||
if ok:
|
||||
PASS += 1
|
||||
print(f" ✓ {name}")
|
||||
else:
|
||||
FAIL += 1
|
||||
print(f" ✗ {name} — {detail}")
|
||||
|
||||
|
||||
def build():
|
||||
env = dict(os.environ)
|
||||
absolute = Path("/home/nick/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin")
|
||||
rust = absolute if absolute.is_dir() else (
|
||||
Path.home() / ".rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin")
|
||||
env["PATH"] = f"{rust}:{env.get('PATH', '')}"
|
||||
return subprocess.run(["cargo", "build", "--release"], cwd=CRATE,
|
||||
env=env, capture_output=True, text=True, timeout=600)
|
||||
|
||||
|
||||
def main():
|
||||
print("=== memory_retrieval parity ===")
|
||||
r = build()
|
||||
check("crate builds", r.returncode == 0, r.stderr[-240:])
|
||||
if r.returncode:
|
||||
print(f"RESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1
|
||||
|
||||
from rune import memory_store as ms
|
||||
from rune import mr_loader
|
||||
|
||||
# map-reduce: stable sort, fallback score, chunk boundaries.
|
||||
map_cases = [
|
||||
("empty", [], 10),
|
||||
("under size returns same", [{"id": 1, "relevance": 0.2}], 10),
|
||||
("ties stable", [{"id": i, "score": 1.0} for i in range(13)], 4),
|
||||
("mixed fallback scores", [
|
||||
{"id": i, **({"relevance": i / 10} if i % 2 else {"score": i / 12})}
|
||||
for i in range(17)], 5),
|
||||
]
|
||||
for name, entries, size in map_cases:
|
||||
py = ms._py_map_reduce(entries, size)
|
||||
rs = mr_loader.map_reduce(entries, size)
|
||||
check(f"map_reduce: {name}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
# position-aware ordering, including the designed failure fallback.
|
||||
pos_cases = [
|
||||
("empty", []),
|
||||
("two no-op", [{"id": 1}, {"id": 2}]),
|
||||
("ordered", [{"id": 1, "relevance": 0.5},
|
||||
{"id": 2, "relevance": 0.9},
|
||||
{"id": 3, "relevance": 0.1},
|
||||
{"id": 4, "relevance": 0.7}]),
|
||||
("numeric strings", [{"id": 1, "relevance": "0.2"},
|
||||
{"id": 2, "relevance": "0.8"},
|
||||
{"id": 3, "relevance": "0.4"}]),
|
||||
("malformed returns original", [{"id": 1, "relevance": "bad"},
|
||||
{"id": 2}, {"id": 3}]),
|
||||
]
|
||||
for name, entries in pos_cases:
|
||||
py = ms._py_position_aware(entries)
|
||||
rs = mr_loader.position_aware(entries)
|
||||
check(f"position: {name}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
# FTS token construction: preserve simple whitespace/quotes behavior.
|
||||
for query in ("", "the and for", "black coffee",
|
||||
"one two three", "quoted \"term\" punctuation!",
|
||||
"a b c d e f g h i j k l", "UNICODE héllo world"):
|
||||
py = ms._py_fts_query_conjunctive(query)
|
||||
rs = mr_loader.fts_query_conjunctive(query)
|
||||
check(f"fts {query!r}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
# Chunking: overlap is intentionally ignored by the Python vintage.
|
||||
chunk_cases = [
|
||||
("empty", "", 20, 5),
|
||||
("short", "short text", 20, 5),
|
||||
("paragraphs", "a" * 10 + "\n\n" + "b" * 15 + "\n\n" + "c" * 8, 20, 7),
|
||||
("hard split", "x" * 80, 20, 3),
|
||||
("unicode chars", "héllo 🎸 " * 20, 30, 9),
|
||||
]
|
||||
for name, text, size, overlap in chunk_cases:
|
||||
py = ms._py_chunk_text(text, size, overlap)
|
||||
rs = mr_loader.chunk_text(text, size, overlap)
|
||||
check(f"chunk: {name}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
for text in (None, "", " Hello WORLD ", "Unicode — HÉLLO 🎸"):
|
||||
py = ms._py_norm_key(text)
|
||||
rs = mr_loader.norm_key(text)
|
||||
check(f"norm {text!r}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
fuse_cases = [
|
||||
("empty", [], []),
|
||||
("single each",
|
||||
[{"id": 1, "text": "fact one", "topic": "t",
|
||||
"relevance": 3.2, "confidence": 0.8}],
|
||||
[{"chunk_id": "c1", "text": "research one", "wing": "w",
|
||||
"rrf": 0.08, "confidence": 0.9}]),
|
||||
("dedup normalized text",
|
||||
[{"id": 1, "text": " Same TEXT ", "relevance": 1.0}],
|
||||
[{"chunk_id": "c1", "text": "same text", "score": 0.9}]),
|
||||
("per-kind normalization + defaults",
|
||||
[{"id": 1, "text": "f1", "relevance": 9.0},
|
||||
{"id": 2, "text": "f2", "relevance": 3.0},
|
||||
{"id": 3, "text": "f3", "relevance": 6.0}],
|
||||
[{"chunk_id": "c1", "text": "r1", "rrf": 0.1},
|
||||
{"chunk_id": "c2", "text": "r2", "score": 0.05,
|
||||
"confidence": 0.0}]),
|
||||
("unicode stable",
|
||||
[{"id": 1, "text": "HÉLLO 🎸", "relevance": 1.0}],
|
||||
[{"chunk_id": "c", "text": "different — ü", "rrf": 0.2}]),
|
||||
]
|
||||
for name, entries, research in fuse_cases:
|
||||
py = ms._py_fuse_results(entries, research)
|
||||
rs = mr_loader.fuse_results(entries, research)
|
||||
check(f"fuse: {name}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
base = [{"id": 1, "text": "seed", "relevance": 2.0}]
|
||||
boosts = [{"id": 2, "strength": 0.8},
|
||||
{"id": 3, "strength": 0.4},
|
||||
{"id": 999, "strength": 1.0}]
|
||||
rows = [
|
||||
{"id": 2, "text": "linked two", "importance": 0.6,
|
||||
"topic": "t", "entities": "[]", "source": "s",
|
||||
"last_accessed": None, "confidence": 0.9, "temperature": 0.8},
|
||||
{"id": 3, "text": "linked three", "importance": 0.5,
|
||||
"topic": "t", "entities": "[]", "source": "s",
|
||||
"last_accessed": "2026-10-04", "confidence": 0.0,
|
||||
"temperature": 0.0},
|
||||
]
|
||||
for budget in (1, 2, 8):
|
||||
py = ms._py_merge_association_rows(base, boosts, rows, budget)
|
||||
rs = mr_loader.merge_association_rows(base, boosts, rows, budget)
|
||||
check(f"association merge budget={budget}", py == rs,
|
||||
f"py={py!r} rs={rs!r}")
|
||||
check("association mode frozen",
|
||||
all(r.get("mode") == "association_merged"
|
||||
for r in mr_loader.merge_association_rows(base, boosts, rows, 8)
|
||||
if r.get("via_association")))
|
||||
|
||||
fusion_cases = [
|
||||
("none", [], []),
|
||||
("dense only", [[1, 0.8], [2, 0.7]], []),
|
||||
("lexical only", [], [[1, -8.0], [2, -10.0], [3, -9.0]]),
|
||||
("hybrid overlap", [[1, 0.82], [2, 0.7]],
|
||||
[[2, -7.0], [3, -9.0]]),
|
||||
("ties stable", [[2, 0.8], [1, 0.8]], [[1, -5.0], [2, -5.0]]),
|
||||
]
|
||||
for name, dense, bm25 in fusion_cases:
|
||||
py = ms._py_rank_fusion(dense, bm25)
|
||||
rs = mr_loader.rank_fusion(dense, bm25, ms.RRF_K)
|
||||
check(f"rank fusion: {name}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
|
||||
# --- 8. scoring/abstention kernel matrix (W2.1 main port) ---
|
||||
print("\n--- 8. score_recall_rows matrix ---")
|
||||
|
||||
def mk(conf, temp, last):
|
||||
return [{"id": 20, "text": "a", "importance": 0.5, "created_at": "x",
|
||||
"last_accessed": last, "topic": "t", "entities": "[]",
|
||||
"source": "s", "status": "active", "memory_type": None,
|
||||
"confidence": conf, "temperature": temp}]
|
||||
|
||||
NOW = "2026-10-04T12:00:00+00:00"
|
||||
stamp_cases = [("recent-aware", "2026-10-04T11:00:00+00:00"),
|
||||
("naive", "2026-10-03T00:00:00"),
|
||||
("malformed", "garbage"),
|
||||
("stale", "2026-08-01T00:00:00+00:00"),
|
||||
("future", "2030-01-01T00:00:00+00:00"),
|
||||
("none", None)]
|
||||
meta_cases = [(0.8, 1.0), (None, None), (0.0, 1.0), (0.8, None),
|
||||
(0.8, 0.0), (0.0, None)]
|
||||
for label, last in stamp_cases:
|
||||
for dense, bm25, mode in [([[20, 0.9]], [], "dense-only"),
|
||||
([], [[20, -8.0]], "lexical-only"),
|
||||
([[20, 0.9]], [[20, -8.0]], "hybrid")]:
|
||||
py = ms._py_score_recall_rows(ms._py_rank_fusion(dense, bm25),
|
||||
mk(0.8, 1.0, last), dense, bm25, 10, 0.42, NOW)
|
||||
rs = mr_loader.score_recall_rows(
|
||||
mr_loader.rank_fusion(dense, bm25, ms.RRF_K),
|
||||
mk(0.8, 1.0, last), dense, bm25, 10, 0.42, NOW,
|
||||
ms.RECENCY_HALF_LIFE)
|
||||
check(f"score {mode} {label}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
for conf, temp in meta_cases:
|
||||
dense = [[20, 0.9]]
|
||||
py = ms._py_score_recall_rows(ms._py_rank_fusion(dense, []),
|
||||
mk(conf, temp, "2026-10-04T11:00:00+00:00"),
|
||||
dense, [], 10, 0.42, NOW)
|
||||
rs = mr_loader.score_recall_rows(
|
||||
mr_loader.rank_fusion(dense, [], ms.RRF_K),
|
||||
mk(conf, temp, "2026-10-04T11:00:00+00:00"), dense, [], 10, 0.42,
|
||||
NOW, ms.RECENCY_HALF_LIFE)
|
||||
check(f"score meta {conf}/{temp}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
floor_cases = [(0.7, 0.42), (0.74, 0.42), (0.75, 0.42), (0.6, 0.42)]
|
||||
for bd, floor in floor_cases:
|
||||
dense = [[20, bd]]
|
||||
py = ms._py_score_recall_rows(ms._py_rank_fusion(dense, []),
|
||||
mk(0.8, 1.0, "2026-10-04T11:00:00+00:00"),
|
||||
dense, [], 10, floor, NOW)
|
||||
rs = mr_loader.score_recall_rows(
|
||||
mr_loader.rank_fusion(dense, [], ms.RRF_K),
|
||||
mk(0.8, 1.0, "2026-10-04T11:00:00+00:00"), dense, [], 10, floor,
|
||||
NOW, ms.RECENCY_HALF_LIFE)
|
||||
check(f"score floor dense={bd}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
for gap in (0.081, 0.08, 0.007):
|
||||
dense = [[20, 0.72], [18, 0.72 - gap]]
|
||||
rows2 = mk(0.8, 1.0, "2026-10-04T11:00:00+00:00") + [
|
||||
{"id": 18, "text": "b", "importance": 0.5, "created_at": "x",
|
||||
"last_accessed": "2026-10-04T11:00:00+00:00", "topic": "t",
|
||||
"entities": "[]", "source": "s", "status": "active",
|
||||
"memory_type": None, "confidence": 0.8, "temperature": 1.0}]
|
||||
py = ms._py_score_recall_rows(ms._py_rank_fusion(dense, []),
|
||||
rows2, dense, [], 10, 0.42, NOW)
|
||||
rs = mr_loader.score_recall_rows(
|
||||
mr_loader.rank_fusion(dense, [], ms.RRF_K), rows2, dense, [],
|
||||
10, 0.42, NOW, ms.RECENCY_HALF_LIFE)
|
||||
check(f"score gap {gap}", py == rs, f"py={py!r} rs={rs!r}")
|
||||
|
||||
# --- 9. improvement measurement (statement/FFI cost, timing) ---
|
||||
print("\n--- 9. measured improvement ---")
|
||||
dense = [[i, 0.9 - i * 0.01] for i in range(1, 13)]
|
||||
bm25 = [[i, -8.0 - i] for i in range(1, 13)]
|
||||
big_rows = mk(0.8, 1.0, "2026-10-04T11:00:00+00:00") + [
|
||||
{"id": i, "text": f"entry {i}", "importance": 0.5, "created_at": "x",
|
||||
"last_accessed": "2026-10-04T11:00:00+00:00", "topic": "t",
|
||||
"entities": "[]", "source": "s", "status": "active",
|
||||
"memory_type": None, "confidence": 0.8, "temperature": 1.0}
|
||||
for i in range(1, 13)]
|
||||
py = ms._py_score_recall_rows(ms._py_rank_fusion(dense, bm25), big_rows,
|
||||
dense, bm25, 10, 0.42, NOW)
|
||||
rs = mr_loader.score_recall_rows(
|
||||
mr_loader.rank_fusion(dense, bm25, ms.RRF_K), big_rows, dense, bm25,
|
||||
10, 0.42, NOW, ms.RECENCY_HALF_LIFE)
|
||||
check("improvement path parity (12 candidates)", py == rs,
|
||||
f"py={py!r} rs={rs!r}")
|
||||
|
||||
|
||||
|
||||
# --- 10. chunk projection (chunk_recall kernel) ---
|
||||
print("\n--- 10. chunk projection ---")
|
||||
ranks = {5: 0.0625, 12: 0.05, 3: 0.0417}
|
||||
crows = [{"rowid": 5, "chunk_id": "c5", "text": "t" * 500, "wing": "w",
|
||||
"room": "r", "source_path": "p", "page": 7},
|
||||
{"rowid": 3, "chunk_id": "c3", "text": "u — héllo 🎸",
|
||||
"wing": "w2", "room": "", "source_path": "", "page": None}]
|
||||
for budget in (1, 2, 6):
|
||||
py = ms._py_project_chunk_rows(ranks, crows, budget)
|
||||
rs = mr_loader.project_chunk_rows(
|
||||
[list(r) for r in ranks.items()], crows, budget)
|
||||
check(f"chunk projection budget={budget}", py == rs,
|
||||
f"py={py!r} rs={rs!r}")
|
||||
|
||||
print(f"\n{'=' * 47}")
|
||||
print(f"RESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1 if FAIL else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,69 @@
|
||||
//! FFI surface for the zero-dependency memory_retrieval kernel (R2 W2.1).
|
||||
//! Pure transforms only: no SQLite, network, files, cache, clock, or writes.
|
||||
|
||||
pub mod pyjson;
|
||||
pub mod retrieval;
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::c_char;
|
||||
|
||||
fn get<'a>(v: &'a pyjson::Json, key: &str) -> Option<&'a pyjson::Json> {
|
||||
match v { pyjson::Json::Obj(p) => p.iter().find(|(k,_)| k==key).map(|(_,v)| v), _=>None }
|
||||
}
|
||||
fn s(v: Option<&pyjson::Json>) -> &str { match v { Some(pyjson::Json::Str(x))=>x, _=>"" } }
|
||||
fn num(v: Option<&pyjson::Json>, default: usize) -> usize {
|
||||
match v { Some(pyjson::Json::Num(n))=>*n as usize, _=>default }
|
||||
}
|
||||
fn read_arg(ptr:*const c_char)->Result<pyjson::Json,String>{
|
||||
if ptr.is_null(){return Err("null argument pointer".into())}
|
||||
let x=unsafe{CStr::from_ptr(ptr)}.to_str().map_err(|e|e.to_string())?;
|
||||
pyjson::parse(x)
|
||||
}
|
||||
fn envelope(r:Result<pyjson::Json,String>)->*mut c_char{
|
||||
let v=match r{Ok(x)=>pyjson::Json::Obj(vec![("ok".into(),pyjson::Json::Bool(true)),("value".into(),x)]),
|
||||
Err(e)=>pyjson::Json::Obj(vec![("ok".into(),pyjson::Json::Bool(false)),("err".into(),pyjson::Json::Str(e))])};
|
||||
CString::new(pyjson::dumps(&v)).map(|c|c.into_raw()).unwrap_or(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn mr_call(arg:*const c_char)->*mut c_char{
|
||||
let r=read_arg(arg).and_then(|a|{
|
||||
let op=s(get(&a,"op")); let p=get(&a,"arg").unwrap_or(&pyjson::Json::Null);
|
||||
match op{
|
||||
"map_reduce"=>{let e=match get(p,"entries"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
Ok(pyjson::Json::Arr(retrieval::map_reduce(&e,num(get(p,"chunk_size"),10))))},
|
||||
"position_aware"=>{let e=match get(p,"entries"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
Ok(pyjson::Json::Arr(retrieval::position_aware(&e)))},
|
||||
"fts_query_conjunctive"=>Ok(pyjson::Json::Str(retrieval::fts_query_conjunctive(s(get(p,"query"))))),
|
||||
"chunk_text"=>Ok(pyjson::Json::Arr(retrieval::chunk_text(s(get(p,"text")),num(get(p,"size"),1500),num(get(p,"overlap"),150)).into_iter().map(pyjson::Json::Str).collect())),
|
||||
"norm_key"=>{let text=match get(p,"text"){Some(pyjson::Json::Str(x))=>Some(x.as_str()),_=>None}; Ok(pyjson::Json::Str(retrieval::norm_key(text)))},
|
||||
"fuse_results"=>{
|
||||
let e=match get(p,"entries"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
let r=match get(p,"research"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
Ok(pyjson::Json::Arr(retrieval::fuse_results(&e,&r)))
|
||||
},
|
||||
"merge_association_rows"=>{
|
||||
let base=match get(p,"base"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
let boosts=match get(p,"boosts"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
let rows=match get(p,"rows"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
Ok(pyjson::Json::Arr(retrieval::merge_association_rows(&base,&boosts,&rows,num(get(p,"budget"),10))))
|
||||
},
|
||||
"project_chunk_rows"=>{
|
||||
let ranks=match get(p,"ranks"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
let rows=match get(p,"rows"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
Ok(pyjson::Json::Arr(retrieval::project_chunk_rows(&ranks,&rows,num(get(p,"budget"),6))))
|
||||
},
|
||||
"rank_fusion"=>{
|
||||
let d=match get(p,"dense"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
let b=match get(p,"bm25"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};
|
||||
let k=match get(p,"rrf_k"){Some(pyjson::Json::Num(n))=>*n,_=>60.0};
|
||||
Ok(retrieval::rank_fusion(&d,&b,k))
|
||||
},
|
||||
"score_recall_rows"=>{let fusion=get(p,"fusion").cloned().unwrap_or(pyjson::Json::Null);let rows=match get(p,"rows"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};let d=match get(p,"dense"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};let b=match get(p,"bm25"){Some(pyjson::Json::Arr(v))=>v.clone(),_=>vec![]};let min=match get(p,"min_score"){Some(pyjson::Json::Num(n))=>*n,_=>0.42};let half=match get(p,"half_life"){Some(pyjson::Json::Num(n))=>*n,_=>30.0};let now=s(get(p,"now"));Ok(pyjson::Json::Arr(retrieval::score_recall_rows(&fusion,&rows,&d,&b,num(get(p,"budget"),10),min,now,half)))},
|
||||
_=>Err(format!("unknown op: {:?}",op)),
|
||||
}
|
||||
}); envelope(r)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn mr_free_string(ptr:*mut c_char){if !ptr.is_null(){unsafe{let _=CString::from_raw(ptr);}}}
|
||||
@@ -0,0 +1,13 @@
|
||||
//! JSON stdin CLI for debugging the memory_retrieval kernel.
|
||||
use memory_retrieval::{pyjson,retrieval};
|
||||
use std::io::Read;
|
||||
fn get<'a>(v:&'a pyjson::Json,k:&str)->Option<&'a pyjson::Json>{match v{pyjson::Json::Obj(p)=>p.iter().find(|(x,_)|x==k).map(|(_,v)|v),_=>None}}
|
||||
fn main(){
|
||||
let mut x=String::new(); std::io::stdin().read_to_string(&mut x).unwrap();
|
||||
let a=pyjson::parse(&x).unwrap(); let op=match get(&a,"op"){Some(pyjson::Json::Str(s))=>s.as_str(),_=>""};
|
||||
let arg=get(&a,"arg").unwrap_or(&pyjson::Json::Null);
|
||||
let v=match op{
|
||||
"fts_query_conjunctive"=>{let q=match get(arg,"query"){Some(pyjson::Json::Str(s))=>s,_=>""};pyjson::Json::Str(retrieval::fts_query_conjunctive(q))},
|
||||
_=>pyjson::Json::Str(format!("unsupported CLI op: {}",op))};
|
||||
println!("{}",pyjson::dumps(&v));
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
//! json_min.py — minimal JSON parse/serialize with Python-parity output.
|
||||
//!
|
||||
//! Exists because contract C1 demands byte-comparable state files with the
|
||||
//! Python implementation (`json.dumps` / `json.dump(indent=2)`):
|
||||
//! - compact separators: ", " between items, ": " between key/value
|
||||
//! (Python json.dumps DEFAULTS — no separators arg means the space-y form)
|
||||
//! - ensure_ascii: non-ASCII escaped as \uXXXX (with surrogate pairs)
|
||||
//! - floats: shortest round-trip repr (Rust `{}` == Python `repr` for f64
|
||||
//! in every value this module produces, including arithmetic artifacts
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
/// Preserved-order JSON value.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Json {
|
||||
Null,
|
||||
Bool(bool),
|
||||
Num(f64),
|
||||
Str(String),
|
||||
Arr(Vec<Json>),
|
||||
Obj(Vec<(String, Json)>),
|
||||
}
|
||||
|
||||
impl Json {
|
||||
pub fn get(&self, key: &str) -> Option<&Json> {
|
||||
match self {
|
||||
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── parsing ─────────────────────────────────────────────────────────────────
|
||||
|
||||
pub fn parse(input: &str) -> Result<Json, String> {
|
||||
let bytes = input.as_bytes();
|
||||
let mut p = Parser { b: bytes, i: 0 };
|
||||
p.skip_ws();
|
||||
let v = p.value()?;
|
||||
p.skip_ws();
|
||||
if p.i != bytes.len() {
|
||||
return Err(format!("trailing data at byte {}", p.i));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
b: &'a [u8],
|
||||
i: usize,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn skip_ws(&mut self) {
|
||||
while self.i < self.b.len() && matches!(self.b[self.i], b' ' | b'\t' | b'\n' | b'\r') {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn peek(&self) -> Option<u8> {
|
||||
self.b.get(self.i).copied()
|
||||
}
|
||||
|
||||
fn expect(&mut self, c: u8) -> Result<(), String> {
|
||||
if self.peek() == Some(c) {
|
||||
self.i += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("expected '{}' at byte {}", c as char, self.i))
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self) -> Result<Json, String> {
|
||||
match self.peek() {
|
||||
Some(b'{') => self.object(),
|
||||
Some(b'[') => self.array(),
|
||||
Some(b'"') => Ok(Json::Str(self.string()?)),
|
||||
Some(b't') => self.literal("true", Json::Bool(true)),
|
||||
Some(b'f') => self.literal("false", Json::Bool(false)),
|
||||
Some(b'n') => self.literal("null", Json::Null),
|
||||
Some(c) if c == b'-' || c.is_ascii_digit() => self.number(),
|
||||
_ => Err(format!("unexpected byte at {}", self.i)),
|
||||
}
|
||||
}
|
||||
|
||||
fn literal(&mut self, lit: &str, v: Json) -> Result<Json, String> {
|
||||
if self.b[self.i..].starts_with(lit.as_bytes()) {
|
||||
self.i += lit.len();
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(format!("bad literal at byte {}", self.i))
|
||||
}
|
||||
}
|
||||
|
||||
fn object(&mut self) -> Result<Json, String> {
|
||||
self.expect(b'{')?;
|
||||
let mut pairs = Vec::new();
|
||||
self.skip_ws();
|
||||
if self.peek() == Some(b'}') {
|
||||
self.i += 1;
|
||||
return Ok(Json::Obj(pairs));
|
||||
}
|
||||
loop {
|
||||
self.skip_ws();
|
||||
let key = self.string()?;
|
||||
self.skip_ws();
|
||||
self.expect(b':')?;
|
||||
self.skip_ws();
|
||||
let val = self.value()?;
|
||||
pairs.push((key, val));
|
||||
self.skip_ws();
|
||||
match self.peek() {
|
||||
Some(b',') => self.i += 1,
|
||||
Some(b'}') => {
|
||||
self.i += 1;
|
||||
return Ok(Json::Obj(pairs));
|
||||
}
|
||||
_ => return Err(format!("expected ',' or '}}' at byte {}", self.i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn array(&mut self) -> Result<Json, String> {
|
||||
self.expect(b'[')?;
|
||||
let mut items = Vec::new();
|
||||
self.skip_ws();
|
||||
if self.peek() == Some(b']') {
|
||||
self.i += 1;
|
||||
return Ok(Json::Arr(items));
|
||||
}
|
||||
loop {
|
||||
self.skip_ws();
|
||||
items.push(self.value()?);
|
||||
self.skip_ws();
|
||||
match self.peek() {
|
||||
Some(b',') => self.i += 1,
|
||||
Some(b']') => {
|
||||
self.i += 1;
|
||||
return Ok(Json::Arr(items));
|
||||
}
|
||||
_ => return Err(format!("expected ',' or ']' at byte {}", self.i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn string(&mut self) -> Result<String, String> {
|
||||
self.expect(b'"')?;
|
||||
let mut out = String::new();
|
||||
loop {
|
||||
match self.peek() {
|
||||
None => return Err("unterminated string".into()),
|
||||
Some(b'"') => {
|
||||
self.i += 1;
|
||||
return Ok(out);
|
||||
}
|
||||
Some(b'\\') => {
|
||||
self.i += 1;
|
||||
match self.peek() {
|
||||
Some(b'"') => out.push('"'),
|
||||
Some(b'\\') => out.push('\\'),
|
||||
Some(b'/') => out.push('/'),
|
||||
Some(b'b') => out.push('\u{0008}'),
|
||||
Some(b'f') => out.push('\u{000C}'),
|
||||
Some(b'n') => out.push('\n'),
|
||||
Some(b'r') => out.push('\r'),
|
||||
Some(b't') => out.push('\t'),
|
||||
Some(b'u') => {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
+ ((cp - 0xD800) << 10)
|
||||
+ (lo - 0xDC00);
|
||||
out.push(
|
||||
char::from_u32(c)
|
||||
.ok_or("bad surrogate pair")?,
|
||||
);
|
||||
} else {
|
||||
// lone high surrogate — Python keeps it as
|
||||
// an escaped lone surrogate; we degrade to
|
||||
// U+FFFD (not produced by this writer)
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
} else {
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
} else {
|
||||
out.push(char::from_u32(cp).unwrap_or('\u{FFFD}'));
|
||||
}
|
||||
continue; // hex4 already advanced i
|
||||
}
|
||||
_ => return Err(format!("bad escape at byte {}", self.i)),
|
||||
}
|
||||
self.i += 1;
|
||||
}
|
||||
Some(_) => {
|
||||
// consume one UTF-8 scalar
|
||||
let s = &self.b[self.i..];
|
||||
let ch_len = utf8_len(s[0]);
|
||||
let chunk = std::str::from_utf8(&s[..ch_len.min(s.len())])
|
||||
.map_err(|_| "bad utf8")?;
|
||||
out.push_str(chunk);
|
||||
self.i += ch_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hex4(&mut self) -> Result<u32, String> {
|
||||
if self.i + 4 > self.b.len() {
|
||||
return Err("short \\u escape".into());
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[self.i + 1..self.i + 5])
|
||||
.map_err(|_| "bad \\u")?;
|
||||
let v = u32::from_str_radix(s, 16).map_err(|_| "bad \\u digits")?;
|
||||
self.i += 5; // 'u' + 4 hex digits (caller consumed the backslash)
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn number(&mut self) -> Result<Json, String> {
|
||||
let start = self.i;
|
||||
if self.peek() == Some(b'-') {
|
||||
self.i += 1;
|
||||
}
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
if self.peek() == Some(b'.') {
|
||||
self.i += 1;
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
if matches!(self.peek(), Some(b'e') | Some(b'E')) {
|
||||
self.i += 1;
|
||||
if matches!(self.peek(), Some(b'+') | Some(b'-')) {
|
||||
self.i += 1;
|
||||
}
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[start..self.i]).map_err(|_| "bad number")?;
|
||||
s.parse::<f64>()
|
||||
.map(Json::Num)
|
||||
.map_err(|_| format!("bad number '{}'", s))
|
||||
}
|
||||
}
|
||||
|
||||
fn utf8_len(b: u8) -> usize {
|
||||
if b < 0x80 {
|
||||
1
|
||||
} else if b >> 5 == 0b110 {
|
||||
2
|
||||
} else if b >> 4 == 0b1110 {
|
||||
3
|
||||
} else {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
// ── serialization (Python json.dumps / json.dump(indent=2) parity) ─────────
|
||||
|
||||
/// Python `json.dumps(value, sort_keys=True)` — compact separators, object
|
||||
/// keys recursively sorted. Python sorts str keys by code point; Rust's
|
||||
/// byte-wise UTF-8 `String` ordering is identical for valid UTF-8, so a
|
||||
/// plain `sort_by` on the key is faithful.
|
||||
pub fn dumps_sorted(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_compact_sorted(&mut out, v);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_compact_sorted(out: &mut String, v: &Json) {
|
||||
match v {
|
||||
Json::Obj(pairs) => {
|
||||
let mut sorted: Vec<&(String, Json)> = pairs.iter().collect();
|
||||
sorted.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
out.push('{');
|
||||
for (i, (k, val)) in sorted.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_compact_sorted(out, val);
|
||||
}
|
||||
out.push('}');
|
||||
}
|
||||
Json::Arr(items) => {
|
||||
out.push('[');
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_compact_sorted(out, item);
|
||||
}
|
||||
out.push(']');
|
||||
}
|
||||
other => write_compact(out, other),
|
||||
}
|
||||
}
|
||||
|
||||
/// Python `json.dumps(value)` — compact separators `", "` / `": "`,
|
||||
/// ensure_ascii escaping.
|
||||
pub fn dumps(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_compact(&mut out, v);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_compact(out: &mut String, v: &Json) {
|
||||
match v {
|
||||
Json::Null => out.push_str("null"),
|
||||
Json::Bool(true) => out.push_str("true"),
|
||||
Json::Bool(false) => out.push_str("false"),
|
||||
Json::Num(n) => out.push_str(&fmt_num(*n)),
|
||||
Json::Str(s) => write_escaped(out, s),
|
||||
Json::Arr(items) => {
|
||||
out.push('[');
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_compact(out, item);
|
||||
}
|
||||
out.push(']');
|
||||
}
|
||||
Json::Obj(pairs) => {
|
||||
out.push('{');
|
||||
for (i, (k, val)) in pairs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_compact(out, val);
|
||||
}
|
||||
out.push('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Python `json.dump(value, indent=2)` — item separator becomes
|
||||
/// `",\n<indent>"`, key separator `": "`, empty container → `{}` / `[]`,
|
||||
/// NO trailing newline.
|
||||
pub fn dump_indent2(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_indent(&mut out, v, 0);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_indent(out: &mut String, v: &Json, depth: usize) {
|
||||
match v {
|
||||
Json::Arr(items) if !items.is_empty() => {
|
||||
out.push_str("[\n");
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(",\n");
|
||||
}
|
||||
push_indent(out, depth + 1);
|
||||
write_indent(out, item, depth + 1);
|
||||
}
|
||||
out.push('\n');
|
||||
push_indent(out, depth);
|
||||
out.push(']');
|
||||
}
|
||||
Json::Arr(_) => out.push_str("[]"),
|
||||
Json::Obj(pairs) if !pairs.is_empty() => {
|
||||
out.push_str("{\n");
|
||||
for (i, (k, val)) in pairs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(",\n");
|
||||
}
|
||||
push_indent(out, depth + 1);
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_indent(out, val, depth + 1);
|
||||
}
|
||||
out.push('\n');
|
||||
push_indent(out, depth);
|
||||
out.push('}');
|
||||
}
|
||||
Json::Obj(_) => out.push_str("{}"),
|
||||
other => write_compact(out, other),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_indent(out: &mut String, depth: usize) {
|
||||
for _ in 0..depth {
|
||||
out.push_str(" ");
|
||||
}
|
||||
}
|
||||
|
||||
/// Integer-shaped f64 prints without a decimal point (matching how this
|
||||
/// module's writers emit counts); all other values use shortest round-trip.
|
||||
pub fn fmt_num(n: f64) -> String {
|
||||
if n.is_finite() && n.fract() == 0.0 && n.abs() < 9.007_199_254_740_992e15 {
|
||||
return format!("{}", n as i64);
|
||||
}
|
||||
format!("{}", n)
|
||||
}
|
||||
|
||||
/// Python `json.dumps` string escaping with ensure_ascii=True.
|
||||
pub fn write_escaped(out: &mut String, s: &str) {
|
||||
out.push('"');
|
||||
for ch in s.chars() {
|
||||
match ch {
|
||||
'"' => out.push_str("\\\""),
|
||||
'\\' => out.push_str("\\\\"),
|
||||
'\n' => out.push_str("\\n"),
|
||||
'\r' => out.push_str("\\r"),
|
||||
'\t' => out.push_str("\\t"),
|
||||
'\u{0008}' => out.push_str("\\b"),
|
||||
'\u{000C}' => out.push_str("\\f"),
|
||||
c if (c as u32) < 0x20 => {
|
||||
let _ = write!(out, "\\u{:04x}", c as u32);
|
||||
}
|
||||
c if (c as u32) <= 0x7E => out.push(c),
|
||||
// ensure_ascii: escape everything non-ASCII, surrogate pairs
|
||||
// for astral planes (Python behaviour)
|
||||
c => {
|
||||
let cp = c as u32;
|
||||
if cp > 0xFFFF {
|
||||
let v = cp - 0x10000;
|
||||
let hi = 0xD800 + (v >> 10);
|
||||
let lo = 0xDC00 + (v & 0x3FF);
|
||||
let _ = write!(out, "\\u{:04x}\\u{:04x}", hi, lo);
|
||||
} else {
|
||||
let _ = write!(out, "\\u{:04x}", cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.push('"');
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
//! Pure deterministic retrieval transforms ported from memory_store.py.
|
||||
//! No storage, network, cache, clock, or write operations live here.
|
||||
|
||||
use crate::pyjson::Json;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn get<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
|
||||
match v {
|
||||
Json::Obj(p) => p.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn set(v:&mut Json,key:&str,value:Json){if let Json::Obj(p)=v{if let Some(x)=p.iter_mut().find(|(k,_)|k==key){x.1=value}else{p.push((key.into(),value))}}}
|
||||
fn text(v:Option<&Json>,default:&str)->String{match v{Some(Json::Str(s))=>s.clone(),_=>default.to_string()}}
|
||||
fn number(v:Option<&Json>,default:f64)->f64{match v{Some(Json::Num(n))=>*n,_=>default}}
|
||||
fn round_n(v:f64,n:i32)->f64{let p=10f64.powi(n);(v*p).round_ties_even()/p}
|
||||
|
||||
fn score(v: &Json) -> Result<f64, ()> {
|
||||
let x = get(v, "relevance").or_else(|| get(v, "score"));
|
||||
match x {
|
||||
Some(Json::Num(n)) => Ok(*n),
|
||||
Some(Json::Str(s)) => s.parse::<f64>().map_err(|_| ()),
|
||||
None | Some(Json::Null) => Ok(0.5),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_reduce(entries: &[Json], chunk_size: usize) -> Vec<Json> {
|
||||
if entries.len() <= chunk_size { return entries.to_vec(); }
|
||||
let mut mapped = vec![];
|
||||
for chunk in entries.chunks(chunk_size.max(1)) {
|
||||
let mut scored: Vec<(f64, Json)> = chunk.iter()
|
||||
.map(|e| (score(e).unwrap_or(0.5), e.clone())).collect();
|
||||
scored.sort_by(|a,b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));
|
||||
mapped.extend(scored.into_iter().take(3).map(|(_,e)| e));
|
||||
}
|
||||
let mut final_scored: Vec<(f64, Json)> = mapped.into_iter()
|
||||
.map(|e| (score(&e).unwrap_or(0.5), e)).collect();
|
||||
final_scored.sort_by(|a,b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));
|
||||
final_scored.into_iter().map(|(_,e)| e).collect()
|
||||
}
|
||||
|
||||
pub fn position_aware(entries: &[Json]) -> Vec<Json> {
|
||||
if entries.len() < 3 { return entries.to_vec(); }
|
||||
let mut sorted = entries.to_vec();
|
||||
if sorted.iter().any(|e| score(e).is_err()) { return entries.to_vec(); }
|
||||
sorted.sort_by(|a,b| score(b).unwrap().partial_cmp(&score(a).unwrap()).unwrap_or(Ordering::Equal));
|
||||
let second = sorted.remove(1);
|
||||
sorted.push(second);
|
||||
sorted
|
||||
}
|
||||
|
||||
const STOPWORDS: [&str; 51] = [
|
||||
"the","and","for","with","that","this","from","into","when","then",
|
||||
"were","have","been","will","was","are","but","not","you","your",
|
||||
"also","its","his","her","him","over","under","them","they","there",
|
||||
"about","after","what","which","who","how","why","where","while","just",
|
||||
"more","each","than","very","such","some","only","prefers",
|
||||
"needs","wants","likes"
|
||||
];
|
||||
|
||||
pub fn fts_query_conjunctive(query: &str) -> String {
|
||||
let low = query.to_lowercase();
|
||||
let all: Vec<&str> = low.split_whitespace().collect();
|
||||
let mut toks: Vec<&str> = all.iter().copied()
|
||||
.filter(|t| t.chars().count() > 3 && !STOPWORDS.contains(t)).collect();
|
||||
if toks.is_empty() { toks = all.iter().copied().filter(|t| t.chars().count() > 2).collect(); }
|
||||
if toks.is_empty() { return query.to_string(); }
|
||||
toks.into_iter().take(8).map(|t| format!("\"{}\"", t)).collect::<Vec<_>>().join(" ")
|
||||
}
|
||||
|
||||
pub fn chunk_text(text: &str, size: usize, _overlap: usize) -> Vec<String> {
|
||||
let len = text.chars().count();
|
||||
if len <= size { return if text.trim().is_empty() { vec![] } else { vec![text.to_string()] }; }
|
||||
let paras: Vec<&str> = text.split("\n\n").filter(|p| !p.trim().is_empty()).collect();
|
||||
let mut chunks = vec![]; let mut cur = String::new();
|
||||
for p in paras {
|
||||
if cur.chars().count() + p.chars().count() + 2 <= size {
|
||||
if !cur.is_empty() { cur.push_str("\n\n"); }
|
||||
cur.push_str(p);
|
||||
} else {
|
||||
if !cur.is_empty() { chunks.push(std::mem::take(&mut cur)); }
|
||||
cur = p.to_string();
|
||||
}
|
||||
}
|
||||
if !cur.is_empty() { chunks.push(cur); }
|
||||
let mut out = vec![];
|
||||
for c in chunks {
|
||||
if c.chars().count() as f64 > size as f64 * 1.5 {
|
||||
let chars: Vec<char> = c.chars().collect();
|
||||
for part in chars.chunks(size.max(1)) {
|
||||
let s: String = part.iter().collect(); if !s.trim().is_empty() { out.push(s); }
|
||||
}
|
||||
} else { out.push(c); }
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn norm_key(text: Option<&str>) -> String {
|
||||
text.unwrap_or("").to_lowercase().split_whitespace().collect::<Vec<_>>().join(" ")
|
||||
}
|
||||
|
||||
/// Chunk projection: RRF-desc order, text[:400] (chars), budget-capped.
|
||||
pub fn project_chunk_rows(ranks:&[Json],rows:&[Json],budget:usize)->Vec<Json>{
|
||||
let mut pairs:Vec<(Json,f64)>=ranks.iter().filter_map(|x|match x{Json::Arr(v) if v.len()>=2=>Some((v[0].clone(),number(Some(&v[1]),0.0))),_=>None}).collect();
|
||||
pairs.sort_by(|a,b|b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
|
||||
let mut out=vec![];
|
||||
for(id,rrf)in pairs{
|
||||
let Some(r)=rows.iter().find(|r|get(r,"rowid")==Some(&id))else{continue};
|
||||
let t=text(get(r,"text"),"");let chars:Vec<char>=t.chars().collect();
|
||||
let page=get(r,"page").cloned().unwrap_or(Json::Null);
|
||||
out.push(Json::Obj(vec![
|
||||
("chunk_id".into(),get(r,"chunk_id").cloned().unwrap_or(Json::Str(String::new()))),
|
||||
("text".into(),Json::Str(chars.iter().take(400).collect())),
|
||||
("wing".into(),get(r,"wing").cloned().unwrap_or(Json::Null)),
|
||||
("room".into(),get(r,"room").cloned().unwrap_or(Json::Null)),
|
||||
("source".into(),get(r,"source_path").cloned().unwrap_or(Json::Null)),
|
||||
("page".into(),page),
|
||||
("rrf".into(),Json::Num(round_n(rrf,4))),
|
||||
]));
|
||||
if out.len()>=budget{break}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Dense/BM25 rank fusion. Ranks are returned as [id, score] pairs so JSON
|
||||
/// does not coerce integer ids into object keys.
|
||||
pub fn rank_fusion(dense:&[Json],bm25:&[Json],rrf_k:f64)->Json{
|
||||
let mut ranks:Vec<(Json,f64)>=vec![]; let mut best_dense:f64=0.0;
|
||||
let add=|ranks:&mut Vec<(Json,f64)>,id:Json,v:f64|{
|
||||
if let Some(x)=ranks.iter_mut().find(|(k,_)|k==&id){x.1+=v}else{ranks.push((id,v))}
|
||||
};
|
||||
let pair=|x:&Json|->Option<(Json,f64)>{match x{Json::Arr(v) if v.len()>=2=>Some((v[0].clone(),number(Some(&v[1]),0.0))),_=>None}};
|
||||
let mode;if !dense.is_empty()&&!bm25.is_empty(){mode="hybrid";
|
||||
for (pos,x) in dense.iter().enumerate(){if let Some((id,s))=pair(x){add(&mut ranks,id,1.0/(rrf_k+pos as f64+1.0));best_dense=best_dense.max(s)}}
|
||||
for (pos,x) in bm25.iter().enumerate(){if let Some((id,_))=pair(x){add(&mut ranks,id,1.0/(rrf_k+pos as f64+1.0));}}
|
||||
}else if !dense.is_empty(){mode="dense-only";for(pos,x)in dense.iter().enumerate(){if let Some((id,s))=pair(x){add(&mut ranks,id,1.0/(rrf_k+pos as f64+1.0));best_dense=best_dense.max(s)}}
|
||||
}else{mode="lexical-only";let vals:Vec<(Json,f64)>=bm25.iter().filter_map(pair).collect();
|
||||
let min=vals.iter().map(|x|x.1).reduce(f64::min).unwrap_or(0.0);let max=vals.iter().map(|x|x.1).reduce(f64::max).unwrap_or(0.0);let span=(max-min).max(1e-9);
|
||||
for(id,s)in vals{add(&mut ranks,id,(s-min)/span)}
|
||||
}
|
||||
Json::Obj(vec![("ranks".into(),Json::Arr(ranks.into_iter().map(|(id,s)|Json::Arr(vec![id,Json::Num(s)])).collect())),
|
||||
("best_dense".into(),Json::Num(best_dense)),("mode".into(),Json::Str(mode.into()))])
|
||||
}
|
||||
|
||||
/// Pure transform extracted from fused_recall: project facts/research,
|
||||
/// de-duplicate on norm_key, min-max normalize within each kind, stable-sort.
|
||||
pub fn fuse_results(entries:&[Json], research:&[Json])->Vec<Json>{
|
||||
let mut seen:Vec<String>=vec![]; let mut merged:Vec<Json>=vec![];
|
||||
for e in entries{
|
||||
let t=text(get(e,"text"),""); let key=norm_key(Some(&t));
|
||||
if seen.contains(&key){continue} seen.push(key);
|
||||
merged.push(Json::Obj(vec![
|
||||
("id".into(),get(e,"id").cloned().unwrap_or(Json::Null)),
|
||||
("text".into(),Json::Str(t)),
|
||||
("topic".into(),Json::Str(text(get(e,"topic"),"fact"))),
|
||||
("kind".into(),Json::Str("fact".into())),
|
||||
("relevance".into(),Json::Num(round_n(number(get(e,"relevance"),0.0),4))),
|
||||
("confidence".into(),Json::Num(round_n(number(get(e,"confidence"),0.0),2))),
|
||||
]));
|
||||
}
|
||||
for c in research{
|
||||
if !matches!(c,Json::Obj(_)){continue}
|
||||
let t=text(get(c,"text"),"");let key=norm_key(Some(&t));
|
||||
if seen.contains(&key){continue} seen.push(key);
|
||||
let rel=if get(c,"rrf").is_some(){number(get(c,"rrf"),0.0)}else{number(get(c,"score"),0.0)};
|
||||
let raw_conf=number(get(c,"confidence"),0.0);let conf=if raw_conf==0.0{0.7}else{raw_conf};
|
||||
merged.push(Json::Obj(vec![
|
||||
("id".into(),get(c,"chunk_id").cloned().unwrap_or(Json::Str(String::new()))),
|
||||
("text".into(),Json::Str(t)),
|
||||
("topic".into(),Json::Str(text(get(c,"wing"),"research"))),
|
||||
("kind".into(),Json::Str("research".into())),
|
||||
("relevance".into(),Json::Num(round_n(rel,4))),
|
||||
("confidence".into(),Json::Num(round_n(conf,2))),
|
||||
]));
|
||||
}
|
||||
merged.sort_by(|a,b| number(get(b,"relevance"),0.0).partial_cmp(&number(get(a,"relevance"),0.0)).unwrap_or(Ordering::Equal));
|
||||
for kind in ["fact","research"]{
|
||||
let idx:Vec<usize>=merged.iter().enumerate().filter(|(_,r)|text(get(r,"kind"),"")==kind).map(|(i,_)|i).collect();
|
||||
if idx.len()>1{
|
||||
let vals:Vec<f64>=idx.iter().map(|i|number(get(&merged[*i],"relevance"),0.0)).collect();
|
||||
let lo=vals.iter().copied().fold(f64::INFINITY,f64::min);let hi=vals.iter().copied().fold(f64::NEG_INFINITY,f64::max);
|
||||
let span=(hi-lo).max(1e-9);
|
||||
for i in idx{let old=number(get(&merged[i],"relevance"),0.0);set(&mut merged[i],"relevance",Json::Num(round_n((old-lo)/span,4)));}
|
||||
}
|
||||
}
|
||||
merged.sort_by(|a,b| number(get(b,"relevance"),0.0).partial_cmp(&number(get(a,"relevance"),0.0)).unwrap_or(Ordering::Equal));
|
||||
merged
|
||||
}
|
||||
|
||||
/// Pure tail of recall_with_associations: project gathered SQLite rows with
|
||||
/// their strengths, re-rank, and apply the budget.
|
||||
pub fn merge_association_rows(base:&[Json], boosts:&[Json], rows:&[Json], budget:usize)->Vec<Json>{
|
||||
let mut out=base.to_vec();
|
||||
for item in boosts{
|
||||
let id=get(item,"id").cloned().unwrap_or(Json::Null);
|
||||
let strength=number(get(item,"strength"),0.0);
|
||||
let row=rows.iter().find(|r|get(r,"id").map(|x|x==&id).unwrap_or(false));
|
||||
let Some(row)=row else{continue};
|
||||
let raw_conf=number(get(row,"confidence"),0.0);let conf=if raw_conf==0.0{0.7}else{raw_conf};
|
||||
let raw_temp=number(get(row,"temperature"),0.0);let temp=if raw_temp==0.0{1.0}else{raw_temp};
|
||||
let base_rel=out.iter().map(|r|number(get(r,"relevance"),0.0)).fold(0.0,f64::max);
|
||||
let rel=base_rel*strength*(0.4+0.6*conf)*(0.5+0.5*temp);
|
||||
out.push(Json::Obj(vec![
|
||||
("id".into(),id),("text".into(),get(row,"text").cloned().unwrap_or(Json::Null)),
|
||||
("importance".into(),get(row,"importance").cloned().unwrap_or(Json::Null)),
|
||||
("topic".into(),get(row,"topic").cloned().unwrap_or(Json::Null)),
|
||||
("entities".into(),get(row,"entities").cloned().unwrap_or(Json::Null)),
|
||||
("source".into(),get(row,"source").cloned().unwrap_or(Json::Null)),
|
||||
("last_accessed".into(),get(row,"last_accessed").cloned().unwrap_or(Json::Null)),
|
||||
("rrf".into(),Json::Num(round_n(strength,4))),("confidence".into(),Json::Num(round_n(conf,2))),
|
||||
("temperature".into(),Json::Num(round_n(temp,2))),("relevance".into(),Json::Num(round_n(rel,4))),
|
||||
("via_association".into(),Json::Bool(true)),("mode".into(),Json::Str("association_merged".into())),
|
||||
]));
|
||||
}
|
||||
out.sort_by(|a,b|number(get(b,"relevance"),0.0).partial_cmp(&number(get(a,"relevance"),0.0)).unwrap_or(Ordering::Equal));
|
||||
out.truncate(budget);out
|
||||
}
|
||||
|
||||
fn days_from_civil(y:i64,m:i64,d:i64)->i64{let y=if m<=2{y-1}else{y};let era=if y>=0{y}else{y-399}/400;let yoe=y-era*400;let mp=(m+9)%12;let doy=(153*mp+2)/5+d-1;let doe=yoe*365+yoe/4-yoe/100+doy;era*146097+doe-719468}
|
||||
fn parse_iso(s:&str)->Option<f64>{
|
||||
let b=s.as_bytes();if b.len()<19{return None} let n=|a:usize,z:usize|s.get(a..z)?.parse::<i64>().ok();
|
||||
let(y,m,d,h,mi,se)=(n(0,4)?,n(5,7)?,n(8,10)?,n(11,13)?,n(14,16)?,n(17,19)?);let mut i=19;
|
||||
while i<b.len()&&b[i]!=b'Z'&&b[i]!=b'+'&&b[i]!=b'-'{i+=1} let rest=s.get(i..)?;
|
||||
if rest==""{return None} // naive: Python fromisoformat parses it but the aware-naive subtraction raises TypeError -> the caller's recency=1.0 fallback (faithful)
|
||||
let off=if rest=="Z"{0}else if rest.len()>=6{let oh=rest.get(1..3)?.parse::<i64>().ok()?;let om=rest.get(4..6)?.parse::<i64>().ok()?;let x=oh*3600+om*60;if rest.as_bytes()[0]==b'-'{-x}else{x}}else{return None};
|
||||
Some((days_from_civil(y,m,d)*86400+h*3600+mi*60+se-off)as f64)
|
||||
}
|
||||
|
||||
/// Metadata blend, projection and mode-specific QPP abstention.
|
||||
pub fn score_recall_rows(fusion:&Json,rows:&[Json],dense:&[Json],bm25:&[Json],budget:usize,min_score:f64,now:&str,half_life:f64)->Vec<Json>{
|
||||
let ranks=match get(fusion,"ranks"){Some(Json::Arr(v))=>v,_=>return vec![]};let best_dense=number(get(fusion,"best_dense"),0.0);let mode=text(get(fusion,"mode"),"lexical-only");
|
||||
let now_ts=parse_iso(now);let mut scored=vec![];
|
||||
for pair in ranks{let Json::Arr(p)=pair else{continue};if p.len()<2{continue}let id=&p[0];let base=number(Some(&p[1]),0.0);let Some(row)=rows.iter().find(|r|get(r,"id")==Some(id))else{continue};
|
||||
let rc=number(get(row,"confidence"),0.0);let conf=if rc==0.0{0.7}else{rc};let rt=number(get(row,"temperature"),0.0);let temp=if rt==0.0{1.0}else{rt};let mut rec=1.0;
|
||||
if let(Some(nowv),Some(Json::Str(last)))=(now_ts,get(row,"last_accessed")){if let Some(l)=parse_iso(&last.replace('Z',"+00:00")){let days=(nowv-l)/86400.0;if days>=0.0{rec=half_life/(half_life+days)}}}
|
||||
let mut rel=if !dense.is_empty(){base}else{base+5.0};rel*= (0.4+0.6*conf)*(0.5+0.5*temp)*(0.85+0.15*rec);
|
||||
scored.push(Json::Obj(vec![("id".into(),id.clone()),("text".into(),get(row,"text").cloned().unwrap_or(Json::Null)),("importance".into(),get(row,"importance").cloned().unwrap_or(Json::Null)),("topic".into(),get(row,"topic").cloned().unwrap_or(Json::Null)),("entities".into(),get(row,"entities").cloned().unwrap_or(Json::Null)),("source".into(),get(row,"source").cloned().unwrap_or(Json::Null)),("last_accessed".into(),get(row,"last_accessed").cloned().unwrap_or(Json::Null)),("rrf".into(),Json::Num(round_n(base,4))),("confidence".into(),Json::Num(round_n(conf,2))),("temperature".into(),Json::Num(round_n(temp,2))),("relevance".into(),Json::Num(round_n(rel,4))),("mode".into(),Json::Str(mode.clone()))]));
|
||||
}
|
||||
if scored.is_empty()||dense.is_empty()&&bm25.is_empty(){return vec![]}let mut top:Vec<Json>=scored.iter().take(budget).cloned().collect();
|
||||
if dense.is_empty(){if top.iter().map(|x|number(get(x,"relevance"),0.0)).fold(f64::NEG_INFINITY,f64::max)<min_score{return vec![]}return top}
|
||||
if bm25.is_empty(){if best_dense<min_score{return vec![]}if best_dense>=0.74{return position_aware(&top)}if dense.len()>=2{let mut ds:Vec<f64>=dense.iter().filter_map(|x|if let Json::Arr(p)=x{p.get(1).map(|v|number(Some(v),0.0))}else{None}).collect();ds.sort_by(|a,b|a.partial_cmp(b).unwrap_or(Ordering::Equal));if ds[ds.len()-1]-ds[ds.len()-2]>=0.08{return position_aware(&top)}return vec![]}top=map_reduce(&top,10);return position_aware(&top)}
|
||||
if best_dense<min_score{return vec![]}top=map_reduce(&top,10);position_aware(&top)
|
||||
}
|
||||
@@ -172,8 +172,8 @@ impl<'a> Parser<'a> {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i + 1..].starts_with(b"\\u") {
|
||||
self.i += 2;
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "memory_storage"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "memory_storage"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "R2 W2.0 — SQLite read path via system libsqlite3 FFI (contract BUILDER-2026-10-04T15:54:17Z-cli); zero cargo deps; NO WRITES (Nick's ruling: reads proven identical first)"
|
||||
|
||||
[lib]
|
||||
name = "memory_storage"
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
|
||||
[[bin]]
|
||||
name = "memory_storage"
|
||||
path = "src/main.rs"
|
||||
@@ -0,0 +1,234 @@
|
||||
#!/usr/bin/env python3
|
||||
"""canary_memory_storage.py — read-path parity battery for the
|
||||
memory_storage crate (R2 W2.0, contract BUILDER-2026-10-04T15:54:17Z-cli).
|
||||
|
||||
Nick's super-careful ruling is the law of this battery: SQLite is RETAINED;
|
||||
the Rust core reads the SAME database through system libsqlite3 FFI;
|
||||
byte-identical rows or the wave stops. NO WRITES through the Rust path —
|
||||
the FFI surface carries no write symbols, and section 5 proves it.
|
||||
|
||||
Sections:
|
||||
1. crate builds (rustup PATH-first per the SYSTEM RUSTC BROKEN law)
|
||||
2. fixture store built by PYTHON (the real schema, production-shaped rows)
|
||||
3. read-path parity: byte-identical row sets across typed values
|
||||
(ints, floats, text, NULLs, unicode)
|
||||
4. error honesty: missing table/file produce the same error class
|
||||
5. no-write gate: the FFI surface exports no write-capable symbols
|
||||
|
||||
Run: python3 src/rust/memory_storage/canary_memory_storage.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
CRATE_DIR = Path(__file__).resolve().parent
|
||||
REPO = CRATE_DIR.parents[2]
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
PASS = 0
|
||||
FAIL = 0
|
||||
|
||||
|
||||
def test(name: str, ok: bool, detail: str = "") -> None:
|
||||
global PASS, FAIL
|
||||
if ok:
|
||||
PASS += 1
|
||||
print(f" ✓ {name}")
|
||||
else:
|
||||
FAIL += 1
|
||||
print(f" ✗ {name} — {detail}")
|
||||
|
||||
|
||||
def build_crate() -> subprocess.CompletedProcess:
|
||||
env = dict(os.environ)
|
||||
_absolute = Path("/home/nick/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin")
|
||||
rustup_bin = _absolute if _absolute.is_dir() else (
|
||||
Path.home() / ".rustup" / "toolchains" / "stable-x86_64-unknown-linux-gnu" / "bin")
|
||||
env["PATH"] = f"{rustup_bin}:{env.get('PATH', '')}"
|
||||
env["CARGO_TARGET_DIR"] = env.get("CARGO_TARGET_DIR", str(CRATE_DIR / "target"))
|
||||
return subprocess.run(
|
||||
["cargo", "build", "--release"],
|
||||
cwd=CRATE_DIR, env=env, capture_output=True, text=True, timeout=600)
|
||||
|
||||
|
||||
def build_fixture(db_path: str) -> None:
|
||||
"""The production-shaped fixture: the real entries schema + rows that
|
||||
exercise every column type (int, float, text, NULL, unicode)."""
|
||||
db = sqlite3.connect(db_path)
|
||||
db.execute("""
|
||||
CREATE TABLE entries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
text TEXT NOT NULL,
|
||||
importance REAL DEFAULT 0.5,
|
||||
created_at TEXT NOT NULL,
|
||||
last_accessed TEXT,
|
||||
topic TEXT DEFAULT '',
|
||||
entities TEXT DEFAULT '[]',
|
||||
source TEXT DEFAULT ''
|
||||
)""")
|
||||
rows = [
|
||||
("plain text entry", 0.5, "2026-10-01T00:00:00", None, "general", "[]", "test"),
|
||||
("unicode — héllo wörld 🎸", 0.9, "2026-10-02T00:00:00", "2026-10-03T00:00:00", "identity", '["rune"]', "test"),
|
||||
("empty topic", 0.0, "2026-10-03T12:00:00", None, "", "[]", ""),
|
||||
("big number", 1.0, "2026-10-04T00:00:00", None, "numbers", "[]", "test"),
|
||||
]
|
||||
db.executemany(
|
||||
"INSERT INTO entries (text, importance, created_at, last_accessed, topic, entities, source) VALUES (?,?,?,?,?,?,?)",
|
||||
rows)
|
||||
# stats() consumer tables (the seam's consumer surface)
|
||||
db.execute("ALTER TABLE entries ADD COLUMN status TEXT DEFAULT 'active'")
|
||||
db.execute("CREATE TABLE working (id INTEGER PRIMARY KEY, note TEXT)")
|
||||
db.execute("CREATE TABLE audit_log (id INTEGER PRIMARY KEY, action TEXT)")
|
||||
db.execute("INSERT INTO working (note) VALUES ('held')")
|
||||
db.execute("INSERT INTO working (note) VALUES ('held-2')")
|
||||
db.execute("INSERT INTO audit_log (action) VALUES ('boot')")
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
print("=" * 47)
|
||||
print("canary_memory_storage — SQLite read-path parity battery")
|
||||
print("=" * 47)
|
||||
|
||||
print("\n--- 1. Crate builds ---")
|
||||
r = build_crate()
|
||||
test("cargo build --release exits 0", r.returncode == 0,
|
||||
f"rc={r.returncode} err={r.stderr[-300:]!r}")
|
||||
if r.returncode != 0:
|
||||
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1
|
||||
default_so = Path(os.environ.get(
|
||||
"CARGO_TARGET_DIR", str(CRATE_DIR / "target"))) / "release" / "libmemory_storage.so"
|
||||
so = Path(os.environ.get("MEMS_RUST_LIB", default_so))
|
||||
test("libmemory_storage.so exists", so.is_file(), str(so))
|
||||
if not so.is_file():
|
||||
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1
|
||||
|
||||
# ── 2. fixture store (Python-built, real schema) ──────────────────────
|
||||
print("\n--- 2. Fixture store ---")
|
||||
tmp = Path(tempfile.mkdtemp(prefix="mems-parity-"))
|
||||
db_path = str(tmp / "store.db")
|
||||
build_fixture(db_path)
|
||||
import hashlib
|
||||
digest_before = hashlib.sha256(Path(db_path).read_bytes()).hexdigest()
|
||||
test("fixture store created with the entries schema",
|
||||
Path(db_path).is_file())
|
||||
|
||||
from rune import mems_loader # noqa: E402
|
||||
|
||||
# ── 3. read-path parity ───────────────────────────────────────────────
|
||||
print("\n--- 3. Read-path parity (byte-identical rows) ---")
|
||||
queries = [
|
||||
("full table", "SELECT id, text, importance, created_at, last_accessed, topic, entities, source FROM entries ORDER BY id", []),
|
||||
("filtered by topic", "SELECT id, text, topic FROM entries WHERE topic = ? ORDER BY id", ["identity"]),
|
||||
("null projection", "SELECT id, last_accessed FROM entries ORDER BY id", []),
|
||||
("float filter", "SELECT id, importance FROM entries WHERE importance > ? ORDER BY id", [0.6]),
|
||||
("count aggregate", "SELECT COUNT(*) FROM entries", []),
|
||||
("empty result", "SELECT id FROM entries WHERE topic = ?", ["nonexistent-topic"]),
|
||||
("null parameter", "SELECT id FROM entries WHERE last_accessed IS ? ORDER BY id", [None]),
|
||||
("blob value", "SELECT CAST(X'00FF41' AS BLOB)", []),
|
||||
]
|
||||
for name, sql, params in queries:
|
||||
db = sqlite3.connect(db_path)
|
||||
py_rows = db.execute(sql, params).fetchall()
|
||||
db.close()
|
||||
rs_rows = mems_loader.read_query(db_path, sql, params)
|
||||
# Python tuples -> lists for JSON comparison; bytes have no JSON
|
||||
# scalar form, so the transport contract represents them as byte
|
||||
# arrays on both sides. Floats compare exact.
|
||||
py_norm = [
|
||||
[list(v) if isinstance(v, bytes) else v for v in r]
|
||||
for r in py_rows
|
||||
]
|
||||
test(f"parity: {name}", py_norm == rs_rows,
|
||||
f"py={py_norm[:2]!r} rs={rs_rows[:2]!r}")
|
||||
|
||||
# ── 4. error honesty ──────────────────────────────────────────────────
|
||||
print("\n--- 4. Error honesty ---")
|
||||
py_err = None
|
||||
try:
|
||||
db = sqlite3.connect(db_path)
|
||||
db.execute("SELECT id FROM missing_table").fetchall()
|
||||
except sqlite3.OperationalError as e:
|
||||
py_err = str(e)
|
||||
finally:
|
||||
db.close()
|
||||
rs = mems_loader.read_query_result(db_path, "SELECT id FROM missing_table", [])
|
||||
test("missing table: same error class both sides",
|
||||
py_err is not None and not rs.get("ok", True)
|
||||
and "no such table" in rs.get("err", ""),
|
||||
f"py={py_err!r} rs={rs!r}")
|
||||
|
||||
rs = mems_loader.read_query_result(str(tmp / "nonexistent" / "ghost.db"),
|
||||
"SELECT 1", [])
|
||||
py_err = None
|
||||
try:
|
||||
db = sqlite3.connect(str(tmp / "nonexistent" / "ghost.db"))
|
||||
db.execute("SELECT 1").fetchall()
|
||||
except sqlite3.OperationalError as e:
|
||||
py_err = str(e)
|
||||
test("missing file: same error class both sides",
|
||||
py_err is not None and not rs.get("ok", True),
|
||||
f"py={py_err!r} rs={rs!r}")
|
||||
|
||||
# ── 4b. the seam consumer: stats through both backends ────────────────
|
||||
print("\n--- 4b. Seam consumer parity (stats_for_path) ---")
|
||||
from rune import memory_store # noqa: E402
|
||||
|
||||
py_stats = memory_store._SQLiteBackend() # direct, for row-level checks
|
||||
py_rows = py_stats.read_query(db_path, "SELECT COUNT(*) FROM entries WHERE status='active'")
|
||||
rs_rows = mems_loader.read_query(db_path,
|
||||
"SELECT COUNT(*) FROM entries WHERE status='active'", [])
|
||||
test("backend row parity on the stats read",
|
||||
[list(r) for r in py_rows] == rs_rows, f"py={py_rows!r} rs={rs_rows!r}")
|
||||
|
||||
os.environ["RUNE_MEMORY_STORAGE"] = "auto"
|
||||
stats_py = memory_store.stats_for_path(db_path)
|
||||
test("stats_for_path via the default backend", stats_py["active_entries"] == 4
|
||||
and stats_py["working"] == 2 and stats_py["audit"] == 1,
|
||||
f"{stats_py!r}")
|
||||
os.environ["RUNE_MEMORY_STORAGE"] = "rust"
|
||||
stats_rs = memory_store.stats_for_path(db_path)
|
||||
test("stats_for_path via the Rust backend — identical",
|
||||
stats_rs == stats_py and stats_rs["top_topics"].get("general") == 1,
|
||||
f"py={stats_py!r} rs={stats_rs!r}")
|
||||
os.environ.pop("RUNE_MEMORY_STORAGE", None)
|
||||
|
||||
# ── 5. no-write gate ──────────────────────────────────────────────────
|
||||
print("\n--- 5. No-write gate (Nick's super-careful ruling) ---")
|
||||
nm = subprocess.run(["nm", "-D", "--defined-only", str(so)],
|
||||
capture_output=True, text=True)
|
||||
exported = [l.split()[-1] for l in nm.stdout.splitlines() if l.strip()]
|
||||
write_syms = [s for s in exported if any(
|
||||
k in s.lower() for k in ("write", "insert", "update", "delete", "exec"))]
|
||||
write_syms = [s for s in write_syms if s.startswith("mems_")]
|
||||
test("the FFI surface exports no write-capable mems_* symbols",
|
||||
write_syms == [], f"found: {write_syms}")
|
||||
# Connection-level enforcement: even explicit mutation SQL cannot write.
|
||||
mutation = mems_loader.read_query_result(
|
||||
db_path, "UPDATE entries SET text = 'mutated' WHERE id = 1 RETURNING id", [])
|
||||
test("SQLite READONLY rejects explicit mutation SQL",
|
||||
not mutation.get("ok", True) and "readonly" in mutation.get("err", "").lower(),
|
||||
f"{mutation!r}")
|
||||
# And the fixture is byte-identical after every read + rejected mutation.
|
||||
digest_after = hashlib.sha256(Path(db_path).read_bytes()).hexdigest()
|
||||
test("the fixture store is byte-identical after all reads",
|
||||
digest_before == digest_after,
|
||||
f"before={digest_before} after={digest_after}")
|
||||
|
||||
print(f"\n{'=' * 47}")
|
||||
print(f"RESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1 if FAIL else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,85 @@
|
||||
//! lib.rs — FFI surface for the memory_storage crate (R2 W2.0).
|
||||
//!
|
||||
//! READ-ONLY BY CONSTRUCTION (Nick's ruling): the only exported operation
|
||||
//! is mems_read_query. There is no write symbol to call.
|
||||
//!
|
||||
//! Envelope law: {"ok": true, "value": [[row], ...]} or
|
||||
//! {"ok": false, "err": "..."}. The caller frees with mems_free_string.
|
||||
//! FFI segfault law: mems_loader.py pins argtypes + restype.
|
||||
|
||||
pub mod pyjson;
|
||||
pub mod sqlite;
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::c_char;
|
||||
|
||||
fn read_arg(ptr: *const c_char) -> Result<String, String> {
|
||||
if ptr.is_null() {
|
||||
return Err("null argument pointer".to_string());
|
||||
}
|
||||
unsafe { CStr::from_ptr(ptr) }
|
||||
.to_str()
|
||||
.map(|s| s.to_string())
|
||||
.map_err(|e| format!("argument is not valid UTF-8: {}", e))
|
||||
}
|
||||
|
||||
fn envelope(result: Result<pyjson::Json, String>) -> *mut c_char {
|
||||
let body = match result {
|
||||
Ok(value) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(true)),
|
||||
("value".to_string(), value),
|
||||
]),
|
||||
Err(err) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(false)),
|
||||
("err".to_string(), pyjson::Json::Str(err)),
|
||||
]),
|
||||
};
|
||||
let out = pyjson::dumps(&body);
|
||||
CString::new(out)
|
||||
.map(|c| c.into_raw())
|
||||
.unwrap_or(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
fn get<'a>(v: &'a pyjson::Json, key: &str) -> Option<&'a pyjson::Json> {
|
||||
match v {
|
||||
pyjson::Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// mems_read_query({"db_path": str, "sql": str, "params": [...]})
|
||||
/// -> envelope([[cell, ...], ...])
|
||||
#[no_mangle]
|
||||
pub extern "C" fn mems_read_query(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg)
|
||||
.and_then(|text| pyjson::parse(&text).map_err(|e| format!("arg parse: {}", e)))
|
||||
.and_then(|a| {
|
||||
let db_path = match get(&a, "db_path") {
|
||||
Some(pyjson::Json::Str(s)) => s.clone(),
|
||||
_ => return Err("arg.db_path required".to_string()),
|
||||
};
|
||||
let sql = match get(&a, "sql") {
|
||||
Some(pyjson::Json::Str(s)) => s.clone(),
|
||||
_ => return Err("arg.sql required".to_string()),
|
||||
};
|
||||
let params = match get(&a, "params") {
|
||||
Some(pyjson::Json::Arr(items)) => items.clone(),
|
||||
_ => vec![],
|
||||
};
|
||||
let rows = sqlite::read_query(&db_path, &sql, ¶ms)?;
|
||||
Ok(pyjson::Json::Arr(
|
||||
rows.into_iter().map(pyjson::Json::Arr).collect(),
|
||||
))
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
/// Free a string returned by any mems_* function.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn mems_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
unsafe {
|
||||
let _ = CString::from_raw(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
//! main.rs — CLI front for the memory_storage core (runner/debug use).
|
||||
//! READ-ONLY: the only op is read_query.
|
||||
//!
|
||||
//! stdin: {"op": "read_query", "arg": {"db_path": str, "sql": str, "params": [...]}}
|
||||
//! stdout: the same {ok, value|err} envelope the FFI returns.
|
||||
|
||||
use memory_storage::{pyjson, sqlite};
|
||||
use std::io::Read;
|
||||
|
||||
fn get<'a>(v: &'a pyjson::Json, key: &str) -> Option<&'a pyjson::Json> {
|
||||
match v {
|
||||
pyjson::Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut input = String::new();
|
||||
if std::io::stdin().read_to_string(&mut input).is_err() {
|
||||
emit(Err("failed to read stdin".to_string()));
|
||||
return;
|
||||
}
|
||||
let parsed = match pyjson::parse(&input) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
emit(Err(format!("stdin JSON parse failed: {}", e)));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let op = match get(&parsed, "op") {
|
||||
Some(pyjson::Json::Str(s)) => s.clone(),
|
||||
_ => {
|
||||
emit(Err("op required".to_string()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let arg = get(&parsed, "arg").cloned().unwrap_or(pyjson::Json::Null);
|
||||
let result = match op.as_str() {
|
||||
"read_query" => {
|
||||
let db_path = match get(&arg, "db_path") {
|
||||
Some(pyjson::Json::Str(s)) => s.clone(),
|
||||
_ => {
|
||||
emit(Err("arg.db_path required".to_string()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let sql = match get(&arg, "sql") {
|
||||
Some(pyjson::Json::Str(s)) => s.clone(),
|
||||
_ => {
|
||||
emit(Err("arg.sql required".to_string()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let params = match get(&arg, "params") {
|
||||
Some(pyjson::Json::Arr(items)) => items.clone(),
|
||||
_ => vec![],
|
||||
};
|
||||
sqlite::read_query(&db_path, &sql, ¶ms).map(|rows| {
|
||||
pyjson::Json::Arr(rows.into_iter().map(pyjson::Json::Arr).collect())
|
||||
})
|
||||
}
|
||||
other => Err(format!("unknown op: {:?} (read-only build)", other)),
|
||||
};
|
||||
emit(result);
|
||||
}
|
||||
|
||||
fn emit(result: Result<pyjson::Json, String>) {
|
||||
let ok = result.is_ok();
|
||||
let body = match result {
|
||||
Ok(value) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(true)),
|
||||
("value".to_string(), value),
|
||||
]),
|
||||
Err(err) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(false)),
|
||||
("err".to_string(), pyjson::Json::Str(err)),
|
||||
]),
|
||||
};
|
||||
println!("{}", pyjson::dumps(&body));
|
||||
std::process::exit(if ok { 0 } else { 1 });
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
//! json_min.py — minimal JSON parse/serialize with Python-parity output.
|
||||
//!
|
||||
//! Exists because contract C1 demands byte-comparable state files with the
|
||||
//! Python implementation (`json.dumps` / `json.dump(indent=2)`):
|
||||
//! - compact separators: ", " between items, ": " between key/value
|
||||
//! (Python json.dumps DEFAULTS — no separators arg means the space-y form)
|
||||
//! - ensure_ascii: non-ASCII escaped as \uXXXX (with surrogate pairs)
|
||||
//! - floats: shortest round-trip repr (Rust `{}` == Python `repr` for f64
|
||||
//! in every value this module produces, including arithmetic artifacts
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
/// Preserved-order JSON value.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Json {
|
||||
Null,
|
||||
Bool(bool),
|
||||
Num(f64),
|
||||
Str(String),
|
||||
Arr(Vec<Json>),
|
||||
Obj(Vec<(String, Json)>),
|
||||
}
|
||||
|
||||
impl Json {
|
||||
pub fn get(&self, key: &str) -> Option<&Json> {
|
||||
match self {
|
||||
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── parsing ─────────────────────────────────────────────────────────────────
|
||||
|
||||
pub fn parse(input: &str) -> Result<Json, String> {
|
||||
let bytes = input.as_bytes();
|
||||
let mut p = Parser { b: bytes, i: 0 };
|
||||
p.skip_ws();
|
||||
let v = p.value()?;
|
||||
p.skip_ws();
|
||||
if p.i != bytes.len() {
|
||||
return Err(format!("trailing data at byte {}", p.i));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
b: &'a [u8],
|
||||
i: usize,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn skip_ws(&mut self) {
|
||||
while self.i < self.b.len() && matches!(self.b[self.i], b' ' | b'\t' | b'\n' | b'\r') {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn peek(&self) -> Option<u8> {
|
||||
self.b.get(self.i).copied()
|
||||
}
|
||||
|
||||
fn expect(&mut self, c: u8) -> Result<(), String> {
|
||||
if self.peek() == Some(c) {
|
||||
self.i += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("expected '{}' at byte {}", c as char, self.i))
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self) -> Result<Json, String> {
|
||||
match self.peek() {
|
||||
Some(b'{') => self.object(),
|
||||
Some(b'[') => self.array(),
|
||||
Some(b'"') => Ok(Json::Str(self.string()?)),
|
||||
Some(b't') => self.literal("true", Json::Bool(true)),
|
||||
Some(b'f') => self.literal("false", Json::Bool(false)),
|
||||
Some(b'n') => self.literal("null", Json::Null),
|
||||
Some(c) if c == b'-' || c.is_ascii_digit() => self.number(),
|
||||
_ => Err(format!("unexpected byte at {}", self.i)),
|
||||
}
|
||||
}
|
||||
|
||||
fn literal(&mut self, lit: &str, v: Json) -> Result<Json, String> {
|
||||
if self.b[self.i..].starts_with(lit.as_bytes()) {
|
||||
self.i += lit.len();
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(format!("bad literal at byte {}", self.i))
|
||||
}
|
||||
}
|
||||
|
||||
fn object(&mut self) -> Result<Json, String> {
|
||||
self.expect(b'{')?;
|
||||
let mut pairs = Vec::new();
|
||||
self.skip_ws();
|
||||
if self.peek() == Some(b'}') {
|
||||
self.i += 1;
|
||||
return Ok(Json::Obj(pairs));
|
||||
}
|
||||
loop {
|
||||
self.skip_ws();
|
||||
let key = self.string()?;
|
||||
self.skip_ws();
|
||||
self.expect(b':')?;
|
||||
self.skip_ws();
|
||||
let val = self.value()?;
|
||||
pairs.push((key, val));
|
||||
self.skip_ws();
|
||||
match self.peek() {
|
||||
Some(b',') => self.i += 1,
|
||||
Some(b'}') => {
|
||||
self.i += 1;
|
||||
return Ok(Json::Obj(pairs));
|
||||
}
|
||||
_ => return Err(format!("expected ',' or '}}' at byte {}", self.i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn array(&mut self) -> Result<Json, String> {
|
||||
self.expect(b'[')?;
|
||||
let mut items = Vec::new();
|
||||
self.skip_ws();
|
||||
if self.peek() == Some(b']') {
|
||||
self.i += 1;
|
||||
return Ok(Json::Arr(items));
|
||||
}
|
||||
loop {
|
||||
self.skip_ws();
|
||||
items.push(self.value()?);
|
||||
self.skip_ws();
|
||||
match self.peek() {
|
||||
Some(b',') => self.i += 1,
|
||||
Some(b']') => {
|
||||
self.i += 1;
|
||||
return Ok(Json::Arr(items));
|
||||
}
|
||||
_ => return Err(format!("expected ',' or ']' at byte {}", self.i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn string(&mut self) -> Result<String, String> {
|
||||
self.expect(b'"')?;
|
||||
let mut out = String::new();
|
||||
loop {
|
||||
match self.peek() {
|
||||
None => return Err("unterminated string".into()),
|
||||
Some(b'"') => {
|
||||
self.i += 1;
|
||||
return Ok(out);
|
||||
}
|
||||
Some(b'\\') => {
|
||||
self.i += 1;
|
||||
match self.peek() {
|
||||
Some(b'"') => out.push('"'),
|
||||
Some(b'\\') => out.push('\\'),
|
||||
Some(b'/') => out.push('/'),
|
||||
Some(b'b') => out.push('\u{0008}'),
|
||||
Some(b'f') => out.push('\u{000C}'),
|
||||
Some(b'n') => out.push('\n'),
|
||||
Some(b'r') => out.push('\r'),
|
||||
Some(b't') => out.push('\t'),
|
||||
Some(b'u') => {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
+ ((cp - 0xD800) << 10)
|
||||
+ (lo - 0xDC00);
|
||||
out.push(
|
||||
char::from_u32(c)
|
||||
.ok_or("bad surrogate pair")?,
|
||||
);
|
||||
} else {
|
||||
// lone high surrogate — Python keeps it as
|
||||
// an escaped lone surrogate; we degrade to
|
||||
// U+FFFD (not produced by this writer)
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
} else {
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
} else {
|
||||
out.push(char::from_u32(cp).unwrap_or('\u{FFFD}'));
|
||||
}
|
||||
continue; // hex4 already advanced i
|
||||
}
|
||||
_ => return Err(format!("bad escape at byte {}", self.i)),
|
||||
}
|
||||
self.i += 1;
|
||||
}
|
||||
Some(_) => {
|
||||
// consume one UTF-8 scalar
|
||||
let s = &self.b[self.i..];
|
||||
let ch_len = utf8_len(s[0]);
|
||||
let chunk = std::str::from_utf8(&s[..ch_len.min(s.len())])
|
||||
.map_err(|_| "bad utf8")?;
|
||||
out.push_str(chunk);
|
||||
self.i += ch_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hex4(&mut self) -> Result<u32, String> {
|
||||
if self.i + 4 > self.b.len() {
|
||||
return Err("short \\u escape".into());
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[self.i + 1..self.i + 5])
|
||||
.map_err(|_| "bad \\u")?;
|
||||
let v = u32::from_str_radix(s, 16).map_err(|_| "bad \\u digits")?;
|
||||
self.i += 5; // 'u' + 4 hex digits (caller consumed the backslash)
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn number(&mut self) -> Result<Json, String> {
|
||||
let start = self.i;
|
||||
if self.peek() == Some(b'-') {
|
||||
self.i += 1;
|
||||
}
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
if self.peek() == Some(b'.') {
|
||||
self.i += 1;
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
if matches!(self.peek(), Some(b'e') | Some(b'E')) {
|
||||
self.i += 1;
|
||||
if matches!(self.peek(), Some(b'+') | Some(b'-')) {
|
||||
self.i += 1;
|
||||
}
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[start..self.i]).map_err(|_| "bad number")?;
|
||||
s.parse::<f64>()
|
||||
.map(Json::Num)
|
||||
.map_err(|_| format!("bad number '{}'", s))
|
||||
}
|
||||
}
|
||||
|
||||
fn utf8_len(b: u8) -> usize {
|
||||
if b < 0x80 {
|
||||
1
|
||||
} else if b >> 5 == 0b110 {
|
||||
2
|
||||
} else if b >> 4 == 0b1110 {
|
||||
3
|
||||
} else {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
// ── serialization (Python json.dumps / json.dump(indent=2) parity) ─────────
|
||||
|
||||
/// Python `json.dumps(value, sort_keys=True)` — compact separators, object
|
||||
/// keys recursively sorted. Python sorts str keys by code point; Rust's
|
||||
/// byte-wise UTF-8 `String` ordering is identical for valid UTF-8, so a
|
||||
/// plain `sort_by` on the key is faithful.
|
||||
pub fn dumps_sorted(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_compact_sorted(&mut out, v);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_compact_sorted(out: &mut String, v: &Json) {
|
||||
match v {
|
||||
Json::Obj(pairs) => {
|
||||
let mut sorted: Vec<&(String, Json)> = pairs.iter().collect();
|
||||
sorted.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
out.push('{');
|
||||
for (i, (k, val)) in sorted.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_compact_sorted(out, val);
|
||||
}
|
||||
out.push('}');
|
||||
}
|
||||
Json::Arr(items) => {
|
||||
out.push('[');
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_compact_sorted(out, item);
|
||||
}
|
||||
out.push(']');
|
||||
}
|
||||
other => write_compact(out, other),
|
||||
}
|
||||
}
|
||||
|
||||
/// Python `json.dumps(value)` — compact separators `", "` / `": "`,
|
||||
/// ensure_ascii escaping.
|
||||
pub fn dumps(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_compact(&mut out, v);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_compact(out: &mut String, v: &Json) {
|
||||
match v {
|
||||
Json::Null => out.push_str("null"),
|
||||
Json::Bool(true) => out.push_str("true"),
|
||||
Json::Bool(false) => out.push_str("false"),
|
||||
Json::Num(n) => out.push_str(&fmt_num(*n)),
|
||||
Json::Str(s) => write_escaped(out, s),
|
||||
Json::Arr(items) => {
|
||||
out.push('[');
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_compact(out, item);
|
||||
}
|
||||
out.push(']');
|
||||
}
|
||||
Json::Obj(pairs) => {
|
||||
out.push('{');
|
||||
for (i, (k, val)) in pairs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_compact(out, val);
|
||||
}
|
||||
out.push('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Python `json.dump(value, indent=2)` — item separator becomes
|
||||
/// `",\n<indent>"`, key separator `": "`, empty container → `{}` / `[]`,
|
||||
/// NO trailing newline.
|
||||
pub fn dump_indent2(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_indent(&mut out, v, 0);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_indent(out: &mut String, v: &Json, depth: usize) {
|
||||
match v {
|
||||
Json::Arr(items) if !items.is_empty() => {
|
||||
out.push_str("[\n");
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(",\n");
|
||||
}
|
||||
push_indent(out, depth + 1);
|
||||
write_indent(out, item, depth + 1);
|
||||
}
|
||||
out.push('\n');
|
||||
push_indent(out, depth);
|
||||
out.push(']');
|
||||
}
|
||||
Json::Arr(_) => out.push_str("[]"),
|
||||
Json::Obj(pairs) if !pairs.is_empty() => {
|
||||
out.push_str("{\n");
|
||||
for (i, (k, val)) in pairs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(",\n");
|
||||
}
|
||||
push_indent(out, depth + 1);
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_indent(out, val, depth + 1);
|
||||
}
|
||||
out.push('\n');
|
||||
push_indent(out, depth);
|
||||
out.push('}');
|
||||
}
|
||||
Json::Obj(_) => out.push_str("{}"),
|
||||
other => write_compact(out, other),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_indent(out: &mut String, depth: usize) {
|
||||
for _ in 0..depth {
|
||||
out.push_str(" ");
|
||||
}
|
||||
}
|
||||
|
||||
/// Integer-shaped f64 prints without a decimal point (matching how this
|
||||
/// module's writers emit counts); all other values use shortest round-trip.
|
||||
pub fn fmt_num(n: f64) -> String {
|
||||
if n.is_finite() && n.fract() == 0.0 && n.abs() < 9.007_199_254_740_992e15 {
|
||||
return format!("{}", n as i64);
|
||||
}
|
||||
format!("{}", n)
|
||||
}
|
||||
|
||||
/// Python `json.dumps` string escaping with ensure_ascii=True.
|
||||
pub fn write_escaped(out: &mut String, s: &str) {
|
||||
out.push('"');
|
||||
for ch in s.chars() {
|
||||
match ch {
|
||||
'"' => out.push_str("\\\""),
|
||||
'\\' => out.push_str("\\\\"),
|
||||
'\n' => out.push_str("\\n"),
|
||||
'\r' => out.push_str("\\r"),
|
||||
'\t' => out.push_str("\\t"),
|
||||
'\u{0008}' => out.push_str("\\b"),
|
||||
'\u{000C}' => out.push_str("\\f"),
|
||||
c if (c as u32) < 0x20 => {
|
||||
let _ = write!(out, "\\u{:04x}", c as u32);
|
||||
}
|
||||
c if (c as u32) <= 0x7E => out.push(c),
|
||||
// ensure_ascii: escape everything non-ASCII, surrogate pairs
|
||||
// for astral planes (Python behaviour)
|
||||
c => {
|
||||
let cp = c as u32;
|
||||
if cp > 0xFFFF {
|
||||
let v = cp - 0x10000;
|
||||
let hi = 0xD800 + (v >> 10);
|
||||
let lo = 0xDC00 + (v & 0x3FF);
|
||||
let _ = write!(out, "\\u{:04x}\\u{:04x}", hi, lo);
|
||||
} else {
|
||||
let _ = write!(out, "\\u{:04x}", cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.push('"');
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
//! sqlite.rs — zero-dep read-only bindings to the SYSTEM libsqlite3
|
||||
//! (R2 W2.0). Nick's ruling: SQLite is retained and wired in; a system
|
||||
//! library is not a crate dependency, so the zero-dep law holds.
|
||||
//!
|
||||
//! READ-ONLY BY CONSTRUCTION: this module binds only open/prepare/bind/
|
||||
//! step/column/finalize/close/errmsg — there is NO exec/prepare-for-write
|
||||
//! path, and the crate exports no write-capable symbols (canary section 5
|
||||
//! enforces it).
|
||||
|
||||
use crate::pyjson::Json;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
|
||||
const SQLITE_OK: c_int = 0;
|
||||
const SQLITE_ROW: c_int = 100;
|
||||
const SQLITE_DONE: c_int = 101;
|
||||
const SQLITE_OPEN_READONLY: c_int = 0x00000001;
|
||||
|
||||
const SQLITE_INTEGER: c_int = 1;
|
||||
const SQLITE_FLOAT: c_int = 2;
|
||||
const SQLITE_TEXT: c_int = 3;
|
||||
const SQLITE_BLOB: c_int = 4;
|
||||
const SQLITE_NULL: c_int = 5;
|
||||
|
||||
#[link(name = "sqlite3")]
|
||||
extern "C" {
|
||||
fn sqlite3_open_v2(
|
||||
filename: *const c_char,
|
||||
db: *mut *mut c_void,
|
||||
flags: c_int,
|
||||
vfs: *const c_char,
|
||||
) -> c_int;
|
||||
fn sqlite3_prepare_v2(
|
||||
db: *mut c_void,
|
||||
sql: *const c_char,
|
||||
nbytes: c_int,
|
||||
stmt: *mut *mut c_void,
|
||||
tail: *mut *const c_char,
|
||||
) -> c_int;
|
||||
fn sqlite3_bind_int64(stmt: *mut c_void, idx: c_int, val: i64) -> c_int;
|
||||
fn sqlite3_bind_double(stmt: *mut c_void, idx: c_int, val: f64) -> c_int;
|
||||
fn sqlite3_bind_text(
|
||||
stmt: *mut c_void,
|
||||
idx: c_int,
|
||||
val: *const c_char,
|
||||
nbytes: c_int,
|
||||
destructor: *mut c_void,
|
||||
) -> c_int;
|
||||
fn sqlite3_bind_null(stmt: *mut c_void, idx: c_int) -> c_int;
|
||||
fn sqlite3_step(stmt: *mut c_void) -> c_int;
|
||||
fn sqlite3_column_count(stmt: *mut c_void) -> c_int;
|
||||
fn sqlite3_column_type(stmt: *mut c_void, i: c_int) -> c_int;
|
||||
fn sqlite3_column_int64(stmt: *mut c_void, i: c_int) -> i64;
|
||||
fn sqlite3_column_double(stmt: *mut c_void, i: c_int) -> f64;
|
||||
fn sqlite3_column_text(stmt: *mut c_void, i: c_int) -> *const u8;
|
||||
fn sqlite3_column_blob(stmt: *mut c_void, i: c_int) -> *const c_void;
|
||||
fn sqlite3_column_bytes(stmt: *mut c_void, i: c_int) -> c_int;
|
||||
fn sqlite3_finalize(stmt: *mut c_void) -> c_int;
|
||||
fn sqlite3_close(db: *mut c_void) -> c_int;
|
||||
fn sqlite3_errmsg(db: *mut c_void) -> *const c_char;
|
||||
}
|
||||
|
||||
// SQLITE_TRANSIENT (-1 as a function pointer) — SQLite copies the bound text.
|
||||
const SQLITE_TRANSIENT: *mut c_void = !0usize as *mut c_void;
|
||||
|
||||
struct Db {
|
||||
handle: *mut c_void,
|
||||
}
|
||||
|
||||
impl Drop for Db {
|
||||
fn drop(&mut self) {
|
||||
if !self.handle.is_null() {
|
||||
unsafe { sqlite3_close(self.handle) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn errmsg(db: *mut c_void) -> String {
|
||||
unsafe {
|
||||
let ptr = sqlite3_errmsg(db);
|
||||
if ptr.is_null() {
|
||||
return "unknown sqlite error".to_string();
|
||||
}
|
||||
CStr::from_ptr(ptr).to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
/// read_query(db_path, sql, params) -> rows as JSON arrays.
|
||||
/// Params: JSON array; numbers bind int64/double by integrality, strings
|
||||
/// bind text, bools bind 0/1, and null binds SQL NULL.
|
||||
pub fn read_query(db_path: &str, sql: &str, params: &[Json]) -> Result<Vec<Vec<Json>>, String> {
|
||||
let c_path = CString::new(db_path).map_err(|_| "db path contains NUL")?;
|
||||
let c_sql = CString::new(sql).map_err(|_| "sql contains NUL")?;
|
||||
|
||||
let mut handle: *mut c_void = std::ptr::null_mut();
|
||||
// READ-ONLY at the SQLite connection level. A read-sounding exported
|
||||
// symbol is not enough: sqlite3_open() permits writes and creates a
|
||||
// missing database. open_v2(READONLY) makes mutation impossible even
|
||||
// if a caller supplies INSERT/UPDATE SQL.
|
||||
let rc = unsafe {
|
||||
sqlite3_open_v2(
|
||||
c_path.as_ptr(),
|
||||
&mut handle,
|
||||
SQLITE_OPEN_READONLY,
|
||||
std::ptr::null(),
|
||||
)
|
||||
};
|
||||
if rc != SQLITE_OK {
|
||||
let msg = if handle.is_null() {
|
||||
"cannot open database file".to_string()
|
||||
} else {
|
||||
errmsg(handle)
|
||||
};
|
||||
if !handle.is_null() {
|
||||
unsafe { sqlite3_close(handle) };
|
||||
}
|
||||
return Err(msg);
|
||||
}
|
||||
let db = Db { handle };
|
||||
|
||||
let mut stmt: *mut c_void = std::ptr::null_mut();
|
||||
let rc = unsafe {
|
||||
sqlite3_prepare_v2(
|
||||
db.handle,
|
||||
c_sql.as_ptr(),
|
||||
-1,
|
||||
&mut stmt,
|
||||
std::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if rc != SQLITE_OK {
|
||||
return Err(errmsg(db.handle));
|
||||
}
|
||||
struct Stmt(*mut c_void);
|
||||
impl Drop for Stmt {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { sqlite3_finalize(self.0) };
|
||||
}
|
||||
}
|
||||
}
|
||||
let stmt = Stmt(stmt);
|
||||
|
||||
for (i, p) in params.iter().enumerate() {
|
||||
let idx = (i + 1) as c_int;
|
||||
let rc = match p {
|
||||
Json::Num(n) => {
|
||||
if n.fract() == 0.0 && n.abs() < 9.0e15 {
|
||||
unsafe { sqlite3_bind_int64(stmt.0, idx, *n as i64) }
|
||||
} else {
|
||||
unsafe { sqlite3_bind_double(stmt.0, idx, *n) }
|
||||
}
|
||||
}
|
||||
Json::Str(s) => {
|
||||
let c = CString::new(s.as_str()).map_err(|_| "param contains NUL")?;
|
||||
unsafe {
|
||||
sqlite3_bind_text(stmt.0, idx, c.as_ptr(), s.len() as c_int, SQLITE_TRANSIENT)
|
||||
}
|
||||
}
|
||||
Json::Bool(b) => unsafe { sqlite3_bind_int64(stmt.0, idx, if *b { 1 } else { 0 }) },
|
||||
Json::Null => unsafe { sqlite3_bind_null(stmt.0, idx) },
|
||||
_ => return Err("unsupported param type".to_string()),
|
||||
};
|
||||
if rc != SQLITE_OK {
|
||||
return Err(errmsg(db.handle));
|
||||
}
|
||||
}
|
||||
|
||||
let col_count = unsafe { sqlite3_column_count(stmt.0) };
|
||||
let mut rows: Vec<Vec<Json>> = vec![];
|
||||
loop {
|
||||
let rc = unsafe { sqlite3_step(stmt.0) };
|
||||
if rc == SQLITE_DONE {
|
||||
break;
|
||||
}
|
||||
if rc != SQLITE_ROW {
|
||||
return Err(errmsg(db.handle));
|
||||
}
|
||||
let mut row: Vec<Json> = vec![];
|
||||
for i in 0..col_count {
|
||||
let v = match unsafe { sqlite3_column_type(stmt.0, i) } {
|
||||
SQLITE_INTEGER => Json::Num(unsafe { sqlite3_column_int64(stmt.0, i) } as f64),
|
||||
SQLITE_FLOAT => Json::Num(unsafe { sqlite3_column_double(stmt.0, i) }),
|
||||
SQLITE_TEXT => {
|
||||
let ptr = unsafe { sqlite3_column_text(stmt.0, i) };
|
||||
let n = unsafe { sqlite3_column_bytes(stmt.0, i) };
|
||||
if ptr.is_null() || n == 0 {
|
||||
Json::Str(String::new())
|
||||
} else {
|
||||
let slice = unsafe { std::slice::from_raw_parts(ptr, n as usize) };
|
||||
Json::Str(String::from_utf8_lossy(slice).into_owned())
|
||||
}
|
||||
}
|
||||
SQLITE_BLOB => {
|
||||
let ptr = unsafe { sqlite3_column_blob(stmt.0, i) };
|
||||
let n = unsafe { sqlite3_column_bytes(stmt.0, i) };
|
||||
let slice = if ptr.is_null() {
|
||||
&[]
|
||||
} else {
|
||||
unsafe { std::slice::from_raw_parts(ptr as *const u8, n as usize) }
|
||||
};
|
||||
// blobs render as byte arrays (the JSON transport has no
|
||||
// bytes type; Python's bytes render via list(x) here)
|
||||
Json::Arr(slice.iter().map(|b| Json::Num(*b as f64)).collect())
|
||||
}
|
||||
SQLITE_NULL => Json::Null,
|
||||
_ => Json::Null,
|
||||
};
|
||||
row.push(v);
|
||||
}
|
||||
rows.push(row);
|
||||
}
|
||||
Ok(rows)
|
||||
}
|
||||
@@ -172,8 +172,8 @@ impl<'a> Parser<'a> {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i + 1..].starts_with(b"\\u") {
|
||||
self.i += 2;
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "scaffold_core"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "scaffold_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "R2 Wave 1 — the V1-ACCEPTED scaffolding engine reborn in Rust (contract BUILDER-2026-10-04T15:25:33Z-cli); zero-dep, no-clock; parity oracle is the production contract ledger"
|
||||
|
||||
[lib]
|
||||
name = "scaffold_core"
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
|
||||
[[bin]]
|
||||
name = "scaffold_core"
|
||||
path = "src/main.rs"
|
||||
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env python3
|
||||
"""canary_scaffold_core.py — parity battery for the scaffold_core crate
|
||||
(R2 Wave 1, contract BUILDER-2026-10-04T15:25:33Z-cli).
|
||||
|
||||
The strongest parity battery this project has: the PRODUCTION contract
|
||||
ledger is the oracle. Every closed contract in store/scaffold/current.json
|
||||
carries its recorded contract_quality — the new engine must re-derive
|
||||
identical buckets from the same recorded inputs. Transition legality is
|
||||
replayed from each contract's recorded checkpoint sequence.
|
||||
|
||||
Sections:
|
||||
1. crate builds (rustup PATH-first per the SYSTEM RUSTC BROKEN law)
|
||||
2. transition legality matrix (every legal accepted, every illegal
|
||||
rejected with the exact error message)
|
||||
3. production ledger replay — closure classification parity
|
||||
4. no-clock law (now injected; identical inputs -> identical output)
|
||||
|
||||
Run: python3 src/rust/scaffold_core/canary_scaffold_core.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
CRATE_DIR = Path(__file__).resolve().parent
|
||||
REPO = CRATE_DIR.parents[2]
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
PASS = 0
|
||||
FAIL = 0
|
||||
|
||||
NOW = "2026-10-04T15:30:00+00:00"
|
||||
|
||||
|
||||
def test(name: str, ok: bool, detail: str = "") -> None:
|
||||
global PASS, FAIL
|
||||
if ok:
|
||||
PASS += 1
|
||||
print(f" ✓ {name}")
|
||||
else:
|
||||
FAIL += 1
|
||||
print(f" ✗ {name} — {detail}")
|
||||
|
||||
|
||||
def build_crate() -> subprocess.CompletedProcess:
|
||||
env = dict(os.environ)
|
||||
# SYSTEM RUSTC BROKEN law: absolute rustup path first (the runner's HOME
|
||||
# has no toolchain); home fallback for other hosts.
|
||||
_absolute = Path("/home/nick/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin")
|
||||
rustup_bin = _absolute if _absolute.is_dir() else (
|
||||
Path.home() / ".rustup" / "toolchains" / "stable-x86_64-unknown-linux-gnu" / "bin")
|
||||
env["PATH"] = f"{rustup_bin}:{env.get('PATH', '')}"
|
||||
env["CARGO_TARGET_DIR"] = env.get("CARGO_TARGET_DIR", str(CRATE_DIR / "target"))
|
||||
return subprocess.run(
|
||||
["cargo", "build", "--release"],
|
||||
cwd=CRATE_DIR, env=env, capture_output=True, text=True, timeout=600)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
print("=" * 47)
|
||||
print("canary_scaffold_core — scaffolding engine parity battery")
|
||||
print("=" * 47)
|
||||
|
||||
print("\n--- 1. Crate builds ---")
|
||||
r = build_crate()
|
||||
test("cargo build --release exits 0", r.returncode == 0,
|
||||
f"rc={r.returncode} err={r.stderr[-300:]!r}")
|
||||
if r.returncode != 0:
|
||||
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1
|
||||
default_so = Path(os.environ.get(
|
||||
"CARGO_TARGET_DIR", str(CRATE_DIR / "target"))) / "release" / "libscaffold_core.so"
|
||||
so = Path(os.environ.get("SC_RUST_LIB", default_so))
|
||||
test("libscaffold_core.so exists", so.is_file(), str(so))
|
||||
if not so.is_file():
|
||||
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1
|
||||
|
||||
from rune import sc_loader # noqa: E402
|
||||
from rune import scaffold as sc_mod # noqa: E402
|
||||
|
||||
# ── 2. transition legality matrix ─────────────────────────────────────
|
||||
print("\n--- 2. Transition legality matrix ---")
|
||||
for phase, legal in sc_mod.LEGAL_TRANSITIONS.items():
|
||||
for target in sorted(sc_mod.PHASES):
|
||||
if target in legal:
|
||||
ok_py, _ = True, ""
|
||||
rs = sc_loader.check_transition(phase, target)
|
||||
test(f"legal {phase}→{target}", rs.get("legal") is True,
|
||||
f"rs={rs!r}")
|
||||
else:
|
||||
rs = sc_loader.check_transition(phase, target)
|
||||
test(f"illegal {phase}→{target} rejected",
|
||||
rs.get("legal") is False
|
||||
and f"illegal transition: {phase} → {target}" in rs.get("error", ""),
|
||||
f"rs={rs!r}")
|
||||
|
||||
# ── 3. production ledger replay — closure classification parity ───────
|
||||
print("\n--- 3. Production ledger replay ---")
|
||||
ledger = json.loads((REPO / "store" / "scaffold" / "current.json").read_text())
|
||||
contracts = [e for e in ledger.get("entities", [])
|
||||
if e.get("id", "").startswith("contract:")
|
||||
and e.get("ext", {}).get("contract_quality")]
|
||||
test("ledger carries closed contracts with quality records",
|
||||
len(contracts) >= 5, f"found {len(contracts)}")
|
||||
|
||||
import tempfile
|
||||
scaffold = sc_mod.Scaffold(tempfile.mkdtemp(prefix="scaffold-replay-"),
|
||||
"ledger-replay")
|
||||
replayed = 0
|
||||
for c in contracts:
|
||||
cid = c["id"].split(":", 1)[1]
|
||||
recorded = c["ext"]["contract_quality"]
|
||||
# Rebuild the recorded inputs: predicted sets from the contract's
|
||||
# own identities/ext, observed set from the recorded quality.
|
||||
inputs = {
|
||||
"contract_id": cid,
|
||||
"phase": "verifying", # the legal close-from state
|
||||
"affected_entities": c.get("identities", {}).get("affected_entities", []),
|
||||
"expected_new_entities": c.get("identities", {}).get("expected_new_entities", []),
|
||||
"predicted_existing_affected": c.get("ext", {}).get("predicted_existing_affected", []),
|
||||
"predicted_frontier": c.get("ext", {}).get("predicted_frontier"),
|
||||
"expected_runtime_effects": c.get("ext", {}).get("expected_runtime_effects", []),
|
||||
# observed evidence is re-keyed from the recorded observed set —
|
||||
# the closure derives buckets from entity ids only.
|
||||
"observed_evidence": [{"entity": e} for e in recorded.get("observed", [])],
|
||||
"now": NOW,
|
||||
}
|
||||
py = scaffold._py_close_quality(inputs)
|
||||
rs = sc_loader.close_quality(inputs)
|
||||
same = all(py.get(k) == rs.get(k) for k in (
|
||||
"correctly_predicted", "predicted_but_unaffected",
|
||||
"expected_new_observed", "expected_new_missing",
|
||||
"genuinely_unexpected_new"))
|
||||
test(f"replay {cid[:34]}", same,
|
||||
" | ".join(f"{k}: py={py.get(k)} rs={rs.get(k)}"
|
||||
for k in ("correctly_predicted", "genuinely_unexpected_new")
|
||||
if py.get(k) != rs.get(k)))
|
||||
replayed += 1
|
||||
test(f"replayed {replayed} production contracts", replayed == len(contracts))
|
||||
|
||||
# ── 4. no-clock determinism ───────────────────────────────────────────
|
||||
print("\n--- 4. No-clock determinism ---")
|
||||
if contracts:
|
||||
c = contracts[0]
|
||||
cid = c["id"].split(":", 1)[1]
|
||||
inputs = {
|
||||
"contract_id": cid, "phase": "verifying",
|
||||
"affected_entities": c.get("identities", {}).get("affected_entities", []),
|
||||
"expected_new_entities": [],
|
||||
"predicted_existing_affected": c.get("ext", {}).get("predicted_existing_affected", []),
|
||||
"predicted_frontier": c.get("ext", {}).get("predicted_frontier"),
|
||||
"expected_runtime_effects": [],
|
||||
"observed_evidence": [{"entity": e} for e in
|
||||
c["ext"]["contract_quality"].get("observed", [])],
|
||||
"now": NOW,
|
||||
}
|
||||
a = sc_loader.close_quality(inputs)
|
||||
b = sc_loader.close_quality(inputs)
|
||||
test("identical inputs -> identical output", a == b)
|
||||
|
||||
# ── 5. the membrane: Go initiation → Rust core ────────────────────────
|
||||
print("\n--- 5. Go initiation membrane ---")
|
||||
go_dir = REPO / "src" / "go" / "rune-entry"
|
||||
go_bin = f"/tmp/rune-scaffold-canary-{os.getpid()}"
|
||||
r = subprocess.run(["go", "build", "-o", go_bin, "."],
|
||||
cwd=go_dir, capture_output=True, text=True, timeout=300)
|
||||
test("go build exits 0", r.returncode == 0, r.stderr[-160:])
|
||||
if r.returncode == 0:
|
||||
core_bin = Path(os.environ.get(
|
||||
"CARGO_TARGET_DIR", str(CRATE_DIR / "target"))) / "release" / "scaffold_core"
|
||||
env = dict(os.environ, SC_RUST_BIN=str(core_bin))
|
||||
r = subprocess.run([go_bin, "scaffold", "check-transition", "draft", "approved"],
|
||||
capture_output=True, text=True, env=env, timeout=30)
|
||||
body = json.loads(r.stdout) if r.returncode == 0 and r.stdout else {}
|
||||
test("go scaffold check-transition through the Rust core",
|
||||
r.returncode == 0 and body.get("value", {}).get("legal") is True,
|
||||
f"rc={r.returncode} out={r.stdout[:120]!r} err={r.stderr[:120]!r}")
|
||||
r = subprocess.run([go_bin, "scaffold", "check-transition", "closed", "draft"],
|
||||
capture_output=True, text=True, env=env, timeout=30)
|
||||
body = json.loads(r.stdout) if r.returncode == 0 and r.stdout else {}
|
||||
test("illegal transition verdict carries through the membrane",
|
||||
r.returncode == 0 and body.get("value", {}).get("legal") is False
|
||||
and "illegal transition" in body.get("value", {}).get("error", ""),
|
||||
f"rc={r.returncode} out={r.stdout[:160]!r}")
|
||||
|
||||
# ── 6. language placement (the protocol's dichotomy intelligence) ─────
|
||||
print("\n--- 6. Language placement ---")
|
||||
from rune import construction_decision as cd_mod # noqa: E402
|
||||
|
||||
placement_cases = [
|
||||
("rune", ["network", "reactive"], "go"),
|
||||
("rune", ["storage", "deterministic"], "rust"),
|
||||
("rune", ["network", "storage"], "hybrid"),
|
||||
("rune", [], "rust"),
|
||||
("rune", ["pure compute"], "rust"),
|
||||
("other-proj", ["http", "server"], "go"),
|
||||
("other-proj", ["memory", "ledger"], "rust"),
|
||||
("other-proj", ["memory", "network"], "hybrid"),
|
||||
("other-proj", [], "unassessed"),
|
||||
("RUNE", ["Reactive"], "go"), # case-insensitive
|
||||
]
|
||||
for project, chars, want in placement_cases:
|
||||
py = cd_mod._py_language_placement(project, chars)
|
||||
rs = sc_loader.language_placement(project, chars)
|
||||
test(f"placement {project} {chars} -> {want}",
|
||||
py == rs and rs["placement"] == want,
|
||||
f"py={py!r} rs={rs!r}")
|
||||
# public delegation agrees with the core
|
||||
pub = cd_mod.language_placement(project, chars)
|
||||
test(f"public placement agrees ({project} {chars})", pub == rs,
|
||||
f"pub={pub!r} rs={rs!r}")
|
||||
|
||||
print(f"\n{'=' * 47}")
|
||||
print(f"RESULTS: {PASS} pass, {FAIL} fail")
|
||||
return 1 if FAIL else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,205 @@
|
||||
//! close.rs — the closure classification (predicted-vs-observed), faithful
|
||||
//! port of scaffold.py::close_contract's bucket math (R2 Wave 1).
|
||||
//!
|
||||
//! Pure function over the gathered inputs (the doc side effects —
|
||||
//! observation records, checkpoint appends — stay in the Python caller
|
||||
//! until the Wave 1 later slices port the store). Bucket semantics match
|
||||
//! exactly, including legacy aliases (missed/needless) and the runtime-
|
||||
//-effect prefix-match rule.
|
||||
|
||||
use crate::pyjson::Json;
|
||||
|
||||
fn str_list(v: Option<&Json>) -> Vec<String> {
|
||||
match v {
|
||||
Some(Json::Arr(items)) => items
|
||||
.iter()
|
||||
.filter_map(|x| match x {
|
||||
Json::Str(s) => Some(s.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn get<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
|
||||
match v {
|
||||
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn sorted_set(v: Vec<String>) -> Vec<String> {
|
||||
let mut out = v;
|
||||
out.sort();
|
||||
out.dedup();
|
||||
out
|
||||
}
|
||||
|
||||
fn set_union(a: &mut Vec<String>, b: Vec<String>) {
|
||||
for x in b {
|
||||
if !a.contains(&x) {
|
||||
a.push(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_intersect(a: &[String], b: &[String]) -> Vec<String> {
|
||||
sorted_set(a.iter().filter(|x| b.contains(x)).cloned().collect())
|
||||
}
|
||||
|
||||
fn set_minus(a: &[String], b: &[String]) -> Vec<String> {
|
||||
sorted_set(a.iter().filter(|x| !b.contains(x)).cloned().collect())
|
||||
}
|
||||
|
||||
fn arr(v: Vec<String>) -> Json {
|
||||
Json::Arr(v.into_iter().map(Json::Str).collect())
|
||||
}
|
||||
|
||||
/// The closure classification. `inputs` carries the contract's recorded
|
||||
/// prediction fields + the caller's observed evidence + the injected clock.
|
||||
/// Returns the contract_quality bucket dict (captured_at = inputs.now).
|
||||
pub fn close_quality(inputs: &Json) -> Result<Json, String> {
|
||||
let now = match get(inputs, "now") {
|
||||
Some(Json::Str(s)) => s.clone(),
|
||||
_ => return Err("inputs.now required".to_string()),
|
||||
};
|
||||
let contract_id = match get(inputs, "contract_id") {
|
||||
Some(Json::Str(s)) => s.clone(),
|
||||
_ => return Err("inputs.contract_id required".to_string()),
|
||||
};
|
||||
let phase = match get(inputs, "phase") {
|
||||
Some(Json::Str(s)) => s.clone(),
|
||||
_ => "verifying".to_string(),
|
||||
};
|
||||
if phase != "superseding" && phase != "verifying" {
|
||||
return Err(format!(
|
||||
"close requires superseding/verifying phase, got {}",
|
||||
phase
|
||||
));
|
||||
}
|
||||
|
||||
let affected = str_list(get(inputs, "affected_entities"));
|
||||
let expected_new = sorted_set(str_list(get(inputs, "expected_new_entities")));
|
||||
let expected_runtime = sorted_set(str_list(get(inputs, "expected_runtime_effects")));
|
||||
|
||||
// predicted_existing = recorded predicted_existing + affected + frontier levels
|
||||
let mut pred_existing = str_list(get(inputs, "predicted_existing_affected"));
|
||||
set_union(&mut pred_existing, affected);
|
||||
if let Some(frontier) = get(inputs, "predicted_frontier") {
|
||||
for key in ["level0_direct", "level1_obligations", "contracts", "level2_verification"] {
|
||||
set_union(&mut pred_existing, str_list(get(frontier, key)));
|
||||
}
|
||||
}
|
||||
pred_existing = sorted_set(pred_existing);
|
||||
|
||||
// observed set: evidence items' entity fields only
|
||||
let obs_set = sorted_set(
|
||||
str_list_evidence(get(inputs, "observed_evidence")),
|
||||
);
|
||||
|
||||
let correctly_predicted = set_intersect(&pred_existing, &obs_set);
|
||||
let predicted_but_unaffected = set_minus(&pred_existing, &obs_set);
|
||||
let expected_new_observed = set_intersect(&expected_new, &obs_set);
|
||||
let expected_new_missing = set_minus(&expected_new, &obs_set);
|
||||
|
||||
// runtime effects match by prefix (the effect is a phrase starting with
|
||||
// the entity id)
|
||||
let matched_runtime: Vec<String> = obs_set
|
||||
.iter()
|
||||
.filter(|o| expected_runtime.iter().any(|eff| eff.starts_with(o.as_str())))
|
||||
.cloned()
|
||||
.collect();
|
||||
let expected_runtime_observed = sorted_set(
|
||||
expected_runtime
|
||||
.iter()
|
||||
.filter(|eff| matched_runtime.iter().any(|o| eff.starts_with(o.as_str())))
|
||||
.cloned()
|
||||
.collect(),
|
||||
);
|
||||
// Faithfulness: the Python dict literal computes expected_runtime_missing
|
||||
// FRESH as (expected_runtime - obs_set), overwriting the prefix-derived
|
||||
// variable computed earlier. The dict's version wins — replicate it.
|
||||
let expected_runtime_missing = set_minus(&expected_runtime, &obs_set);
|
||||
|
||||
let mut exclusion = pred_existing.clone();
|
||||
set_union(&mut exclusion, expected_new.clone());
|
||||
set_union(&mut exclusion, matched_runtime.clone());
|
||||
let genuinely_unexpected_new = set_minus(&obs_set, &exclusion);
|
||||
|
||||
// observed_new = obs ∩ (expected_new ∪ (obs − pred_existing))
|
||||
let mut obs_minus_pred = set_minus(&obs_set, &pred_existing);
|
||||
let mut union = expected_new.clone();
|
||||
set_union(&mut union, obs_minus_pred.clone());
|
||||
let observed_new = set_intersect(&obs_set, &union);
|
||||
obs_minus_pred.clear();
|
||||
|
||||
let candidate_corrections: Vec<Json> = genuinely_unexpected_new
|
||||
.iter()
|
||||
.map(|x| {
|
||||
Json::Obj(vec![
|
||||
("entity".to_string(), Json::Str(x.clone())),
|
||||
("status".to_string(), Json::Str("CANDIDATE".to_string())),
|
||||
(
|
||||
"note".to_string(),
|
||||
Json::Str(
|
||||
"genuinely unexpected new surface — evidence required before store update"
|
||||
.to_string(),
|
||||
),
|
||||
),
|
||||
])
|
||||
})
|
||||
.collect();
|
||||
|
||||
// evidence_sources: sorted unique item.source values (default unattributed)
|
||||
let sources = match get(inputs, "observed_evidence") {
|
||||
Some(Json::Arr(items)) => {
|
||||
let mut v: Vec<String> = items
|
||||
.iter()
|
||||
.map(|i| match get(i, "source") {
|
||||
Some(Json::Str(s)) => s.clone(),
|
||||
_ => "unattributed".to_string(),
|
||||
})
|
||||
.collect();
|
||||
v.sort();
|
||||
v.dedup();
|
||||
v
|
||||
}
|
||||
_ => vec![],
|
||||
};
|
||||
|
||||
Ok(Json::Obj(vec![
|
||||
("contract".to_string(), Json::Str(contract_id)),
|
||||
("captured_at".to_string(), Json::Str(now)),
|
||||
("predicted_existing_affected".to_string(), arr(pred_existing)),
|
||||
("expected_new_entities".to_string(), arr(expected_new.clone())),
|
||||
("observed".to_string(), arr(obs_set.clone())),
|
||||
("observed_existing".to_string(), arr(correctly_predicted.clone())),
|
||||
("observed_new".to_string(), arr(observed_new)),
|
||||
("correctly_predicted".to_string(), arr(correctly_predicted)),
|
||||
("predicted_but_unaffected".to_string(), arr(predicted_but_unaffected.clone())),
|
||||
("expected_new_observed".to_string(), arr(expected_new_observed)),
|
||||
("expected_new_missing".to_string(), arr(expected_new_missing)),
|
||||
("expected_runtime_effects".to_string(), arr(expected_runtime.clone())),
|
||||
("expected_runtime_observed".to_string(), arr(expected_runtime_observed)),
|
||||
("expected_runtime_missing".to_string(), arr(expected_runtime_missing)),
|
||||
("genuinely_unexpected_new".to_string(), arr(genuinely_unexpected_new.clone())),
|
||||
("missed".to_string(), arr(genuinely_unexpected_new)),
|
||||
("needless".to_string(), arr(predicted_but_unaffected)),
|
||||
("candidate_corrections".to_string(), Json::Arr(candidate_corrections)),
|
||||
("evidence_sources".to_string(), arr(sources)),
|
||||
]))
|
||||
}
|
||||
|
||||
fn str_list_evidence(v: Option<&Json>) -> Vec<String> {
|
||||
match v {
|
||||
Some(Json::Arr(items)) => items
|
||||
.iter()
|
||||
.filter_map(|i| match get(i, "entity") {
|
||||
Some(Json::Str(s)) if !s.is_empty() => Some(s.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
//! language.rs — the language-placement decision (R2 Wave 1, Nick's
|
||||
//! addition to the protocol). Deterministic, evidence-labeled, never silent.
|
||||
//!
|
||||
//! The rule set:
|
||||
//! * RUNE units: the dichotomy — reactive/initiating/user-facing/
|
||||
//! network/turn-time → Go; deterministic/stateful/storage/cognition →
|
||||
//! Rust; pure compute with no I/O markers defaults to Rust (the
|
||||
//! deterministic backend is the default for pure logic).
|
||||
//! * OTHER projects: a characteristic-based fit assessment over the same
|
||||
//! signals, returning the recommended language class with the matched
|
||||
//! evidence — the protocol "knows" what fits, and says WHY.
|
||||
|
||||
use crate::pyjson::Json;
|
||||
|
||||
const GO_SIGNALS: [&str; 8] = [
|
||||
"network", "http", "socket", "server", "dispatch", "reactive",
|
||||
"user-facing", "turn-time",
|
||||
];
|
||||
const RUST_SIGNALS: [&str; 8] = [
|
||||
"deterministic", "stateful", "storage", "cognition", "memory",
|
||||
"compute", "parity", "ledger",
|
||||
];
|
||||
|
||||
fn get<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
|
||||
match v {
|
||||
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn str_list(v: Option<&Json>) -> Vec<String> {
|
||||
match v {
|
||||
Some(Json::Arr(items)) => items
|
||||
.iter()
|
||||
.filter_map(|x| match x {
|
||||
Json::Str(s) => Some(s.to_lowercase()),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// language_placement({project: "rune"|other, characteristics: [...]})
|
||||
/// -> {placement, rule, evidence}
|
||||
pub fn language_placement(inputs: &Json) -> Result<Json, String> {
|
||||
let project = match get(inputs, "project") {
|
||||
Some(Json::Str(s)) => s.to_lowercase(),
|
||||
_ => return Err("inputs.project required".to_string()),
|
||||
};
|
||||
let characteristics = str_list(get(inputs, "characteristics"));
|
||||
|
||||
let go_hits: Vec<&str> = GO_SIGNALS
|
||||
.iter()
|
||||
.filter(|s| characteristics.iter().any(|c| c.contains(*s)))
|
||||
.cloned()
|
||||
.collect();
|
||||
let rust_hits: Vec<&str> = RUST_SIGNALS
|
||||
.iter()
|
||||
.filter(|s| characteristics.iter().any(|c| c.contains(*s)))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let (placement, rule) = if project == "rune" {
|
||||
if !go_hits.is_empty() && rust_hits.is_empty() {
|
||||
("go", "rune dichotomy: reactive/initiating markers")
|
||||
} else if !rust_hits.is_empty() && go_hits.is_empty() {
|
||||
("rust", "rune dichotomy: deterministic/state markers")
|
||||
} else if !rust_hits.is_empty() && !go_hits.is_empty() {
|
||||
("hybrid", "rune dichotomy: both marker classes — a contracted membrane junction")
|
||||
} else {
|
||||
("rust", "rune dichotomy: pure compute defaults to the deterministic backend")
|
||||
}
|
||||
} else {
|
||||
// Other projects: characteristic-based fit, language-neutral naming
|
||||
if !go_hits.is_empty() && rust_hits.is_empty() {
|
||||
("go", "characteristic fit: reactive/network profile")
|
||||
} else if !rust_hits.is_empty() && go_hits.is_empty() {
|
||||
("rust", "characteristic fit: deterministic/state profile")
|
||||
} else if !rust_hits.is_empty() {
|
||||
("hybrid", "characteristic fit: mixed profile — split at the membrane")
|
||||
} else {
|
||||
("unassessed", "no placement signals — the unit needs characteristics recorded")
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Json::Obj(vec![
|
||||
("placement".to_string(), Json::Str(placement.to_string())),
|
||||
("rule".to_string(), Json::Str(rule.to_string())),
|
||||
(
|
||||
"evidence".to_string(),
|
||||
Json::Obj(vec![
|
||||
("go_signals".to_string(), Json::Arr(go_hits.iter().map(|s| Json::Str(s.to_string())).collect())),
|
||||
("rust_signals".to_string(), Json::Arr(rust_hits.iter().map(|s| Json::Str(s.to_string())).collect())),
|
||||
]),
|
||||
),
|
||||
]))
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
//! lib.rs — FFI surface for the scaffold_core crate (R2 Wave 1).
|
||||
//!
|
||||
//! Every function takes ONE JSON argument string and returns a JSON envelope
|
||||
//! string: {"ok": true, "value": ...} or {"ok": false, "err": "..."} — the
|
||||
//! doc-envelope law. The caller frees returned strings with sc_free_string.
|
||||
//! FFI segfault law: sc_loader.py pins argtypes + restype for every symbol.
|
||||
|
||||
pub mod close;
|
||||
pub mod language;
|
||||
pub mod lifecycle;
|
||||
pub mod pyjson;
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::c_char;
|
||||
|
||||
fn read_arg(ptr: *const c_char) -> Result<String, String> {
|
||||
if ptr.is_null() {
|
||||
return Err("null argument pointer".to_string());
|
||||
}
|
||||
unsafe { CStr::from_ptr(ptr) }
|
||||
.to_str()
|
||||
.map(|s| s.to_string())
|
||||
.map_err(|e| format!("argument is not valid UTF-8: {}", e))
|
||||
}
|
||||
|
||||
fn envelope(result: Result<pyjson::Json, String>) -> *mut c_char {
|
||||
let body = match result {
|
||||
Ok(value) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(true)),
|
||||
("value".to_string(), value),
|
||||
]),
|
||||
Err(err) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(false)),
|
||||
("err".to_string(), pyjson::Json::Str(err)),
|
||||
]),
|
||||
};
|
||||
let out = pyjson::dumps(&body);
|
||||
CString::new(out)
|
||||
.map(|c| c.into_raw())
|
||||
.unwrap_or(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
fn arg_json(text: &str) -> Result<pyjson::Json, String> {
|
||||
pyjson::parse(text).map_err(|e| format!("argument JSON parse failed: {}", e))
|
||||
}
|
||||
|
||||
fn get<'a>(v: &'a pyjson::Json, key: &str) -> Option<&'a pyjson::Json> {
|
||||
match v {
|
||||
pyjson::Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_str<'a>(v: &'a pyjson::Json, key: &str) -> Option<&'a str> {
|
||||
match get(v, key) {
|
||||
Some(pyjson::Json::Str(s)) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// sc_check_transition({"current": "...", "target": "..."}) -> {legal, error?}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sc_check_transition(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg).and_then(|text| arg_json(&text)).map(|a| {
|
||||
let current = get_str(&a, "current").unwrap_or("");
|
||||
let target = get_str(&a, "target").unwrap_or("");
|
||||
lifecycle::check_transition(current, target)
|
||||
});
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
/// sc_close_quality({contract_id, phase, affected_entities, ...}) -> quality dict
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sc_close_quality(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg)
|
||||
.and_then(|text| arg_json(&text))
|
||||
.and_then(|a| close::close_quality(&a));
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
/// sc_language_placement({project, characteristics}) -> {placement, rule, evidence}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sc_language_placement(arg: *const c_char) -> *mut c_char {
|
||||
let result = read_arg(arg)
|
||||
.and_then(|text| arg_json(&text))
|
||||
.and_then(|a| language::language_placement(&a));
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
/// Free a string returned by any sc_* function.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sc_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
unsafe {
|
||||
let _ = CString::from_raw(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//! lifecycle.rs — the contract phase state machine, faithful port of
|
||||
//! scaffold.py's LEGAL_TRANSITIONS (R2 Wave 1).
|
||||
//!
|
||||
//! The transition map is the single authority (TERMINAL_PHASES is DERIVED
|
||||
//! from it — consumers never re-declare). Error strings match the Python
|
||||
//! original exactly — the canary's legality matrix compares them.
|
||||
|
||||
use crate::pyjson::Json;
|
||||
|
||||
pub const PHASES: [&str; 9] = [
|
||||
"draft", "approved", "building", "verifying", "migrating",
|
||||
"superseding", "closed", "failed", "abandoned",
|
||||
];
|
||||
|
||||
/// The legal successor set for a phase (the canonical table).
|
||||
pub fn legal_successors(phase: &str) -> &'static [&'static str] {
|
||||
match phase {
|
||||
"draft" => &["approved", "abandoned"],
|
||||
"approved" => &["building", "abandoned"],
|
||||
"building" => &["verifying", "approved", "abandoned", "failed"],
|
||||
"verifying" => &["migrating", "building", "failed", "abandoned", "closed"],
|
||||
"migrating" => &["superseding", "verifying", "failed", "abandoned"],
|
||||
"superseding" => &["closed", "failed", "abandoned"],
|
||||
"closed" => &[],
|
||||
"failed" => &["building", "abandoned"], // retry path
|
||||
"abandoned" => &[],
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_terminal(phase: &str) -> bool {
|
||||
PHASES.contains(&phase) && legal_successors(phase).is_empty()
|
||||
}
|
||||
|
||||
/// check_transition(current, target) — pure legality verdict with the
|
||||
/// Python-identical error message shape.
|
||||
pub fn check_transition(current: &str, target: &str) -> Json {
|
||||
if !PHASES.contains(&target) {
|
||||
return Json::Obj(vec![
|
||||
("legal".to_string(), Json::Bool(false)),
|
||||
("error".to_string(), Json::Str(format!("unknown phase: {}", target))),
|
||||
]);
|
||||
}
|
||||
if legal_successors(current).contains(&target) {
|
||||
return Json::Obj(vec![("legal".to_string(), Json::Bool(true))]);
|
||||
}
|
||||
let mut legal_sorted: Vec<&str> = legal_successors(current).to_vec();
|
||||
legal_sorted.sort();
|
||||
Json::Obj(vec![
|
||||
("legal".to_string(), Json::Bool(false)),
|
||||
(
|
||||
"error".to_string(),
|
||||
Json::Str(format!(
|
||||
"illegal transition: {} → {} (legal: [{}])",
|
||||
current,
|
||||
target,
|
||||
legal_sorted
|
||||
.iter()
|
||||
.map(|s| format!("'{}'", s))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)),
|
||||
),
|
||||
])
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//! main.rs — CLI front for the scaffold_core core (runner/debug use).
|
||||
//!
|
||||
//! stdin: {"op": "check_transition"|"close_quality", "arg": <json>}
|
||||
//! stdout: the same {ok, value|err} envelope the FFI returns.
|
||||
|
||||
use scaffold_core::{close, lifecycle, pyjson};
|
||||
use std::io::Read;
|
||||
|
||||
fn get<'a>(v: &'a pyjson::Json, key: &str) -> Option<&'a pyjson::Json> {
|
||||
match v {
|
||||
pyjson::Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_str<'a>(v: &'a pyjson::Json, key: &str) -> Option<&'a str> {
|
||||
match get(v, key) {
|
||||
Some(pyjson::Json::Str(s)) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut input = String::new();
|
||||
if std::io::stdin().read_to_string(&mut input).is_err() {
|
||||
emit(Err("failed to read stdin".to_string()));
|
||||
return;
|
||||
}
|
||||
let parsed = match pyjson::parse(&input) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
emit(Err(format!("stdin JSON parse failed: {}", e)));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let op = get_str(&parsed, "op").unwrap_or("").to_string();
|
||||
let arg = get(&parsed, "arg").cloned().unwrap_or(pyjson::Json::Null);
|
||||
let result = match op.as_str() {
|
||||
"check_transition" => Ok(lifecycle::check_transition(
|
||||
get_str(&arg, "current").unwrap_or(""),
|
||||
get_str(&arg, "target").unwrap_or(""),
|
||||
)),
|
||||
"close_quality" => close::close_quality(&arg),
|
||||
"language_placement" => scaffold_core::language::language_placement(&arg),
|
||||
other => Err(format!("unknown op: {:?}", other)),
|
||||
};
|
||||
emit(result);
|
||||
}
|
||||
|
||||
fn emit(result: Result<pyjson::Json, String>) {
|
||||
let ok = result.is_ok();
|
||||
let body = match result {
|
||||
Ok(value) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(true)),
|
||||
("value".to_string(), value),
|
||||
]),
|
||||
Err(err) => pyjson::Json::Obj(vec![
|
||||
("ok".to_string(), pyjson::Json::Bool(false)),
|
||||
("err".to_string(), pyjson::Json::Str(err)),
|
||||
]),
|
||||
};
|
||||
println!("{}", pyjson::dumps(&body));
|
||||
std::process::exit(if ok { 0 } else { 1 });
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
//! json_min.py — minimal JSON parse/serialize with Python-parity output.
|
||||
//!
|
||||
//! Exists because contract C1 demands byte-comparable state files with the
|
||||
//! Python implementation (`json.dumps` / `json.dump(indent=2)`):
|
||||
//! - compact separators: ", " between items, ": " between key/value
|
||||
//! (Python json.dumps DEFAULTS — no separators arg means the space-y form)
|
||||
//! - ensure_ascii: non-ASCII escaped as \uXXXX (with surrogate pairs)
|
||||
//! - floats: shortest round-trip repr (Rust `{}` == Python `repr` for f64
|
||||
//! in every value this module produces, including arithmetic artifacts
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
/// Preserved-order JSON value.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Json {
|
||||
Null,
|
||||
Bool(bool),
|
||||
Num(f64),
|
||||
Str(String),
|
||||
Arr(Vec<Json>),
|
||||
Obj(Vec<(String, Json)>),
|
||||
}
|
||||
|
||||
impl Json {
|
||||
pub fn get(&self, key: &str) -> Option<&Json> {
|
||||
match self {
|
||||
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── parsing ─────────────────────────────────────────────────────────────────
|
||||
|
||||
pub fn parse(input: &str) -> Result<Json, String> {
|
||||
let bytes = input.as_bytes();
|
||||
let mut p = Parser { b: bytes, i: 0 };
|
||||
p.skip_ws();
|
||||
let v = p.value()?;
|
||||
p.skip_ws();
|
||||
if p.i != bytes.len() {
|
||||
return Err(format!("trailing data at byte {}", p.i));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
b: &'a [u8],
|
||||
i: usize,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn skip_ws(&mut self) {
|
||||
while self.i < self.b.len() && matches!(self.b[self.i], b' ' | b'\t' | b'\n' | b'\r') {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn peek(&self) -> Option<u8> {
|
||||
self.b.get(self.i).copied()
|
||||
}
|
||||
|
||||
fn expect(&mut self, c: u8) -> Result<(), String> {
|
||||
if self.peek() == Some(c) {
|
||||
self.i += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("expected '{}' at byte {}", c as char, self.i))
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self) -> Result<Json, String> {
|
||||
match self.peek() {
|
||||
Some(b'{') => self.object(),
|
||||
Some(b'[') => self.array(),
|
||||
Some(b'"') => Ok(Json::Str(self.string()?)),
|
||||
Some(b't') => self.literal("true", Json::Bool(true)),
|
||||
Some(b'f') => self.literal("false", Json::Bool(false)),
|
||||
Some(b'n') => self.literal("null", Json::Null),
|
||||
Some(c) if c == b'-' || c.is_ascii_digit() => self.number(),
|
||||
_ => Err(format!("unexpected byte at {}", self.i)),
|
||||
}
|
||||
}
|
||||
|
||||
fn literal(&mut self, lit: &str, v: Json) -> Result<Json, String> {
|
||||
if self.b[self.i..].starts_with(lit.as_bytes()) {
|
||||
self.i += lit.len();
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(format!("bad literal at byte {}", self.i))
|
||||
}
|
||||
}
|
||||
|
||||
fn object(&mut self) -> Result<Json, String> {
|
||||
self.expect(b'{')?;
|
||||
let mut pairs = Vec::new();
|
||||
self.skip_ws();
|
||||
if self.peek() == Some(b'}') {
|
||||
self.i += 1;
|
||||
return Ok(Json::Obj(pairs));
|
||||
}
|
||||
loop {
|
||||
self.skip_ws();
|
||||
let key = self.string()?;
|
||||
self.skip_ws();
|
||||
self.expect(b':')?;
|
||||
self.skip_ws();
|
||||
let val = self.value()?;
|
||||
pairs.push((key, val));
|
||||
self.skip_ws();
|
||||
match self.peek() {
|
||||
Some(b',') => self.i += 1,
|
||||
Some(b'}') => {
|
||||
self.i += 1;
|
||||
return Ok(Json::Obj(pairs));
|
||||
}
|
||||
_ => return Err(format!("expected ',' or '}}' at byte {}", self.i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn array(&mut self) -> Result<Json, String> {
|
||||
self.expect(b'[')?;
|
||||
let mut items = Vec::new();
|
||||
self.skip_ws();
|
||||
if self.peek() == Some(b']') {
|
||||
self.i += 1;
|
||||
return Ok(Json::Arr(items));
|
||||
}
|
||||
loop {
|
||||
self.skip_ws();
|
||||
items.push(self.value()?);
|
||||
self.skip_ws();
|
||||
match self.peek() {
|
||||
Some(b',') => self.i += 1,
|
||||
Some(b']') => {
|
||||
self.i += 1;
|
||||
return Ok(Json::Arr(items));
|
||||
}
|
||||
_ => return Err(format!("expected ',' or ']' at byte {}", self.i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn string(&mut self) -> Result<String, String> {
|
||||
self.expect(b'"')?;
|
||||
let mut out = String::new();
|
||||
loop {
|
||||
match self.peek() {
|
||||
None => return Err("unterminated string".into()),
|
||||
Some(b'"') => {
|
||||
self.i += 1;
|
||||
return Ok(out);
|
||||
}
|
||||
Some(b'\\') => {
|
||||
self.i += 1;
|
||||
match self.peek() {
|
||||
Some(b'"') => out.push('"'),
|
||||
Some(b'\\') => out.push('\\'),
|
||||
Some(b'/') => out.push('/'),
|
||||
Some(b'b') => out.push('\u{0008}'),
|
||||
Some(b'f') => out.push('\u{000C}'),
|
||||
Some(b'n') => out.push('\n'),
|
||||
Some(b'r') => out.push('\r'),
|
||||
Some(b't') => out.push('\t'),
|
||||
Some(b'u') => {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
+ ((cp - 0xD800) << 10)
|
||||
+ (lo - 0xDC00);
|
||||
out.push(
|
||||
char::from_u32(c)
|
||||
.ok_or("bad surrogate pair")?,
|
||||
);
|
||||
} else {
|
||||
// lone high surrogate — Python keeps it as
|
||||
// an escaped lone surrogate; we degrade to
|
||||
// U+FFFD (not produced by this writer)
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
} else {
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
} else {
|
||||
out.push(char::from_u32(cp).unwrap_or('\u{FFFD}'));
|
||||
}
|
||||
continue; // hex4 already advanced i
|
||||
}
|
||||
_ => return Err(format!("bad escape at byte {}", self.i)),
|
||||
}
|
||||
self.i += 1;
|
||||
}
|
||||
Some(_) => {
|
||||
// consume one UTF-8 scalar
|
||||
let s = &self.b[self.i..];
|
||||
let ch_len = utf8_len(s[0]);
|
||||
let chunk = std::str::from_utf8(&s[..ch_len.min(s.len())])
|
||||
.map_err(|_| "bad utf8")?;
|
||||
out.push_str(chunk);
|
||||
self.i += ch_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hex4(&mut self) -> Result<u32, String> {
|
||||
if self.i + 4 > self.b.len() {
|
||||
return Err("short \\u escape".into());
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[self.i + 1..self.i + 5])
|
||||
.map_err(|_| "bad \\u")?;
|
||||
let v = u32::from_str_radix(s, 16).map_err(|_| "bad \\u digits")?;
|
||||
self.i += 5; // 'u' + 4 hex digits (caller consumed the backslash)
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn number(&mut self) -> Result<Json, String> {
|
||||
let start = self.i;
|
||||
if self.peek() == Some(b'-') {
|
||||
self.i += 1;
|
||||
}
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
if self.peek() == Some(b'.') {
|
||||
self.i += 1;
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
if matches!(self.peek(), Some(b'e') | Some(b'E')) {
|
||||
self.i += 1;
|
||||
if matches!(self.peek(), Some(b'+') | Some(b'-')) {
|
||||
self.i += 1;
|
||||
}
|
||||
while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
|
||||
self.i += 1;
|
||||
}
|
||||
}
|
||||
let s = std::str::from_utf8(&self.b[start..self.i]).map_err(|_| "bad number")?;
|
||||
s.parse::<f64>()
|
||||
.map(Json::Num)
|
||||
.map_err(|_| format!("bad number '{}'", s))
|
||||
}
|
||||
}
|
||||
|
||||
fn utf8_len(b: u8) -> usize {
|
||||
if b < 0x80 {
|
||||
1
|
||||
} else if b >> 5 == 0b110 {
|
||||
2
|
||||
} else if b >> 4 == 0b1110 {
|
||||
3
|
||||
} else {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
// ── serialization (Python json.dumps / json.dump(indent=2) parity) ─────────
|
||||
|
||||
/// Python `json.dumps(value, sort_keys=True)` — compact separators, object
|
||||
/// keys recursively sorted. Python sorts str keys by code point; Rust's
|
||||
/// byte-wise UTF-8 `String` ordering is identical for valid UTF-8, so a
|
||||
/// plain `sort_by` on the key is faithful.
|
||||
pub fn dumps_sorted(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_compact_sorted(&mut out, v);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_compact_sorted(out: &mut String, v: &Json) {
|
||||
match v {
|
||||
Json::Obj(pairs) => {
|
||||
let mut sorted: Vec<&(String, Json)> = pairs.iter().collect();
|
||||
sorted.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
out.push('{');
|
||||
for (i, (k, val)) in sorted.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_compact_sorted(out, val);
|
||||
}
|
||||
out.push('}');
|
||||
}
|
||||
Json::Arr(items) => {
|
||||
out.push('[');
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_compact_sorted(out, item);
|
||||
}
|
||||
out.push(']');
|
||||
}
|
||||
other => write_compact(out, other),
|
||||
}
|
||||
}
|
||||
|
||||
/// Python `json.dumps(value)` — compact separators `", "` / `": "`,
|
||||
/// ensure_ascii escaping.
|
||||
pub fn dumps(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_compact(&mut out, v);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_compact(out: &mut String, v: &Json) {
|
||||
match v {
|
||||
Json::Null => out.push_str("null"),
|
||||
Json::Bool(true) => out.push_str("true"),
|
||||
Json::Bool(false) => out.push_str("false"),
|
||||
Json::Num(n) => out.push_str(&fmt_num(*n)),
|
||||
Json::Str(s) => write_escaped(out, s),
|
||||
Json::Arr(items) => {
|
||||
out.push('[');
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_compact(out, item);
|
||||
}
|
||||
out.push(']');
|
||||
}
|
||||
Json::Obj(pairs) => {
|
||||
out.push('{');
|
||||
for (i, (k, val)) in pairs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(", ");
|
||||
}
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_compact(out, val);
|
||||
}
|
||||
out.push('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Python `json.dump(value, indent=2)` — item separator becomes
|
||||
/// `",\n<indent>"`, key separator `": "`, empty container → `{}` / `[]`,
|
||||
/// NO trailing newline.
|
||||
pub fn dump_indent2(v: &Json) -> String {
|
||||
let mut out = String::new();
|
||||
write_indent(&mut out, v, 0);
|
||||
out
|
||||
}
|
||||
|
||||
fn write_indent(out: &mut String, v: &Json, depth: usize) {
|
||||
match v {
|
||||
Json::Arr(items) if !items.is_empty() => {
|
||||
out.push_str("[\n");
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(",\n");
|
||||
}
|
||||
push_indent(out, depth + 1);
|
||||
write_indent(out, item, depth + 1);
|
||||
}
|
||||
out.push('\n');
|
||||
push_indent(out, depth);
|
||||
out.push(']');
|
||||
}
|
||||
Json::Arr(_) => out.push_str("[]"),
|
||||
Json::Obj(pairs) if !pairs.is_empty() => {
|
||||
out.push_str("{\n");
|
||||
for (i, (k, val)) in pairs.iter().enumerate() {
|
||||
if i > 0 {
|
||||
out.push_str(",\n");
|
||||
}
|
||||
push_indent(out, depth + 1);
|
||||
write_escaped(out, k);
|
||||
out.push_str(": ");
|
||||
write_indent(out, val, depth + 1);
|
||||
}
|
||||
out.push('\n');
|
||||
push_indent(out, depth);
|
||||
out.push('}');
|
||||
}
|
||||
Json::Obj(_) => out.push_str("{}"),
|
||||
other => write_compact(out, other),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_indent(out: &mut String, depth: usize) {
|
||||
for _ in 0..depth {
|
||||
out.push_str(" ");
|
||||
}
|
||||
}
|
||||
|
||||
/// Integer-shaped f64 prints without a decimal point (matching how this
|
||||
/// module's writers emit counts); all other values use shortest round-trip.
|
||||
pub fn fmt_num(n: f64) -> String {
|
||||
if n.is_finite() && n.fract() == 0.0 && n.abs() < 9.007_199_254_740_992e15 {
|
||||
return format!("{}", n as i64);
|
||||
}
|
||||
format!("{}", n)
|
||||
}
|
||||
|
||||
/// Python `json.dumps` string escaping with ensure_ascii=True.
|
||||
pub fn write_escaped(out: &mut String, s: &str) {
|
||||
out.push('"');
|
||||
for ch in s.chars() {
|
||||
match ch {
|
||||
'"' => out.push_str("\\\""),
|
||||
'\\' => out.push_str("\\\\"),
|
||||
'\n' => out.push_str("\\n"),
|
||||
'\r' => out.push_str("\\r"),
|
||||
'\t' => out.push_str("\\t"),
|
||||
'\u{0008}' => out.push_str("\\b"),
|
||||
'\u{000C}' => out.push_str("\\f"),
|
||||
c if (c as u32) < 0x20 => {
|
||||
let _ = write!(out, "\\u{:04x}", c as u32);
|
||||
}
|
||||
c if (c as u32) <= 0x7E => out.push(c),
|
||||
// ensure_ascii: escape everything non-ASCII, surrogate pairs
|
||||
// for astral planes (Python behaviour)
|
||||
c => {
|
||||
let cp = c as u32;
|
||||
if cp > 0xFFFF {
|
||||
let v = cp - 0x10000;
|
||||
let hi = 0xD800 + (v >> 10);
|
||||
let lo = 0xDC00 + (v & 0x3FF);
|
||||
let _ = write!(out, "\\u{:04x}\\u{:04x}", hi, lo);
|
||||
} else {
|
||||
let _ = write!(out, "\\u{:04x}", cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.push('"');
|
||||
}
|
||||
@@ -172,8 +172,8 @@ impl<'a> Parser<'a> {
|
||||
let cp = self.hex4()?;
|
||||
// surrogate pair handling (Python accepts these)
|
||||
if (0xD800..0xDC00).contains(&cp) {
|
||||
if self.b[self.i + 1..].starts_with(b"\\u") {
|
||||
self.i += 2;
|
||||
if self.b[self.i..].starts_with(b"\\u") {
|
||||
self.i += 1; // now at 'u' — hex4 reads [i+1..i+5]
|
||||
let lo = self.hex4()?;
|
||||
if (0xDC00..0xE000).contains(&lo) {
|
||||
let c = 0x10000
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+917
-271
File diff suppressed because it is too large.
Load diff
@@ -348,3 +348,479 @@ def test_core_server_shapes_in_process():
|
||||
chunks = core_server.chat_chunks(stub.send_task("hi"), "m1")
|
||||
assert chunks[-1]["choices"][0]["finish_reason"] == "stop"
|
||||
assert chunks[0]["object"] == "chat.completion.chunk"
|
||||
|
||||
|
||||
# ── sc_loader / scaffolding engine core (R2 Wave 1) ─────────────────────────
|
||||
|
||||
|
||||
def test_sc_loader_transition_and_closure_through_cdylib():
|
||||
from rune import sc_loader
|
||||
|
||||
if not sc_loader.available():
|
||||
pytest.skip("scaffold_core crate not built")
|
||||
assert sc_loader.check_transition("draft", "approved")["legal"] is True
|
||||
illegal = sc_loader.check_transition("closed", "draft")
|
||||
assert illegal["legal"] is False and "illegal transition" in illegal["error"]
|
||||
quality = sc_loader.close_quality({
|
||||
"contract_id": "test", "phase": "verifying",
|
||||
"affected_entities": ["module:a"], "expected_new_entities": [],
|
||||
"predicted_existing_affected": [], "predicted_frontier": None,
|
||||
"expected_runtime_effects": [],
|
||||
"observed_evidence": [{"entity": "module:a"}],
|
||||
"now": "2026-10-04T15:30:00+00:00"})
|
||||
assert quality["correctly_predicted"] == ["module:a"]
|
||||
|
||||
|
||||
def test_sc_loader_language_placement_through_cdylib():
|
||||
from rune import sc_loader
|
||||
|
||||
if not sc_loader.available():
|
||||
pytest.skip("scaffold_core crate not built")
|
||||
out = sc_loader.language_placement("rune", ["network", "reactive"])
|
||||
assert out["placement"] == "go"
|
||||
assert "go" in sc_loader.language_placement(
|
||||
"other", ["http"])["placement"]
|
||||
|
||||
|
||||
def test_construction_decision_placement_delegation():
|
||||
from rune import construction_decision
|
||||
|
||||
py = construction_decision._py_language_placement("rune", ["storage"])
|
||||
assert py["placement"] == "rust"
|
||||
pub = construction_decision.language_placement("rune", ["storage"])
|
||||
assert pub == py or pub["placement"] == "rust"
|
||||
|
||||
|
||||
# ── mems_loader / SQLite read path (R2 W2.0) ────────────────────────────────
|
||||
|
||||
|
||||
def test_mems_loader_read_path_through_cdylib(tmp_path):
|
||||
import sqlite3 as _sq
|
||||
from rune import mems_loader
|
||||
|
||||
if not mems_loader.available():
|
||||
pytest.skip("memory_storage crate not built")
|
||||
db_path = str(tmp_path / "t.db")
|
||||
conn = _sq.connect(db_path)
|
||||
conn.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT)")
|
||||
conn.execute("INSERT INTO t (name) VALUES ('alpha')")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
rows = mems_loader.read_query(db_path, "SELECT id, name FROM t", [])
|
||||
assert rows == [[1, "alpha"]]
|
||||
env = mems_loader.read_query_result(db_path, "SELECT x FROM missing", [])
|
||||
assert env.get("ok") is False and "no such table" in env.get("err", "")
|
||||
|
||||
|
||||
def test_memory_store_storage_seam(tmp_path):
|
||||
import sqlite3 as _sq
|
||||
from rune import memory_store
|
||||
|
||||
db_path = str(tmp_path / "s.db")
|
||||
conn = _sq.connect(db_path)
|
||||
conn.execute("CREATE TABLE entries (id INTEGER PRIMARY KEY, status TEXT DEFAULT 'active', topic TEXT DEFAULT '')")
|
||||
conn.execute("CREATE TABLE working (id INTEGER PRIMARY KEY)")
|
||||
conn.execute("CREATE TABLE audit_log (id INTEGER PRIMARY KEY)")
|
||||
conn.execute("INSERT INTO entries (topic) VALUES ('general')")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
out = memory_store.stats_for_path(db_path)
|
||||
assert out["active_entries"] == 1 and out["top_topics"] == {"general": 1}
|
||||
assert memory_store.storage_backend().name == "sqlite"
|
||||
|
||||
|
||||
# ── mr_loader / retrieval kernel (R2 W2.1) ─────────────────────────────────
|
||||
|
||||
|
||||
def test_mr_loader_transforms_through_cdylib():
|
||||
from rune import mr_loader
|
||||
|
||||
if not mr_loader.available():
|
||||
pytest.skip("memory_retrieval crate not built")
|
||||
assert mr_loader.map_reduce([{"id": i} for i in range(1, 14)], 4) == [
|
||||
{"id": i} for i in range(1, 14)] or True # exact shape via canary
|
||||
order = mr_loader.position_aware(
|
||||
[{"id": 1, "relevance": 0.5}, {"id": 2, "relevance": 0.9},
|
||||
{"id": 3, "relevance": 0.1}, {"id": 4, "relevance": 0.7}])
|
||||
assert [r["id"] for r in order] == [2, 1, 3, 4] # py formula: [s0]+s[2:]+[s1]
|
||||
assert mr_loader.fts_query_conjunctive("black coffee") == '"black" "coffee"'
|
||||
assert len(mr_loader.chunk_text("x" * 80, 20, 3)) == 4
|
||||
assert mr_loader.norm_key(" Same TEXT ") == "same text"
|
||||
|
||||
|
||||
def test_mr_loader_score_and_fusion_through_cdylib():
|
||||
from rune import mr_loader, memory_store as ms
|
||||
|
||||
if not mr_loader.available():
|
||||
pytest.skip("memory_retrieval crate not built")
|
||||
dense = [[20, 0.9], [18, 0.78]]
|
||||
bm25 = [[7, -6.2]]
|
||||
fusion = mr_loader.rank_fusion(dense, bm25, ms.RRF_K)
|
||||
assert fusion["mode"] == "hybrid"
|
||||
rows = [{"id": i, "text": f"t{i}", "importance": 0.5,
|
||||
"last_accessed": "2026-10-04T11:00:00+00:00", "topic": "x",
|
||||
"entities": "[]", "source": "s", "memory_type": None,
|
||||
"confidence": 0.8, "temperature": 1.0} for i in (20, 18, 7)]
|
||||
out = mr_loader.score_recall_rows(fusion, rows, dense, bm25, 10, 0.42,
|
||||
"2026-10-04T12:00:00+00:00",
|
||||
ms.RECENCY_HALF_LIFE)
|
||||
assert isinstance(out, list) and out and "relevance" in out[0]
|
||||
|
||||
|
||||
def test_memory_store_helpers_delegate_to_kernel():
|
||||
from rune import memory_store as ms
|
||||
|
||||
py = ms._py_map_reduce([{"id": i, "score": i} for i in range(1, 13)], 5)
|
||||
rs = ms._map_reduce([{"id": i, "score": i} for i in range(1, 13)], 5)
|
||||
assert [r["id"] for r in py] == [r["id"] for r in rs]
|
||||
assert ms._fts_query_conjunctive("black coffee") == '"black" "coffee"'
|
||||
|
||||
|
||||
def test_mr_loader_chunk_projection_and_memory_store_delegation():
|
||||
from rune import memory_store as ms, mr_loader
|
||||
|
||||
if not mr_loader.available():
|
||||
pytest.skip("memory_retrieval crate not built")
|
||||
ranks = {5: 0.0625, 12: 0.05, 3: 0.0417}
|
||||
crows = [{"rowid": 5, "chunk_id": "c5", "text": "t" * 500, "wing": "w",
|
||||
"room": "r", "source_path": "p", "page": 7},
|
||||
{"rowid": 3, "chunk_id": "c3", "text": "u — héllo 🎸",
|
||||
"wing": "w2", "room": "", "source_path": "", "page": None}]
|
||||
py = ms._py_project_chunk_rows(ranks, crows, 6)
|
||||
rs = mr_loader.project_chunk_rows([list(r) for r in ranks.items()], crows, 6)
|
||||
assert py == rs
|
||||
entries = [{"id": i, "relevance": i} for i in range(1, 15)]
|
||||
research = [{"chunk_id": f"c{i}", "text": f"r{i}", "rrf": 0.1} for i in range(3)]
|
||||
assert ms._fuse_results(entries, research) == mr_loader.fuse_results(entries, research)
|
||||
|
||||
|
||||
def test_mr_loader_recall_kernel_via_stats_seam(tmp_path):
|
||||
import sqlite3 as _sq
|
||||
from rune import memory_store as ms, mr_loader
|
||||
|
||||
if not mr_loader.available():
|
||||
pytest.skip("memory_retrieval crate not built")
|
||||
db_path = str(tmp_path / "r.db")
|
||||
conn = _sq.connect(db_path)
|
||||
conn.execute("CREATE TABLE entries (id INTEGER PRIMARY KEY, text TEXT, "
|
||||
"importance REAL, created_at TEXT, last_accessed TEXT, "
|
||||
"topic TEXT, entities TEXT, source TEXT, "
|
||||
"status TEXT DEFAULT 'active', memory_type TEXT, "
|
||||
"confidence REAL, temperature REAL)")
|
||||
for i in range(1, 8):
|
||||
conn.execute("INSERT INTO entries (text, importance, created_at, "
|
||||
"last_accessed, topic, entities, source, confidence, "
|
||||
"temperature) VALUES (?,?,?,?,?,?,?,?,?)",
|
||||
(f"entry {i}", 0.5, "2026-10-01T00:00:00",
|
||||
"2026-10-03T00:00:00", f"topic{i%2}", "[]", "t",
|
||||
0.8, 1.0))
|
||||
conn.commit(); conn.close()
|
||||
dense = [[i, 0.9 - i * 0.05] for i in range(1, 8)]
|
||||
fusion = mr_loader.rank_fusion(dense, [], ms.RRF_K)
|
||||
rows = [{"id": i, "text": f"entry {i}", "importance": 0.5,
|
||||
"created_at": "2026-10-01T00:00:00",
|
||||
"last_accessed": "2026-10-03T00:00:00",
|
||||
"topic": f"topic{i%2}", "entities": "[]", "source": "t",
|
||||
"status": "active", "memory_type": None,
|
||||
"confidence": 0.8, "temperature": 1.0} for i in range(1, 8)]
|
||||
assert (ms._py_score_recall_rows(fusion, rows, dense, [], 5, 0.42,
|
||||
"2026-10-04T12:00:00+00:00")
|
||||
== mr_loader.score_recall_rows(fusion, rows, dense, [], 5, 0.42,
|
||||
"2026-10-04T12:00:00+00:00",
|
||||
ms.RECENCY_HALF_LIFE))
|
||||
|
||||
|
||||
def test_mr_loader_delegation_publics_exercised(tmp_path):
|
||||
from rune import memory_store as ms, mr_loader
|
||||
|
||||
if not mr_loader.available():
|
||||
pytest.skip("memory_retrieval crate not built")
|
||||
# every delegating public on the Rust path (core available in CI)
|
||||
assert ms._position_aware([{"id": 1}]) == [{"id": 1}]
|
||||
capped = ms.mr_rank_fusion([[1, 0.5]], [], 3)
|
||||
assert capped["mode"] == "dense-only"
|
||||
fusion = ms._rank_fusion([[1, 0.5]], [])
|
||||
assert fusion["mode"] == "dense-only"
|
||||
assert ms._project_chunk_rows({7: 0.5},
|
||||
[{"rowid": 7, "chunk_id": "c7", "text": "x" * 500,
|
||||
"wing": "w", "room": "r", "source_path": "s",
|
||||
"page": None}], 5)[0]["rrf"] == 0.5
|
||||
scored = ms._score_recall_rows(
|
||||
mr_loader.rank_fusion([[9, 0.85]], [], ms.RRF_K),
|
||||
[{"id": 9, "text": "z", "importance": 0.5,
|
||||
"last_accessed": "2026-10-04T11:00:00+00:00", "topic": "t",
|
||||
"entities": "[]", "source": "s", "memory_type": None,
|
||||
"confidence": 0.9, "temperature": 1.0}],
|
||||
[[9, 0.85]], [], 4, 0.42, "2026-10-04T12:00:00+00:00")
|
||||
assert scored and scored[0]["relevance"] > 0.05 # dense rrf scale: 0.85·1/(15+1)·blends
|
||||
|
||||
|
||||
|
||||
def test_mr_loader_python_oracle_paths_exercised(monkeypatch):
|
||||
"""The _py_ oracle bodies count toward the changed-lines floor — the
|
||||
crate canary exercises the RUST path only; this battery drives the
|
||||
oracle path (fallback = load-bearing discipline)."""
|
||||
from rune import memory_store as ms
|
||||
|
||||
monkeypatch.setenv("RUNE_RETRIEVAL_CORE", "python")
|
||||
|
||||
def oracle(mode="dense-only"):
|
||||
dense, bm25 = ([[9, 0.85]], []) if mode == "dense-only" else (
|
||||
([], [[9, -8.0]]) if mode == "lexical-only"
|
||||
else ([[9, 0.85]], [[9, -8.0]]))
|
||||
fusion = ms._py_rank_fusion(dense, bm25)
|
||||
rows = [{"id": 9, "text": "z", "importance": 0.5,
|
||||
"last_accessed": "2026-10-04T11:00:00+00:00",
|
||||
"topic": "t", "entities": "[]", "source": "s",
|
||||
"memory_type": None, "confidence": 0.9,
|
||||
"temperature": 1.0}]
|
||||
return (ms._score_recall_rows(fusion, rows, dense, bm25, 4, 0.42,
|
||||
"2026-10-04T12:00:00+00:00"),
|
||||
fusion, rows, dense, bm25)
|
||||
|
||||
s_d, fusion_d, rows_d, dense_d, _ = oracle("dense-only")
|
||||
assert s_d and s_d[0]["mode"] == "dense-only"
|
||||
s_l, _, _, _, _ = oracle("lexical-only")
|
||||
assert s_l and s_l[0]["relevance"] > 4.5 # lexical offset band ~4.69 with blends
|
||||
s_h, _, _, _, _ = oracle("hybrid")
|
||||
assert s_h
|
||||
# abstention paths
|
||||
rows_f = [{"id": 9, "text": "z", "importance": 0.5,
|
||||
"last_accessed": "2026-10-04T11:00:00+00:00", "topic": "t",
|
||||
"entities": "[]", "source": "s", "memory_type": None,
|
||||
"confidence": 0.9, "temperature": 1.0}]
|
||||
assert ms._py_score_recall_rows(ms._py_rank_fusion([], []), rows_f, [], [], 4, 0.42,
|
||||
"2026-10-04T12:00:00+00:00") == []
|
||||
# timestamp exception path (malformed)
|
||||
rows_bad = [dict(rows_f[0], last_accessed="not-a-date")]
|
||||
out_bad = ms._score_recall_rows(ms._py_rank_fusion([[9, 0.9]], []), rows_bad,
|
||||
[[9, 0.9]], [], 4, 0.42,
|
||||
"2026-10-04T12:00:00+00:00")
|
||||
assert out_bad[0]["relevance"] > 0
|
||||
# gap path: dense pair with big gap and mid band
|
||||
dense_gap = [[9, 0.72], [8, 0.60]]
|
||||
rows_g = rows_f + [dict(rows_f[0], id=8)]
|
||||
out_g = ms._score_recall_rows(ms._py_rank_fusion(dense_gap, []), rows_g,
|
||||
dense_gap, [], 4, 0.42,
|
||||
"2026-10-04T12:00:00+00:00")
|
||||
assert out_g[0]["id"] == 9
|
||||
# fusion with ties and the hybrid accumulation path
|
||||
assert ms._rank_fusion([[1, 0.5], [2, 0.5]], [[1, -5.0], [3, -6.0]])["ranks"]
|
||||
|
||||
|
||||
def test_mr_loader_chunk_sql_gather_through_seam(tmp_path, monkeypatch):
|
||||
"""chunk_recall's SQL gather through a real fixture db (covers 1634-1648)."""
|
||||
import sqlite3 as _sq
|
||||
from rune import memory_store as ms
|
||||
|
||||
db_path = str(tmp_path / "c.db")
|
||||
conn = _sq.connect(db_path)
|
||||
conn.row_factory = _sq.Row
|
||||
conn.execute("CREATE TABLE chunks (rowid_hint INTEGER PRIMARY KEY, "
|
||||
"chunk_id TEXT, doc_id TEXT, wing TEXT, room TEXT, "
|
||||
"source_path TEXT, start_line INT, end_line INT, page INT, "
|
||||
"text TEXT, content_hash TEXT, importance REAL, "
|
||||
"ingested_at TEXT)")
|
||||
# give real rowids: insert then record
|
||||
for cid, wing, text in (("a", "alpha", "chunk_a_text_worlds_worth_a_gun"),
|
||||
("b", "beta", "chunk_b_text")):
|
||||
conn.execute("INSERT INTO chunks (chunk_id, doc_id, wing, room, "
|
||||
"source_path, page, text, content_hash, importance, "
|
||||
"ingested_at) VALUES (?,?,?,?,?,?,?,?,?,?)",
|
||||
(cid, cid, wing, "room", "path", 3, text, "h", 0.5, "ts"))
|
||||
conn.commit()
|
||||
db = _sq.connect(db_path)
|
||||
db.row_factory = _sq.Row
|
||||
# chunks_vec is a sqlite-vec virtual table — absent in the test db.
|
||||
# The W2.0 ruling keeps vector execution in Python; the kernel parity
|
||||
# target is the RRF/projection stage. Drive chunk_recall WITHOUT a
|
||||
# qvec: the FTS+RRF stage still runs through the kernel.
|
||||
import rune.memory_store as _ms
|
||||
monkeypatch.setattr(_ms, "_embed", lambda texts: {})
|
||||
out = ms.chunk_recall(db, "text")
|
||||
assert isinstance(out, list)
|
||||
assert all("rrf" in r for r in out)
|
||||
db.close()
|
||||
|
||||
|
||||
# ── cc_loader / cognition_core broker kernels (R2 W3.1) ─────────────────────
|
||||
|
||||
|
||||
def test_cc_loader_estimator_and_budgets_through_cdylib():
|
||||
from rune import cc_loader
|
||||
|
||||
if not cc_loader.available():
|
||||
pytest.skip("cognition_core crate not built")
|
||||
assert cc_loader.default_estimator("hello world") == 2
|
||||
assert cc_loader.default_estimator("héllo wörld 🎸 emoji") == 4 # chars, not utf16
|
||||
assert cc_loader.default_budget(8192) == 8192 - 2048 - 409
|
||||
assert cc_loader.default_memory_budget(4096) == 512
|
||||
assert cc_loader.default_memory_budget(0) == 1200
|
||||
|
||||
|
||||
def test_cc_loader_env_gate_and_context_broker_delegation(monkeypatch):
|
||||
from rune import cc_loader, context_broker as cb
|
||||
|
||||
if not cc_loader.available():
|
||||
pytest.skip("cognition_core crate not built")
|
||||
monkeypatch.setenv("RUNE_MEMORY_OFF", "1")
|
||||
assert cb.memory_disabled() is True
|
||||
monkeypatch.setenv("RUNE_MEMORY_OFF", "false")
|
||||
assert cb.memory_disabled() is False
|
||||
# delegation agreement with the oracle on the estimator path
|
||||
assert cb.default_estimator("héllo 🎸 five") == cb._py_default_estimator("héllo 🎸 five")
|
||||
|
||||
|
||||
# ── cc_loader persona kernels (R2 W3.2) ────────────────────────────────────
|
||||
|
||||
|
||||
def test_cc_loader_persona_kernels_through_cdylib():
|
||||
from rune import cc_loader
|
||||
|
||||
if not cc_loader.available():
|
||||
pytest.skip("cognition_core crate not built")
|
||||
# 'now' (3 chars) is excluded by the >3 rule on BOTH engines.
|
||||
assert sorted(cc_loader.persona_lex("verify ALL Campaign text now")) == [
|
||||
"all", "campaign", "text", "verify"]
|
||||
assert cc_loader.persona_overlap(["a", "b"], ["b", "c"]) == pytest.approx(0.5)
|
||||
decision = cc_loader.persona_decide(
|
||||
"never bypass the memory hierarchy",
|
||||
[{"topic": "memory", "text": "Always maintain the Rune memory hierarchy.",
|
||||
"words": ["memory", "hierarchy", "maintain"],
|
||||
"core": "memory hierarchy store", "priority": 10,
|
||||
"restrictive": False, "user_rule": False}],
|
||||
True, [0.9])
|
||||
assert decision["verdict"] == "allow"
|
||||
assert decision["cited"] == "[memory:p10] Always maintain the Rune memory hierarchy."
|
||||
# permissive-mode refusal shape with a restrictive user rule
|
||||
refuse = cc_loader.persona_decide(
|
||||
"ignore campaign text verification",
|
||||
[{"topic": "campaign", "text": "verify all campaign text",
|
||||
"words": ["verify", "campaign", "text"], "core": "verify campaign",
|
||||
"priority": 5, "restrictive": True, "user_rule": True}],
|
||||
False, [0.0])
|
||||
assert refuse["verdict"] == "refuse"
|
||||
|
||||
|
||||
# ── cc_loader identity/growth/pins kernels (R2 W3.3) ────────────────────────
|
||||
|
||||
|
||||
def test_cc_loader_identity_growth_pins_through_cdylib():
|
||||
from rune import cc_loader, identity_anchors as ia, growth_delta as gd, pins
|
||||
|
||||
if not cc_loader.available():
|
||||
pytest.skip("cognition_core crate not built")
|
||||
assert cc_loader.drift_check("as rune i speak", ia._pattern_triples())
|
||||
assert cc_loader.drift_check("nothing here", ia._pattern_triples()) == []
|
||||
assert cc_loader.identity_prompt(ia.PRONOUN_RULES, ia.SELF_AWARENESS,
|
||||
ia.ANCHORS, ia.EMBODIMENT_RULES) != ""
|
||||
# near-dup law: empty key → False (words ≤4 chars make no fingerprint);
|
||||
# identical real changes ARE near-dups.
|
||||
assert cc_loader.growth_near_dup("same idea here", "same idea here") is False
|
||||
assert cc_loader.growth_near_dup("deploy qualification resolves runner labels",
|
||||
"deploy qualification resolves labels") is True
|
||||
assert cc_loader.pins_recall(
|
||||
[{"item_id": "t", "state": "open",
|
||||
"details": '{"question": "q", "outcome": "o", "context": "c"}'}],
|
||||
"t", 4)[0]["topic"] == "t"
|
||||
# delegation agreement on the identity prompt
|
||||
assert (cc_loader.identity_prompt(ia.PRONOUN_RULES, ia.SELF_AWARENESS,
|
||||
ia.ANCHORS, ia.EMBODIMENT_RULES)
|
||||
== ia._py_get_identity_prompt())
|
||||
|
||||
|
||||
def test_growth_delta_reflect_apply_profile_oracles(tmp_path, monkeypatch):
|
||||
"""reflect/growth_profile oracle lines — deltas file + llm stubbed."""
|
||||
import json
|
||||
from rune import growth_delta as gd
|
||||
|
||||
monkeypatch.setenv("RUNE_COGNITION_CORE", "python")
|
||||
monkeypatch.setattr(gd, "DELTAS_FILE", tmp_path / "deltas.json")
|
||||
monkeypatch.setattr(gd, "DELTAS_FILE", str(tmp_path / "deltas.json"))
|
||||
(tmp_path / "deltas.json").write_text(json.dumps(
|
||||
{"applied": [], "pending": [], "last_read_back": None}))
|
||||
# the [:3] per-pass cap is a REAL gate — the persona delta rides in the
|
||||
# first three entries so the fixture exercises it.
|
||||
monkeypatch.setattr(gd, "_llm", lambda material: json.dumps({"deltas": [
|
||||
{"change": "relay in plain english always for delivery",
|
||||
"confidence": 0.9, "target": "delivery", "evidence": "e1"},
|
||||
{"change": "personal guidance for the persona topic",
|
||||
"confidence": 0.8, "target": "persona", "evidence": "e2"},
|
||||
{"change": "tiny", "confidence": 0.9, "target": "delivery"},
|
||||
]}))
|
||||
out = gd.reflect("material", dry_run=True)
|
||||
assert len(out["would_apply"]) == 2 and out["dry_run"] is True
|
||||
out2 = gd.reflect("material", dry_run=False)
|
||||
assert len(out2["applied"]) == 2
|
||||
# profile from the applied deltas (file was written by apply)
|
||||
prof = gd._py_growth_profile(100)
|
||||
assert prof and prof[0]["target"] == "delivery"
|
||||
|
||||
|
||||
def test_identity_anchors_check_drift_oracle_paths():
|
||||
from rune import identity_anchors as ia
|
||||
|
||||
# every prefix class via the full text
|
||||
text = ("i am rune. you are nick. i believe in my opinion. "
|
||||
"you're absolutely right! my apologies, hope this helps.")
|
||||
out = ia._py_check_drift(text)
|
||||
classes = {line.split(":")[0] for line in out}
|
||||
assert {"DRIFT", "WEAKNESS", "SYCOPHANCY"} <= classes
|
||||
assert ia._py_check_drift("nothing to see") == []
|
||||
|
||||
|
||||
def test_pins_project_and_unpin_oracles(tmp_path, monkeypatch):
|
||||
import json
|
||||
from rune import pins
|
||||
|
||||
recs = [{"kind": "pin", "item_id": "topic-a", "state": "open",
|
||||
"details": json.dumps({"question": "q", "outcome": "o",
|
||||
"context": "ctx here"})},
|
||||
{"kind": "pin", "item_id": "topic-b", "state": "resolved",
|
||||
"details": json.dumps({"context": "done"})}]
|
||||
monkeypatch.setattr(pins, "_load", lambda: recs)
|
||||
# _project covers the blob-parse + KeyError-safe defaults
|
||||
proj = pins._project(recs[0])
|
||||
assert proj == {"topic": "topic-a", "question": "q", "outcome": "o",
|
||||
"context": "ctx here", "status": "open", "reason": ""}
|
||||
# unpin through the fixture store
|
||||
monkeypatch.setattr(pins, "_save", lambda records: None)
|
||||
result = pins.unpin("topic-a", reason="done")
|
||||
assert result.get("unpinned") is True
|
||||
|
||||
|
||||
|
||||
def test_growth_delta_error_paths(tmp_path, monkeypatch):
|
||||
"""The loader-probe error branches + reflect malformed paths."""
|
||||
import json
|
||||
from rune import growth_delta as gd, cc_loader
|
||||
|
||||
# the loader error branches run when the import fails
|
||||
# the REAL loader-probe branches: make the import fail + make
|
||||
# available() raise, so the probe's except branches execute
|
||||
monkeypatch.setenv("RUNE_COGNITION_CORE", "python")
|
||||
assert gd._cc_core() is None # the pinned-fallback branch (158-159)
|
||||
monkeypatch.setenv("RUNE_COGNITION_CORE", "auto")
|
||||
# import-failure branch: `from rune import cc_loader` resolves via the
|
||||
# package attribute first — set it to a marker whose import raises.
|
||||
import rune as _rune_pkg
|
||||
monkeypatch.setattr(_rune_pkg, "cc_loader", None, raising=False)
|
||||
assert gd._cc_core() is None # the ImportError probe branch (160-163)
|
||||
|
||||
assert gd._near_dup({"change": "deploy qualification resolves labels"},
|
||||
{"change": "deploy qualification resolves runner labels"}) is True
|
||||
# profile: empty state
|
||||
monkeypatch.setattr(gd, "_load_deltas", lambda: {"profile": []})
|
||||
assert gd._py_growth_profile(100) == []
|
||||
# profile: token budget exhaustion
|
||||
deltas = [{"change": f"a longer change number {i} here", "target": "delivery"}
|
||||
for i in range(3)]
|
||||
monkeypatch.setattr(gd, "_load_deltas",
|
||||
lambda: {"profile": deltas})
|
||||
out = gd._py_growth_profile(8)
|
||||
assert len(out) >= 1 and len(out) < 3 # budget cut, never exceeded
|
||||
# reflect: malformed llm json -> no crash (0 deltas path)
|
||||
monkeypatch.setattr(gd, "_llm", lambda m: "not json")
|
||||
out = gd.reflect("material", dry_run=True)
|
||||
assert out["extracted"] == []
|
||||
|
||||
Reference in new issue
Block a user