Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

All notable changes to GBrain will be documented in this file.

## [0.42.63.3] - 2026-07-22

**Eva Brain install success now means the brain is callable, not that every optional content-maintenance cycle has run.**

### Fixed

- **Installer health now proves callability without hiding runtime failures.** The updater permits only explicit content-maintenance gaps (`sync_freshness`, `cycle_freshness`, and `links_extraction_lag`) after source-aware search succeeds. Unknown, schema, migration, index, database, and malformed doctor results still fail the install.
- **Non-actionable taxonomy drift no longer fails doctor.** `type_proliferation` stays blocking only when the active schema pack has a built-in successor; otherwise the report identifies custom taxonomy drift without suggesting a no-op onboard command.
- **Removed stale source-freshness calls.** The Eva updater no longer invokes `sources cycle-freshness` or `sources sync-freshness`, which current upstream GBrain does not expose.

## [0.42.63.2] - 2026-07-22

**Eva Brain installs now finish cleanly against upstream GBrain 0.42.63.1.**
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.42.63.2
0.42.63.3
6 changes: 6 additions & 0 deletions docs/downstream-carry-patches.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ Eva Brain uses upstream GBrain as its core. Core changes in this file are tempor
- Reason: only a truly missing `pages` table means an empty brain. Other database failures must surface instead of being reported as zero pages.
- Removal condition: upstream distinguishes missing-table errors from unexpected query/database failures.

## Actionable type-proliferation diagnostics

- Files: `src/core/onboard/checks.ts`, `test/onboard-pack-upgrade-checks.test.ts`
- Reason: a current schema pack with no built-in successor cannot remediate custom type drift through `gbrain onboard`. The diagnostic must report the observed and declared type counts without failing the brain or recommending a no-op command.
- Removal condition: upstream makes type-proliferation severity depend on an available pack successor or another concrete, previewable remediation.

## Install-time migration policy

