Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4db3442
feat(sentinel): add provenance-aware learning model
tuxevil Sep 7, 2026
752adbd
feat(sentinel): persist learned memories and skill lifecycle
tuxevil Sep 7, 2026
4437790
feat(sentinel): implement memory validation and skill lifecycle
tuxevil Sep 7, 2026
2bcaae5
test(sentinel): enforce learning safety boundaries
tuxevil Sep 7, 2026
d394e79
feat(api): expose audited Sentinel learning lifecycle
tuxevil Sep 7, 2026
9ecd2c8
chore(ci): finalize Sentinel learning wiring
tuxevil Sep 7, 2026
59dd733
fix(ci): remove stale learning imports before validation
tuxevil Sep 7, 2026
f7e3bbf
feat(sentinel): wire learning lifecycle into Case runner
github-actions[bot] Sep 7, 2026
ef269e7
chore(ci): harden Sentinel learning persistence
tuxevil Sep 7, 2026
c95ae25
fix(ci): match Sentinel history retention SQL
tuxevil Sep 7, 2026
912f8c7
fix(ci): use regex for Sentinel retention hardening
tuxevil Sep 7, 2026
dbb055d
fix(sentinel): harden learning retention and promotion metrics
github-actions[bot] Sep 7, 2026
2a4692b
chore(ci): remove temporary Sentinel learning hardener
tuxevil Sep 7, 2026
81125e4
chore(ci): remove temporary Sentinel learning finalizer
tuxevil Sep 7, 2026
ad0d61e
docs(sentinel): document provenance-aware learning lifecycle
tuxevil Sep 7, 2026
6328985
chore(ci): preserve cross-Case learning provenance
tuxevil Sep 7, 2026
771e44f
chore(dev): add one-shot learning provenance patch
tuxevil Sep 7, 2026
23f4346
chore(ci): run one-shot learning provenance patch
tuxevil Sep 7, 2026
67b3a69
fix(ci): make Sentinel provenance patch whitespace-agnostic
tuxevil Sep 7, 2026
406f841
fix(sentinel): preserve cross-Case learning provenance
github-actions[bot] Sep 7, 2026
dde507c
chore(ci): remove one-shot Sentinel provenance workflow
tuxevil Sep 7, 2026
f252c2d
chore(ci): remove temporary Sentinel provenance fixer
tuxevil Sep 7, 2026
0e70aba
chore: remove Sentinel provenance patch helper
tuxevil Sep 7, 2026
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
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ ALLOW_LEGACY_PROVISION=false
# Keep it stable; changing it makes existing AI keys unreadable.
# AI_ENGINE_ENCRYPTION_KEY=

# ── Sentinel learning ─────────────────────────────────────────────────────────
# Optional asynchronous curation of Case evidence into CANDIDATE memories and
# DRAFT skills. Disabled by default. Enabling it also requires an explicit
# curation route configured through the Sentinel model router (#20).
# SENTINEL_AUTO_CURATION=false


# ── SuperAdmin bootstrap ──────────────────────────────────────────────────────
# If unset, a random password is generated and logged on first boot.
Expand Down
1 change: 1 addition & 0 deletions cmd/openwrt-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
sentinelStopCh := make(chan struct{})
services.StartSentinelCaseContextRecovery(sentinelStopCh)
services.StartSentinelOptionalModelTaskWorker(sentinelStopCh)
services.StartSentinelLearningMaintenance(sentinelStopCh)
defer close(sentinelStopCh)

// Build the route mux and wrap it with the metrics middleware.
Expand All @@ -131,7 +132,7 @@
tlsEnabled := *tlsCert != "" && *tlsKey != ""
if *requireTLS && !tlsEnabled {
logger.Error("REQUIRE_TLS is set but --tls-cert/--tls-key are missing; refusing to start on plain HTTP")
os.Exit(1)

Check failure on line 135 in cmd/openwrt-controller/main.go

View workflow job for this annotation

GitHub Actions / Go Backend

exitAfterDefer: os.Exit will exit, and `defer close(sentinelStopCh)` will not run (gocritic)

Check failure on line 135 in cmd/openwrt-controller/main.go

View workflow job for this annotation

GitHub Actions / Go Backend

exitAfterDefer: os.Exit will exit, and `defer close(sentinelStopCh)` will not run (gocritic)
}

