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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,8 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Thi
## [Unreleased]

### Added
- A/B fallback update contract v0.1 (TRUST FABRIC W9.2): `UpdateSlot` (one of exactly two slots, carrying the GPT priority-boot attribute triple `bootPriority`/`triesRemaining`/`successful`, the installed payload digest, and a deliberate `role` vs `currentlyRunning` split so the fallback slot stays describable during a trial boot), `UpdateTransaction` (one apply attempt: write target, pinned probe, per-attempt boot record naming where each failure fell back to, terminal `promoted`/`rolled-back`/`refused` outcome with a closed `rollbackReason` set), and `UpdateHealthProbe` (the digest-pinned promotion gate: non-empty check set with at least one blocking check, mandatory hardware+software watchdog pair enforced by two `contains` clauses, `evaluatedIn` closed to post-boot userspace, `onProbeUnavailable` closed to `fail`). **Normative invariant — the currently-good slot is never overwritten by the update being applied** — enforced three ways: by schema within a document (a top-level `not`/`anyOf` enumerating the two illegal `(fromSlot, toSlot)` pairs, plus `UpdateSlot`'s `state: writing` ⇒ `role: candidate`), by schema on the settle path (four if/then clauses pinning `settledOnSlot` to `fromSlot` on rollback/refusal and to `toSlot` on promotion), and across documents by the validator (a settled transaction's `preservedPayloadDigest` still equals the active slot's `payloadDigest`). The attempt budget follows the GPT attribute — decremented by the bootloader *before* control transfers, so a payload that hangs before userspace still consumes an attempt — and `refused` is terminal, which is what ends the boot loop. Includes a refused-update and a promoted-update example set telling two coherent end-to-end stories, fourteen negative conformance vectors (`fixtures/ab-update/conformance.json`), a `validate-ab-update-examples` target whose probe-digest check is *recomputed* rather than read back, and a normative spec note (`specs/ab-fallback-update-contract.md`). Reference implementation: `AbUpdateMachine` in `sourceos-boot`.
- `make validate` now also runs the duplicate schema `$id` guardrail, which previously ran only in CI — a local run could not reproduce the check that gates the PR.
- KnowledgeNugget contract v0.1 (the estate's L2 content grain): warrant-typed knowledge fragments generalizing the production IFM warrant-typed extraction — content-addressed source spans (`docRef` + span + `sha256-` content hash), a closed four-kind warrant taxonomy (`direct-quote`/`computed`/`inferred`/`model-generated`) with evidence refs and confidence, ontology type refs (`kkoTypeRefs`), normalized `canonicalPayload`, typed provenance chain links, and `wallTime`/`logicalTime` carried verbatim from the MPCC `ConversationEvent` envelope (parity machine-enforced). Normative: `model-generated` nuggets MUST stay visibly distinguishable downstream (admissibility discounting), and `computed`/`inferred` warrants must cite evidence (schema-enforced). Includes direct-quote and model-generated examples, negative conformance vectors (`fixtures/knowledge-nugget/conformance.json`), a `validate-knowledge-nugget-examples` target, and a normative spec note (`specs/knowledge-nugget-contract.md`).
- SemanticAction contract v0.1 (the declarative typed-action registry for the NL→plan compiler): ontology-typed inputs and output (KKO concept URIs recommended, shared with `KnowledgeNugget.kkoTypeRefs`), a closed constraint taxonomy (`subClassOf`/`instanceOf`/`sameAs` — polymorphism via subsumption), executor binding, registry metadata (owner + deprecated), and a two-value effect posture: actions are side-effect-free at plan-search time, and `sideEffects: "effect-request"` declares the executor emits an MPCC `EffectRequest` and defers to an `EffectDecision` rather than acting directly — no direct-mutation vocabulary exists (validator-pinned). Includes pure-lookup and effect-request examples, negative conformance vectors (`fixtures/semantic-action/conformance.json`), a `validate-semantic-action-examples` target, and a normative spec note (`specs/semantic-action-contract.md`).
- MPCC event contract v0.1 (conversation + trading event family): `ConversationEvent` (the canonical 26-field conversation-fabric event — causal parents, authority context with delegation chain, visibility scope, requested/approved/actual effect references, modality, speech act), `EffectRequest` / `EffectDecision` / `EffectRecord` (the requested → approved → actual → compensated effect lifecycle with idempotency keys, referencing `PolicyDecision` / `ExecutionDecision` rather than duplicating them), `NullAbsenceRecord` (12-kind null/absence taxonomy), and the trading families `MarketDataEvent`, `OrderIntent`, `ExecutionReport`, `PositionChange`, `ReconciliationRecord` as profiles of the ConversationEvent envelope (one shared envelope vocabulary; parity machine-enforced). Includes canonical examples telling one end-to-end governed trade story, negative conformance vectors (`fixtures/mpcc-event-contract/conformance.json`), a `validate-mpcc-event-examples` target, and a normative spec note (`specs/mpcc-event-contract.md`). Provenance: SocioProphet/profit-mpcc, hardened to the policy-integrity tranche-0001 strictness bar.
Expand Down
15 changes: 13 additions & 2 deletions Makefile
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
.PHONY: validate validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples
.PHONY: validate validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-duplicate-schema-ids

validate: validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples
validate: validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-duplicate-schema-ids
@echo "OK: validate"

validate-ab-update-examples:
python3 -m pip install --user jsonschema >/dev/null
python3 tools/validate_ab_update_examples.py

# The duplicate-$$id guardrail already runs in CI (.github/workflows/validate.yml)
# but was not reachable from `make validate`, so a local run could not reproduce
# the check that gates the PR. Wiring it in costs nothing and removes a way for
# local and CI verdicts to disagree.
validate-duplicate-schema-ids:
python3 scripts/check_duplicate_schema_ids.py

validate-knowledge-nugget-examples:
python3 -m pip install --user jsonschema >/dev/null
python3 tools/validate_knowledge_nugget_examples.py
Expand Down
59 changes: 59 additions & 0 deletions examples/update_health_probe.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
{
"id": "urn:srcos:update-health-probe:sourceos_node_v1",
"type": "UpdateHealthProbe",
"specVersion": "0.1.0",
"definitionDigest": "sha256:2e0672e76fbc68c30cad6542a5f0a778596cb8700e77a222715738d4731da86c",
"evaluatedIn": "post-boot-userspace",
"onProbeUnavailable": "fail",
"timeoutSeconds": 180,
"minConsecutivePasses": 2,
"description": "Promotion gate for SourceOS fog-node images and for Noetica desktop installs. Both targets run the same five checks because both fail the same way: a payload that starts, answers one request, and then cannot reach its control plane.",
"checks": [
{
"name": "supervisor-alive",
"kind": "process-liveness",
"blocking": true,
"description": "The node supervisor reached its ready state and has stayed there for the probe window."
},
{
"name": "local-api-200",
"kind": "endpoint-health",
"blocking": true,
"description": "The local control endpoint answers with a 200 and reports the payload version this transaction wrote."
},
{
"name": "state-store-readable",
"kind": "data-integrity",
"blocking": true,
"description": "The persistent state store opens and its schema version is one this payload can serve. A payload that boots but cannot read the state it inherited is a brick with a login prompt."
},
{
"name": "control-plane-reachable",
"kind": "connectivity",
"blocking": true,
"description": "The target reached its control plane at least once. Blocking on purpose: an edge node that cannot be reached cannot be remotely rolled back, so promoting it converts a recoverable fault into a site visit."
},
{
"name": "fallback-slot-bootable",
"kind": "rollback-capability",
"blocking": true,
"description": "The other slot still holds a digest-verified payload with a non-zero boot priority. Checked BEFORE promotion because promotion is the moment the previous payload stops being the guaranteed way back."
}
],
"watchdogs": [
{
"kind": "software",
"timeoutSeconds": 90,
"pettedBy": "urn:srcos:component:node_supervisor_health_loop",
"expiryAction": "reboot-to-fallback",
"description": "Petted only by the health loop after a full passing check sweep, never on a timer. A supervisor that pets on a schedule proves the supervisor is alive and says nothing about the payload."
},
{
"kind": "hardware",
"timeoutSeconds": 300,
"pettedBy": "urn:srcos:component:node_supervisor_health_loop",
"expiryAction": "reboot",
"description": "Independent SoC timer. Longer than the software timeout so the software watchdog gets the first, attributable word; it exists for the case where the kernel wedges and the software watchdog can never run to fire."
}
]
}
19 changes: 19 additions & 0 deletions examples/update_slot.fog07_a_active.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
{
"id": "urn:srcos:update-slot:fog_edge_07_a",
"type": "UpdateSlot",
"specVersion": "0.1.0",
"targetRef": "urn:srcos:node:sourceos_fog_edge_07",
"slot": "A",
"role": "active",
"state": "good",
"bootPriority": 15,
"triesRemaining": 0,
"successful": true,
"currentlyRunning": true,
"payloadDigest": "sha256:b73d34fdc15b73c8efeb4527811459b62addf6e4c4a69730f81244ff0beab97e",
"payloadRef": "urn:srcos:image:sourceos_node_2026.07.3",
"version": "2026.07.3",
"installedAt": "2026-07-14T11:40:02.000Z",
"lastBootedAt": "2026-07-27T02:26:59.000Z",
"lastProbeVerdict": "pass"
}
19 changes: 19 additions & 0 deletions examples/update_slot.fog07_b_unbootable.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
{
"id": "urn:srcos:update-slot:fog_edge_07_b",
"type": "UpdateSlot",
"specVersion": "0.1.0",
"targetRef": "urn:srcos:node:sourceos_fog_edge_07",
"slot": "B",
"role": "candidate",
"state": "unbootable",
"bootPriority": 0,
"triesRemaining": 0,
"successful": false,
"currentlyRunning": false,
"payloadDigest": "sha256:9da88dc197887a52961b7846083b868e0a2e4ed0f1846abdfa6e9f4d566c66d0",
"payloadRef": "urn:srcos:image:sourceos_node_2026.07.4",
"version": "2026.07.4",
"installedAt": "2026-07-27T02:17:11.000Z",
"lastBootedAt": "2026-07-27T02:26:12.000Z",
"lastProbeVerdict": "fail"
}
19 changes: 19 additions & 0 deletions examples/update_slot.noetica_a_fallback.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
{
"id": "urn:srcos:update-slot:noetica_a41_a",
"type": "UpdateSlot",
"specVersion": "0.1.0",
"targetRef": "urn:srcos:install:noetica_desktop_a41",
"slot": "A",
"role": "candidate",
"state": "good",
"bootPriority": 14,
"triesRemaining": 0,
"successful": true,
"currentlyRunning": false,
"payloadDigest": "sha256:aa850dde865a39601a8b2f5af88cfb18878a59d91f4fc01b2e465826da90d356",
"payloadRef": "urn:srcos:release:noetica_desktop_1.8.2",
"version": "1.8.2",
"installedAt": "2026-06-30T18:22:40.000Z",
"lastBootedAt": "2026-07-28T09:01:12.000Z",
"lastProbeVerdict": "pass"
}
19 changes: 19 additions & 0 deletions examples/update_slot.noetica_b_active.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
{
"id": "urn:srcos:update-slot:noetica_a41_b",
"type": "UpdateSlot",
"specVersion": "0.1.0",
"targetRef": "urn:srcos:install:noetica_desktop_a41",
"slot": "B",
"role": "active",
"state": "good",
"bootPriority": 15,
"triesRemaining": 0,
"successful": true,
"currentlyRunning": true,
"payloadDigest": "sha256:22e07d29331b31e37a137ce875de35689ad1d719690cc7a0a6e592a76cb7fcb8",
"payloadRef": "urn:srcos:release:noetica_desktop_1.9.0",
"version": "1.9.0",
"installedAt": "2026-07-28T09:07:55.000Z",
"lastBootedAt": "2026-07-28T09:08:21.000Z",
"lastProbeVerdict": "pass"
}
29 changes: 29 additions & 0 deletions examples/update_transaction.promoted.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
{
"id": "urn:srcos:update-transaction:noetica_a41_0007",
"type": "UpdateTransaction",
"specVersion": "0.1.0",
"targetRef": "urn:srcos:install:noetica_desktop_a41",
"fromSlot": "A",
"toSlot": "B",
"preservedPayloadDigest": "sha256:aa850dde865a39601a8b2f5af88cfb18878a59d91f4fc01b2e465826da90d356",
"candidatePayloadDigest": "sha256:22e07d29331b31e37a137ce875de35689ad1d719690cc7a0a6e592a76cb7fcb8",
"healthProbeRef": "urn:srcos:update-health-probe:sourceos_node_v1",
"healthProbeDigest": "sha256:2e0672e76fbc68c30cad6542a5f0a778596cb8700e77a222715738d4731da86c",
"maxAttempts": 2,
"outcome": "promoted",
"rollbackReason": null,
"openedAt": "2026-07-28T09:02:00.000Z",
"settledAt": "2026-07-28T09:14:38.000Z",
"settledOnSlot": "B",
"receiptRef": "urn:srcos:reasoning:receipt:noetica_a41_update_0007",
"attempts": [
{
"attemptNumber": 1,
"startedAt": "2026-07-28T09:08:21.000Z",
"result": "pass",
"fellBackTo": null,
"triesRemainingAfter": 1,
"detail": "All five blocking checks passed on two consecutive sweeps, satisfying minConsecutivePasses; successful set by userspace."
}
]
}
37 changes: 37 additions & 0 deletions examples/update_transaction.refused.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
{
"id": "urn:srcos:update-transaction:fog_edge_07_0042",
"type": "UpdateTransaction",
"specVersion": "0.1.0",
"targetRef": "urn:srcos:node:sourceos_fog_edge_07",
"fromSlot": "A",
"toSlot": "B",
"preservedPayloadDigest": "sha256:b73d34fdc15b73c8efeb4527811459b62addf6e4c4a69730f81244ff0beab97e",
"candidatePayloadDigest": "sha256:9da88dc197887a52961b7846083b868e0a2e4ed0f1846abdfa6e9f4d566c66d0",
"healthProbeRef": "urn:srcos:update-health-probe:sourceos_node_v1",
"healthProbeDigest": "sha256:2e0672e76fbc68c30cad6542a5f0a778596cb8700e77a222715738d4731da86c",
"maxAttempts": 2,
"outcome": "refused",
"rollbackReason": "attempts-exhausted",
"openedAt": "2026-07-27T02:10:00.000Z",
"settledAt": "2026-07-27T02:31:44.000Z",
"settledOnSlot": "A",
"receiptRef": "urn:srcos:reasoning:receipt:fog_edge_07_update_0042",
"attempts": [
{
"attemptNumber": 1,
"startedAt": "2026-07-27T02:18:03.000Z",
"result": "probe-failed",
"fellBackTo": "A",
"triesRemainingAfter": 1,
"detail": "control-plane-reachable failed: no successful control-plane call within the 180s probe window."
},
{
"attemptNumber": 2,
"startedAt": "2026-07-27T02:26:12.000Z",
"result": "watchdog-expired",
"fellBackTo": "A",
"triesRemainingAfter": 0,
"detail": "software watchdog expired after 90s without a pet; expiryAction reboot-to-fallback zeroed the candidate's remaining tries."
}
]
}
Loading
Loading