- File: `package.json`
Expand Down
2 changes: 1 addition & 1 deletion openclaw.plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "gbrain",
"name": "gbrain",
"version": "0.42.63.2",
"version": "0.42.63.3",
"description": "Eva Brain/GBrain skills and personal knowledge brain with provider-neutral hybrid search",
"family": "bundle-plugin",
"configSchema": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
"bun": ">=1.3.10"
},
"license": "MIT",
"version": "0.42.63.2",
"version": "0.42.63.3",
"overrides": {
"@hono/node-server": "2.0.10",
"body-parser": "^2.3.0",
Expand Down
2 changes: 1 addition & 1 deletion plugins/gbrain-codex/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gbrain-codex",
"version": "0.42.63.2",
"version": "0.42.63.3",
"description": "Full-surface Codex Desktop adapter for a local Eva Brain/GBrain install.",
"author": {
"name": "Electric Sheep",
Expand Down
2 changes: 1 addition & 1 deletion plugins/gbrain-codex/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@eva-brain/gbrain-codex",
"version": "0.42.63.2",
"version": "0.42.63.3",
"description": "Codex Desktop local plugin adapter for Eva Brain/GBrain.",
"type": "module",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion plugins/openclaw-gbrain/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@eva-brain/openclaw-gbrain",
"version": "0.42.63.2",
"version": "0.42.63.3",
"description": "OpenClaw native plugin for Eva Brain/GBrain search, query, and OAuth-backed media extraction.",
"type": "module",
"main": "index.js",
Expand Down
38 changes: 36 additions & 2 deletions scripts/eva-brain-health.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ const WORKSPACE_DOCS_QUERY = process.env.EVA_BRAIN_WORKSPACE_DOCS_QUERY || 'runb
const DEFAULT_TIMEOUT_MS = 30_000;
const CANONICAL_WORKSPACE_DOCS_PATH = '/root/.openclaw/workspace/docs';
const CANONICAL_WORKSPACE_RUNBOOKS_PATH = '/root/.openclaw/workspace/docs/runbooks';
const ADVISORY_DOCTOR_FAILURES = new Set([
Comment thread
100yenadmin marked this conversation as resolved.
'cycle_freshness',
'links_extraction_lag',
'sync_freshness',
Comment thread
100yenadmin marked this conversation as resolved.
Outdated
]);

const requireOpenClaw = process.argv.includes('--require-openclaw') || process.env.EVA_BRAIN_REQUIRE_OPENCLAW === 'true';
const allowMissingSupportKb = process.argv.includes('--allow-missing-support-kb') || process.env.EVA_BRAIN_ALLOW_MISSING_SUPPORT_KB === 'true';
Expand Down Expand Up @@ -295,11 +300,35 @@ function main() {
const pluginInspect = run(openclaw, ['plugins', 'inspect', 'gbrain', '--runtime', '--json'], {
timeoutMs: 15_000,
});
const doctorReport = parseJson(doctor.stdout, null);
const doctorFailures = Array.isArray(doctorReport?.checks)
? doctorReport.checks
.filter(check => check?.status === 'fail')
.map(check => ({
name: String(check.name ?? 'unknown'),
category: String(check.category ?? 'unknown'),
message: String(check.message ?? ''),
}))
: [];
const doctorDiagnosticAvailable = Boolean(
Comment thread
100yenadmin marked this conversation as resolved.
Array.isArray(doctorReport?.checks) &&
!doctor.timedOut &&
doctor.signal == null,
);
const doctorBlockingFailures = doctorFailures.filter(
failure => !ADVISORY_DOCTOR_FAILURES.has(failure.name),
);
const doctorExitAcceptable = Boolean(
Comment thread
100yenadmin marked this conversation as resolved.
doctor.ok ||
(doctorFailures.length > 0 && doctorBlockingFailures.length === 0),
);

const report = {
ok: Boolean(
version.ok &&
doctor.ok &&
doctorDiagnosticAvailable &&
doctorExitAcceptable &&
doctorBlockingFailures.length === 0 &&
sourcesResult.ok &&
(!requireSupportKb ||
(supportKb &&
Expand All @@ -318,7 +347,12 @@ function main() {
version: version.stdout.trim(),
versionOk: version.ok,
doctorOk: doctor.ok,
doctor: parseJson(doctor.stdout, null),
doctorGate: 'advisory-content-only',
doctorDiagnosticAvailable,
doctorExitAcceptable,
doctorFailures,
doctorBlockingFailures,
doctor: doctorReport,
},
pages: {
total: totalPages,
Expand Down
61 changes: 17 additions & 44 deletions scripts/update-local-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,23 @@ doctor() {
return
fi
stop_stale_serve_if_requested
run env GBRAIN_SKILLS_DIR="$INSTALL_DIR/skills" "$HOME/.bun/bin/gbrain" doctor --json
local output
local cmd=(env GBRAIN_SKILLS_DIR="$INSTALL_DIR/skills" "$HOME/.bun/bin/gbrain" doctor --json)
printf '+'
printf ' %q' "${cmd[@]}"
printf '\n'
if [ "$DRY_RUN" = "true" ]; then
return
fi
if output="$("${cmd[@]}" 2>&1)"; then
printf '%s\n' "$output"
return
fi
printf '%s\n' "$output"
if [ "$RUN_HEALTH" = "false" ]; then
die "Doctor failed and --skip-health disabled the structured failure classifier. Rerun without --skip-health or repair the reported doctor failure."
fi
log "Doctor reported brain/content readiness gaps; continuing to the source-aware runtime health gate."
Comment thread
100yenadmin marked this conversation as resolved.
}

health_report() {
Expand All @@ -364,10 +380,6 @@ health_report() {
if [ "$WITH_WORKSPACE_DOCS" = "true" ] || { [ "$WITH_WORKSPACE_DOCS" = "auto" ] && [ -d "$WORKSPACE_DOCS_DIR" ]; }; then
require_workspace_docs="true"
fi
if [ "$RUN_HEALTH" = "auto" ] && [ "$WITH_SUPPORT_KB" != "true" ] && [ "$require_workspace_docs" != "true" ]; then
log "Skipping source-aware health report because no source package was requested or detected"
return
fi
local health_args=()
Comment thread
100yenadmin marked this conversation as resolved.
if [ "$WITH_OPENCLAW" = "true" ]; then
health_args+=(--require-openclaw)
Expand Down Expand Up @@ -556,43 +568,6 @@ install_support_kb() {
run node "$kb_dir/scripts/status.mjs"
run "$HOME/.bun/bin/gbrain" sync --repo "$kb_dir" --source openclaw-support-kb --no-embed
embed_support_kb_if_provider_auth_available
disable_source_cycle_freshness_if_supported openclaw-support-kb
}

disable_source_cycle_freshness_if_supported() {
disable_source_freshness_if_supported "$1" cycle-freshness
}

disable_source_sync_freshness_if_supported() {
disable_source_freshness_if_supported "$1" sync-freshness
}

disable_source_freshness_if_supported() {
local source_id="$1"
local freshness_command="$2"
local output
local cmd=("$HOME/.bun/bin/gbrain" sources "$freshness_command" "$source_id" off)
printf '+'
printf ' %q' "${cmd[@]}"
printf '\n'
if [ "$DRY_RUN" = "true" ]; then
log "Dry-run: skipping optional $freshness_command disable execution"
return
fi
if output="$("${cmd[@]}" 2>&1)"; then
printf '%s\n' "$output"
return
fi
local normalized_output
normalized_output="$(printf '%s' "$output" | tr -d '\r' | sed -e 's/[[:space:]]*$//')"
local first_line
first_line="$(printf '%s\n' "$normalized_output" | sed -n '1p')"
if [ "$first_line" = "Unknown sources subcommand: $freshness_command" ]; then
log "Skipping $freshness_command disable; installed gbrain does not expose 'sources $freshness_command'."
return
fi
printf '%s\n' "$output" >&2
return 1
}

install_workspace_docs() {
Expand Down Expand Up @@ -621,8 +596,6 @@ install_workspace_docs() {
fi
run "$HOME/.bun/bin/gbrain" import "$WORKSPACE_DOCS_DIR" --source-id "$WORKSPACE_DOCS_SOURCE" --no-embed
embed_source_if_provider_auth_available "$WORKSPACE_DOCS_SOURCE" "Workspace docs"
disable_source_cycle_freshness_if_supported "$WORKSPACE_DOCS_SOURCE"
disable_source_sync_freshness_if_supported "$WORKSPACE_DOCS_SOURCE"
}

main() {
Expand Down
2 changes: 1 addition & 1 deletion skills/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gbrain",
"version": "0.42.63.2",
"version": "0.42.63.3",
"conformance_version": "1.0.0",
"description": "Personal knowledge brain with hybrid RAG search \u2014 GStack mod for agent platforms",
"skills": [
Expand Down
45 changes: 43 additions & 2 deletions src/core/onboard/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface OnboardCheckResult {
name: string;
status: 'ok' | 'warn' | 'fail';
message: string;
details?: Record<string, unknown>;
};
remediations: RemediationStep[];
}
Expand Down Expand Up @@ -461,15 +462,29 @@ export async function checkTypeProliferation(
engine: BrainEngine,
): Promise<OnboardCheckResult> {
let declared = 15; // fallback to gbrain-base-v2 default if pack unavailable
let activeName: string | null = null;
let activeIdentity: string | null = null;
let builtInRemediationAvailable = false;
let successorIdentity: string | null = null;
try {
const { loadActivePack } = await import('../schema-pack/load-active.ts');
const { loadActivePack, findPackSuccessors } = await import('../schema-pack/load-active.ts');
let dbConfig: string | undefined;
try {
dbConfig = (await engine.getConfig('schema_pack')) ?? undefined;
} catch { /* tolerate pre-config brains */ }
const active = await loadActivePack({ cfg: null, remote: false, dbConfig })
.catch(() => null);
if (active) declared = active.manifest.page_types.length;
if (active) {
declared = active.manifest.page_types.length;
activeName = active.manifest.name;
activeIdentity = active.identity;
const successors = await findPackSuccessors(active.manifest.name, active.manifest.version)
.catch(() => []);
if (successors.length > 0) {
builtInRemediationAvailable = true;
successorIdentity = successors[0]!.identity;
}
}
} catch {
// Use fallback.
}
Expand All @@ -479,15 +494,39 @@ export async function checkTypeProliferation(
);
const warn = declared + 5;
const fail = declared * 2;
const details = {
distinct_type_count: n,
declared_type_count: declared,
active_pack_name: activeName,
active_pack_identity: activeIdentity,
built_in_remediation_available: builtInRemediationAvailable,
successor_identity: successorIdentity,
};
if (!builtInRemediationAvailable && n > warn) {
Comment thread
100yenadmin marked this conversation as resolved.
Outdated
return {
check: {
name: 'type_proliferation',
status: 'ok',
Comment thread
100yenadmin marked this conversation as resolved.
Outdated
message:
`${n} distinct page types (pack declares ${declared}); ` +
`active pack ${activeIdentity ?? activeName ?? 'unknown'} has no built-in type-unification successor. ` +
`Treat as custom taxonomy drift unless you define a custom pack with mapping_rules.`,
details,
},
remediations: [],
};
}
if (n > fail) {
return {
check: {
name: 'type_proliferation',
status: 'fail',
message:
`${n} distinct page types (pack declares ${declared}). ` +
(successorIdentity ? `Built-in successor available: ${successorIdentity}. ` : '') +
`Run \`gbrain onboard --check --explain\` to preview a pack upgrade ` +
`or define a custom pack with mapping_rules.`,
details,
},
remediations: [], // pack_upgrade_available check emits the actionable step
};
Expand All @@ -498,6 +537,7 @@ export async function checkTypeProliferation(
name: 'type_proliferation',
status: 'warn',
message: `${n} distinct page types vs ${declared} declared in pack — consider unification.`,
details,
},
remediations: [],
};
Expand All @@ -507,6 +547,7 @@ export async function checkTypeProliferation(
name: 'type_proliferation',
status: 'ok',
message: `${n} distinct typed values (pack declares ${declared})`,
details,
},
remediations: [],
};
Expand Down
Loading
Loading