srv := &http.Server{
Expand Down
203 changes: 203 additions & 0 deletions docs/SENTINEL_LEARNING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# Sentinel Learning

Sentinel learning is designed to improve investigations without creating a second source of truth or allowing learned content to expand controller authority.

## Memory planes

Sentinel keeps four concerns separate:

1. **Authoritative World State** — current OMEGA/controller state queried from trusted controller data sources. Learned content never writes this plane.
2. **Episodic memory** — `sentinel_cases`, their evidence ledger, outcomes, conversations, and timestamps.
3. **Learned memory** — reusable generalizations stored in `sentinel_learned_memories` with evidence provenance, confidence, scope, validation state, counter-evidence, TTL, and supersession metadata.
4. **Procedural skills** — declarative investigation recipes in `sentinel_skills`.

Only `VALIDATED` learned memories and `TRUSTED` skills are exposed to the Context Compiler. They are serialized as `learned_knowledge`, never as `authoritative_state` and never as instructions.

## Hard trust boundary

The write path is intentionally one-way:

```text
model/tool output
CANDIDATE memory / DRAFT skill
controller validation
historical replay
live SHADOW evaluation
TRUSTED artifact
```

A model response or tool result cannot write directly to trusted memory or create an immediately trusted skill.

Learning code cannot modify the Tool Registry, Safety Kernel, policy/trust roots, proposal approval boundary, executor, verification, or rollback mechanisms.

## Learned memory lifecycle

States:

```text
CANDIDATE → VALIDATED → SUPERSEDED
│ │
├→ REJECTED └→ CANDIDATE (new counter-evidence)
└→ EXPIRED
```

A learned-memory candidate contains:

- source Case;
- Case/site/device scope;
- statement;
- confidence in `[0,1]`;
- evidence references into Case evidence ledgers;
- counter-evidence references;
- provenance;
- creator/timestamps;
- validation state;
- TTL / expiry;
- optional superseding memory.

The default TTL is 30 days and the controller maximum is 365 days. An hourly maintenance sweep expires stale candidate/validated memories.

Adding valid counter-evidence to a `VALIDATED` memory immediately demotes it to `CANDIDATE`, removing it from model context until it is replaced or deliberately resolved. A superseding memory must itself be validated and have the same scope.

The normal Sentinel history-retention sweep preserves a resolved source Case while that Case is still required by an unexpired candidate/validated memory or an active skill. This keeps provenance available for the lifetime of learned knowledge.

## Skill format

Skills are data interpreted by trusted controller code. Schema version 1 contains only:

```json
{
"schema_version": 1,
"name": "wan-loss-rca",
"description": "Collect the read-only evidence normally useful for WAN loss cases.",
"match": {
"sources": ["log_anomaly"],
"severities": ["high", "critical"],
"keywords": ["packet loss"]
},
"evidence_tools": [
"get_device_status",
"get_incidents"
]
}
```

Unknown JSON fields are rejected. A skill cannot contain shell, Python, Lua, Go, SQL, HTTP requests, UCI commands, arbitrary command strings, credentials, policies, prompts that override controller policy, or executable code.

`evidence_tools` may reference only tools that already exist in the trusted Tool Registry and whose side-effect class is `none`. Learning therefore cannot manufacture a new primitive capability.

Even for a trusted skill, arguments are not stored in the skill. The Context Compiler reconstructs arguments from the active Case site/device scope and applies its normal global tool budget. A trusted skill can therefore suggest *which existing read-only evidence source to inspect*, not where or how to execute arbitrary work.

## Skill lifecycle

```text
DRAFT → VALIDATED → SHADOW → TRUSTED → DEPRECATED
│ │ │ │
└─────────┴──────────┴─────────┴→ REVOKED
```

### DRAFT

A human or optional curator may create a draft. Draft creation grants no runtime effect.

### VALIDATED

Static controller validation requires:

- schema version 1;
- valid bounded selectors;
- 1–4 evidence tools;
- every tool present in the trusted Tool Registry;
- every tool strictly read-only;
- no unknown executable fields.

### Historical replay

A validated skill can be replayed against past Cases. Replay reads only the persisted Case evidence ledger and ignores evidence whose `captured_at` is later than the selected historical `as_of` timestamp. Replay never executes a live tool.

A skill needs at least 3 matching historical Cases with an aggregate success ratio of at least 0.80 and zero unsafe evaluations before it may enter `SHADOW`.

Promotion accounting is based on **distinct Cases**, using the latest evaluation per `(mode, case)`. Replaying the same Case repeatedly cannot inflate promotion thresholds.

### SHADOW

Shadow skills are evaluated on live Cases only after the production investigation has completed and its evidence has been persisted. Shadow evaluation compares the skill recipe with evidence already collected by the production path:

- it does not request extra tools;
- it does not change compiled context;
- it does not change the answer;
- it does not create proposals;
- it has no execution authority.

A skill requires at least 5 matching shadow Cases, a shadow success ratio of at least 0.80, the replay threshold above, and zero unsafe evaluations before it can be promoted.

### TRUSTED

Trusted skills may contribute their already-validated read-only tool names to the Context Compiler. The compiler still enforces its global evidence-tool budget and Case-scoped argument construction.

Static safety validation is re-run when a trusted skill is loaded. If its referenced Tool Registry contract is no longer safe/available, it stops affecting the investigation even before an operator revokes it.

## Optional model curation

Issue #20 provides the optional `curation` reasoning class. #21 uses it as a teacher only, never as a trust authority.

Manual curation can be queued through:

```text
POST /api/sentinel/cases/{case_id}/curate
```

Automatic curation is disabled by default and is enabled with:

```text
SENTINEL_AUTO_CURATION=true
```

A curation route must also be explicitly configured through the model router. Because optional model tasks use the durable queue from #20, Internet/cloud unavailability does not block normal local Sentinel operation; the optional task is retried later.

The curator must return strict JSON containing at most five memory candidates and five skill drafts. It may cite only evidence IDs already present in the source Case evidence ledger. The controller independently verifies every cited evidence ID and clamps the artifact scope to the source Case before persisting it.

Imported artifacts always start as:

- memory: `CANDIDATE`;
- skill: `DRAFT`.

The curator has no API or internal path that can mark them `VALIDATED`, `SHADOW`, or `TRUSTED`.

## Context Compiler integration

For every Case investigation the compiler can include:

- unexpired `VALIDATED` memories that match tenant/site/device scope;
- `TRUSTED` skills whose declarative selectors match the Case.

Both are emitted under the `learned_knowledge` trust class with provenance and identifiers. They never overwrite the Case scope or authoritative OMEGA observations.

Trusted skills are merged into the normal prefetch plan only until the existing Context Compiler maximum of four read-only prefetches is reached. The model tool-call budget and Safety Kernel remain unchanged.

## API authorization

Read endpoints for memories, skills, and evaluation history require normal authenticated access.

Creating candidates/drafts, validating/rejecting/superseding memories, replaying or changing skill lifecycle state, and queueing curation require `ADMIN`.

## Safety invariants

The following must remain true in future changes:

- World State is never populated from learned memory.
- Model/tool output cannot bypass candidate/draft state.
- Learned memory cannot change its own validation state.
- Skills cannot add Tool Registry entries or side-effecting primitives.
- Skills cannot supply arbitrary tool arguments.
- Historical replay cannot see future evidence.
- Shadow mode cannot affect production behavior.
- Promotion thresholds are deterministic and based on distinct Cases.
- Counter-evidence removes contradicted learned memory from trusted context.
- Revocation is terminal and available from every non-revoked skill state.
- Optional cloud curation is not required for normal Sentinel operation.
Loading
Loading