Skip to content

feat(doctor): add --deep runtime diagnostics and middleware slot matrix - #1046

Merged
PurpleCHOIms merged 4 commits into
mainfrom
feat/doctor-deep
Oct 22, 2026
Merged

PurpleCHOIms merged 4 commits into
mainfrom
feat/doctor-deep

Conversation

@PurpleCHOIms

Copy link
Copy Markdown
Member

Partially addresses #1040

Root cause

Conditional middleware slots (KG, HITL, model_fallback) fail silently at assembly time — their factories return None plus one log line and the slot is absent. The host-side doctor only saw Docker/config/auth/LangGraph reachability; kg-health covered KG alone. Operators couldn't tell which of the 20 slots resolved for any role.

What

Python runtime (packages/decepticon/decepticon/diagnostics.py):

  • deep_report()/slot_matrix(): read-only matrix for all 26 roles, evaluating the same conditional guards (HITL env toggle, fallback chains, KG config/reachability) without constructing agents or creating engagement state.
  • KG read-only reachability probe via a diagnostics-scoped count.
  • python -m decepticon.diagnostics emits JSON and exits 0/1.

Launcher:

  • Context-aware compose.ExecCapture for read-only service exec.
  • decepticon doctor --deep folds the runtime report into checks: runtime_kg, runtime_skillogy, runtime_hitl, runtime_model_fallback, runtime_mcp_auth, runtime_slot_matrix, with recovery hints.
  • Stack-down degrades to an optional failed check; existing doctor behavior is unchanged.

Verification

  • Python module import/diagnostic smoke test under uv workspace (no Neo4j: reports KG absent, Skillogy unreachable, 26 roles and slot matrix still emitted).
  • Go build + vet pass.
  • Existing readiness test failure reproduced on a clean baseline (environment-dependent, unrelated to this change).

Follow-up

In-session /doctor (scope/ROE/OPPLAN/workflow pins/checkpoints/budget) remains a separate client UX follow-up, as proposed in #1040.

…MCP auth)

Root cause of the visibility gap: conditional middleware slots (KG, HITL,
model_fallback) fail silently at assembly time — the factory returns None
plus one log line and the slot is simply absent. The host doctor could not
see any of it, and kg-health covered only the KG.

Python side (packages/decepticon/decepticon/diagnostics.py):
- deep_report()/slot_matrix(): for all 26 configured roles, report which of
  the 20 slots resolve; conditional slots are evaluated against the same
  guard conditions the factories use (HITL env toggle, fallback chains,
  KGStore config) — no agent construction, no fake engagement state.
- KG reachability probed read-only via a diagnostics-scoped count.
- CLI: python -m decepticon.diagnostics (JSON, exit code 0/1).

Launcher side:
- compose.ExecCapture: capture output of a service exec (context-aware).
- decepticon doctor --deep: folds the runtime report into the doctor
  checks (runtime_kg, runtime_skillogy, runtime_hitl, runtime_model_fallback,
  runtime_mcp_auth, runtime_slot_matrix) with per-component recovery hints;
  stack-down degrades to an optional failed check, not an error.

Addresses #1040 (host half; in-session /doctor to follow)
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-21T07:18:16.269385Z bd787e1 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bd787e1231

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// langgraph container (python -m decepticon.diagnostics) and folds the
// result into the doctor report. Missing stack is not an error here: the
// base checks already report service status.
func addDeepRuntimeChecks(ctx context.Context, report *doctorReport) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Wire the deep option into the doctor command

The launcher command in doctor.go still registers only --json and calls diagnose unconditionally, and a repository-wide search finds no caller of addDeepRuntimeChecks. Consequently decepticon doctor --deep is rejected as an unknown flag and none of the newly added runtime diagnostics can be reached; register the flag and invoke this function when it is set.

Useful? React with 👍 / 👎.

Comment on lines +392 to +395
out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("%s compose exec %s: %w", c.Runtime.Name, service, err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve diagnostic JSON on nonzero exit

When KG or enabled Skillogy is unhealthy, diagnostics.py deliberately prints the component report and exits 1, but cmd.Output() returns that stdout alongside an ExitError and this branch discards it. These are exactly the failure cases deep doctor must explain, yet users receive only a generic compose-exec error instead of the KG/Skillogy details and slot matrix; retain and parse stdout for expected diagnostic exit failures.

Useful? React with 👍 / 👎.

Comment on lines +48 to +54
for role in SLOTS_PER_ROLE:
chain = os.environ.get(f"DECEPTICON_MODEL_{role.upper()}_FALLBACK", "").strip()
roles[role] = chain
if chain:
any_chain = True
return {
"ok": any_chain,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Compute fallback status per actual role assignment

This does not match the runtime guard, which resolves each role's fallback_models through LLMFactory.get_fallback_models() from the configured credential chain. A normal installation with multiple authentication methods can therefore have active fallback middleware while no per-role environment variable exists and be reported absent; conversely, one role-specific variable makes any_chain mark the slot resolved for every role. Derive the result per role from the same model assignments used during agent construction.

Useful? React with 👍 / 👎.

Comment on lines +26 to +29
// addDeepRuntimeChecks runs the read-only diagnostics module inside the
// langgraph container (python -m decepticon.diagnostics) and folds the
// result into the doctor report. Missing stack is not an error here: the
// base checks already report service status.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Record the deep diagnostics change in CHAGELOG

This commit adds a user-visible launcher option and diagnostic behavior but leaves the root CHAGELOG.md unchanged. Add the proposed change and PR link under Unreleased as required by the repository's versioned-change policy.

AGENTS.md reference: AGENTS.md:L3-L8

Useful? React with 👍 / 👎.

Comment thread packages/decepticon/decepticon/diagnostics.py Fixed
mschoi added 2 commits October 22, 2026 19:10
- register the --deep flag: addDeepRuntimeChecks existed but nothing
  called it, so the whole in-container diagnostics surface was dead code
- _truthy(None) now reads False: str(None) is "none", which silently
  passed the falsy set — unset HITL reported OK and unset Skillogy
  failed instead of reporting the filesystem fallback
- model_fallback resolves through LLMFactory.get_fallback_models (the
  credential-chain mapping assembly actually feeds the middleware)
  instead of the nonexistent DECEPTICON_MODEL_<ROLE>_FALLBACK env var,
  so the report reflects the operator's real fallback chains
@PurpleCHOIms
PurpleCHOIms merged commit bdd8bb5 into main Oct 22, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants