fix(demo): frame the control decision and the branch endings clearly
Some checks failed
Tests / Declarative: Post Actions testing.tests.test_repo_structure.test_knowledge_service_mirror_matches_source failed
Some checks failed
Tests / Declarative: Post Actions testing.tests.test_repo_structure.test_knowledge_service_mirror_matches_source failed
Five corrections to how the monitor explains itself, plus code-demo support. The authorization is now described as what it is: a match between an action Ariadne already has code to perform, an action id Hermes is permitted to request, and the action Hermes actually recommended. Hermes cannot add to that registry, and the recommendation proceeds only because it names something already in it. The editorial line about pull requests is gone. The repair now reads as a change rather than a value: the field said unhealthy when the build failed and says healthy because Ariadne just patched it. The rebuild stage says plainly that the operational branch is complete and that neither the human-required response nor the optional source proposal is entered, rather than leaving the reader to infer it from silence. Inspectable outputs states that on the chart it is the 'records and artifacts' edge out of the whole response box, not out of one branch - every path ends there. The layout makes it look like it belongs to the proposal path alone. follows hermes-code-demo, which takes the proposal branch: the stages now read as a patch proposal and a pull request instead of being mislabelled an escalation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7d40355ff6
commit
4e3be5f7e4
@ -6,7 +6,7 @@
|
|||||||
# hermes_triage_demo.sh status # current incident/alert state, no changes
|
# hermes_triage_demo.sh status # current incident/alert state, no changes
|
||||||
# hermes_triage_demo.sh preflight # confirm the lab is ready to demo
|
# hermes_triage_demo.sh preflight # confirm the lab is ready to demo
|
||||||
# hermes_triage_demo.sh reset # restore the demo to its pre-run state
|
# hermes_triage_demo.sh reset # restore the demo to its pre-run state
|
||||||
# hermes_triage_demo.sh monitor # stream the flow chart stages live
|
# hermes_triage_demo.sh monitor [code] # stream the flow chart stages live
|
||||||
#
|
#
|
||||||
# FIRST RUN: copy hermes_triage_demo.env.example to hermes_triage_demo.env in
|
# FIRST RUN: copy hermes_triage_demo.env.example to hermes_triage_demo.env in
|
||||||
# this directory and fill it in. That file is git-ignored precisely so it can
|
# this directory and fill it in. That file is git-ignored precisely so it can
|
||||||
@ -78,7 +78,11 @@ for line in sys.stdin:
|
|||||||
print(" ", d["timestamp"][11:19], d.get("jobs"))' | tail -"${2:-5}"
|
print(" ", d["timestamp"][11:19], d.get("jobs"))' | tail -"${2:-5}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# `monitor` follows the fixture job; `monitor code` follows the code-proposal
|
||||||
|
# job, which takes the source-proposal branch of the chart instead.
|
||||||
cmd_monitor() {
|
cmd_monitor() {
|
||||||
|
local which="${1:-fixture}"
|
||||||
|
[ "$which" = "code" ] && export MONITOR_JOB="$CODE_JOB"
|
||||||
exec python3 "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/hermes_triage_monitor.py"
|
exec python3 "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/hermes_triage_monitor.py"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,6 +289,6 @@ case "${1:-}" in
|
|||||||
status) cmd_status ;;
|
status) cmd_status ;;
|
||||||
preflight) cmd_preflight ;;
|
preflight) cmd_preflight ;;
|
||||||
reset) cmd_reset ;;
|
reset) cmd_reset ;;
|
||||||
monitor) cmd_monitor ;;
|
monitor) shift; cmd_monitor "$@" ;;
|
||||||
*) sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//' ; exit 1 ;;
|
*) sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//' ; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@ -288,14 +288,16 @@ def evidence_for(key: str, incident: str = "") -> None:
|
|||||||
print(f" {DIM}Hermes holds no Git or Kubernetes write access; this JSON is its"
|
print(f" {DIM}Hermes holds no Git or Kubernetes write access; this JSON is its"
|
||||||
f" entire output{RESET}\n")
|
f" entire output{RESET}\n")
|
||||||
elif key == "gates":
|
elif key == "gates":
|
||||||
print(f" {DIM}authorized/authorize_reason above is the policy result: the verdict"
|
print(f" {DIM}the authorization is a match between three separate things: an action"
|
||||||
f" Ariadne reached on its own reading{RESET}")
|
f" Ariadne already has code to perform, an action id Hermes is permitted to"
|
||||||
|
f" request, and the action Hermes actually recommended. Ariadne holds the"
|
||||||
|
f" registry below; Hermes cannot add to it, and the recommendation only"
|
||||||
|
f" proceeds because it names something already in it.{RESET}")
|
||||||
run(["kubectl", "-n", NS_ARIADNE, "exec", "deploy/ariadne", "-c", "ariadne", "--",
|
run(["kubectl", "-n", NS_ARIADNE, "exec", "deploy/ariadne", "-c", "ariadne", "--",
|
||||||
"printenv", "ARIADNE_HERMES_ALLOWED_ACTIONS"], limit=2)
|
"printenv", "ARIADNE_HERMES_ALLOWED_ACTIONS"], limit=2)
|
||||||
run(["kubectl", "-n", NS_ARIADNE, "exec", "deploy/ariadne", "-c", "ariadne", "--",
|
run(["kubectl", "-n", NS_ARIADNE, "exec", "deploy/ariadne", "-c", "ariadne", "--",
|
||||||
"printenv", "ARIADNE_HERMES_MIN_CONFIDENCE"], limit=2)
|
"printenv", "ARIADNE_HERMES_MIN_CONFIDENCE"], limit=2)
|
||||||
print(f" {DIM}only these two ids may ever be executed. Source fixes are not actions:"
|
print()
|
||||||
f" they become pull requests and are never executed by Ariadne.{RESET}\n")
|
|
||||||
elif key == "route":
|
elif key == "route":
|
||||||
print(f" {DIM}the fixture repair is an operational action, so the Optional source"
|
print(f" {DIM}the fixture repair is an operational action, so the Optional source"
|
||||||
f" proposal branch is not taken for this incident{RESET}\n")
|
f" proposal branch is not taken for this incident{RESET}\n")
|
||||||
@ -303,12 +305,20 @@ def evidence_for(key: str, incident: str = "") -> None:
|
|||||||
run(["kubectl", "-n", NS_DEMO, "get", "cm", "hermes-triage-demo-fixture",
|
run(["kubectl", "-n", NS_DEMO, "get", "cm", "hermes-triage-demo-fixture",
|
||||||
"-o", "jsonpath={.data.state}"])
|
"-o", "jsonpath={.data.state}"])
|
||||||
if key == "response":
|
if key == "response":
|
||||||
print(f" {DIM}Scoped ConfigMap repair on the chart: one merge patch to one"
|
print(f" {DIM}that value read 'unhealthy' when the build failed - the seeded"
|
||||||
f" ConfigMap, in process, no pod created{RESET}\n")
|
f" fault - and reads 'healthy' above because Ariadne has just patched it."
|
||||||
|
f" That single field changing is the repair.{RESET}\n")
|
||||||
if key == "outputs":
|
if key == "outputs":
|
||||||
|
print(f" {DIM}on the chart this is the 'records and artifacts' edge out of the"
|
||||||
|
f" whole Ariadne response box, not out of one branch. Every path ends"
|
||||||
|
f" here: an executed action, an escalation, or a pull request all record"
|
||||||
|
f" the same audit events and metrics.{RESET}")
|
||||||
print(f" {YELLOW}issues filed by triage: {GITEA}/bstein/ariadne/issues{RESET}\n")
|
print(f" {YELLOW}issues filed by triage: {GITEA}/bstein/ariadne/issues{RESET}\n")
|
||||||
elif key == "verify":
|
elif key == "verify":
|
||||||
print(f" {DIM}exactly one rebuild is triggered; it never retries in a loop{RESET}\n")
|
print(f" {DIM}exactly one rebuild is triggered; it never retries in a loop. This"
|
||||||
|
f" completes the operational branch: because the action was authorized and"
|
||||||
|
f" performed, neither the human-required response nor the optional source"
|
||||||
|
f" proposal is entered for this incident.{RESET}\n")
|
||||||
|
|
||||||
|
|
||||||
class Monitor:
|
class Monitor:
|
||||||
@ -373,14 +383,40 @@ def main() -> None:
|
|||||||
)
|
)
|
||||||
monitor.mark("verify", "one rebuild triggered with seeding disabled")
|
monitor.mark("verify", "one rebuild triggered with seeding disabled")
|
||||||
if status == "human_required":
|
if status == "human_required":
|
||||||
|
reason = str(state.get("reason") or "")
|
||||||
|
proposed = reason == "code_fix_proposed"
|
||||||
monitor.mark("evidence", "bundle collected")
|
monitor.mark("evidence", "bundle collected")
|
||||||
monitor.mark("hermes", "diagnosis returned")
|
|
||||||
monitor.mark("gates", f"Ariadne refused: {state.get('reason', '')} — nothing ran")
|
|
||||||
monitor.mark(
|
monitor.mark(
|
||||||
"route",
|
"hermes",
|
||||||
"policy result: refused -> Diagnosis and next checks -> Ariadne opens an issue",
|
"patch proposed as data: a path, an exact anchor and a replacement"
|
||||||
)
|
if proposed
|
||||||
monitor.mark("response", "escalated; issue filed in the service repository")
|
else "diagnosis returned",
|
||||||
|
)
|
||||||
|
monitor.mark(
|
||||||
|
"gates",
|
||||||
|
"no action was authorized; a source fix is not an action, so this takes"
|
||||||
|
" the proposal branch rather than the registry"
|
||||||
|
if proposed
|
||||||
|
else f"Ariadne refused: {reason} - nothing ran",
|
||||||
|
)
|
||||||
|
monitor.mark(
|
||||||
|
"route",
|
||||||
|
"policy result: no action -> Optional source proposal -> Patch validator"
|
||||||
|
if proposed
|
||||||
|
else "policy result: refused -> Diagnosis and next checks -> opens an issue",
|
||||||
|
)
|
||||||
|
monitor.mark(
|
||||||
|
"response",
|
||||||
|
"Ariadne opens a pull request; nothing merges without a human"
|
||||||
|
if proposed
|
||||||
|
else "escalated; issue filed in the service repository",
|
||||||
|
)
|
||||||
|
if proposed:
|
||||||
|
monitor.mark(
|
||||||
|
"verify",
|
||||||
|
"the branch build validates the proposal; the incident stays"
|
||||||
|
" human-required either way",
|
||||||
|
)
|
||||||
if status == "healthy" and state.get("resolved") and not monitor.summarised:
|
if status == "healthy" and state.get("resolved") and not monitor.summarised:
|
||||||
monitor.mark("verify", "rebuild finished green")
|
monitor.mark("verify", "rebuild finished green")
|
||||||
monitor.mark("outputs", f"resolved: {', '.join(state['resolved'])}")
|
monitor.mark("outputs", f"resolved: {', '.join(state['resolved'])}")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user