190 Commits

Author SHA1 Message Date
8f00545828 hermes: add a fail-closed full-handoff acceptance harness
Decides whether the Hermes platform handoff is fit to release, and refuses
to round an absence of evidence up to a pass.

The harness is read-only by default and classifies 71 checks PASS / FAIL /
NOT_RUN / NOT_APPLICABLE. Any mandatory FAIL or NOT_RUN is NO_GO, and so is a
harness-level problem: an unreachable vantage, a catalog entry whose evidence
no longer exists, an expired deadline, or an evaluator that raised.

Evidence comes from two vantages that cannot cover for each other: an external
read-only operator kubeconfig, and the Hermes agent probing itself from inside
its own pod. Before any check runs, the harness asks each vantage who it is and
stops if they are the same principal, because dual-vantage evidence from one
identity is a restatement rather than a corroboration. `--as` is rejected for
every operator-side command and reachable only as the inner command of a
`kubectl exec`, so impersonation can never stand in for a real self-probe. A
deny check needs a live refused request, not only an authorization review.

Two safety properties are structural rather than conventional, enforced where
an argv becomes a subprocess: the default mode mutates nothing (mutating verbs
require a server dry run; there is deliberately no live TokenRequest probe,
because a successful one would mint a real credential), and no probe can pull a
credential value into a report (no vault/sops/curl, secrets readable only with
-o name, environment probes list names, shell only through frozen reviewed
templates). Captures are bounded before they are screened, and the rendered
report is re-screened before it is written.

Mutation lives behind a separate arming flag with an exact confirmation phrase,
a caller-supplied unique ref, a preflight that refuses a protected push target
before any network call, and a cleanup whose verification is itself mandatory.
A default run reports those four checks NOT_RUN.

The catalog is declarative so a reviewer reads what is asserted rather than how
it is plumbed, and so structural properties can be proven over every entry
before a run. Catalog drift surfaces as NOT_RUN, which stops the release.

docs/hermes_full_handoff_acceptance.md carries the merge order for PRs #14-#18
on top of the merged #13 baseline, the image build and Flux rollout, the
rollback point for each step, the go/no-go checklist, and the limits that are
asserted rather than exercised.

Validation: 295 handoff tests pass with 100% line coverage on all 15 new
modules; the full unit suite is 647 passed with two failures that reproduce
unchanged on origin/main; Ruff, py_compile, kustomize render, and a diff
credential screen are clean; a live read-only run against Atlas returns NO_GO
for the pre-merge cluster with no unscreened fields in the report.
2026-08-17 10:14:17 +00:00
Hermes Agent
750dfa241f hermes: fail closed on kanban created-event producer drift
The sticky-block gate added in the previous commit classifies a task from
the `created` event payload that upstream `create_task` writes. That
producer is code we do not own, so trusting it silently was the gap: if
upstream renamed the key, dropped it, or stopped deriving it from
`initial_status`, the image would still build and ship a consumer that
mis-classifies every task it reads.

Anchor the producer contract at build time, before the regression suite
runs, with three assert-only preconditions: the `initial_status="blocked"`
park resolves `task_status` to `"blocked"`, every non-park creation
resolves it to something else, and the `created` event carries that same
variable under `"status"`. None of them rewrite the producer.

Textual anchors cannot see dataflow, so add the runtime net the reviewer
asked for. The suite now drives the real API: create + claim an ordinary
task, trip the circuit breaker once at failure_limit=1 so it parks with a
`gave_up` event (leaving its own `created` event as the most recent
create/block/unblock row), then recompute at failure_limit=2 and require
promotion to ready. That case is red under an unconditional-true created
predicate and red under producer drift that labels every created event
blocked, while the explicit block/unblock, dependency-promotion and
circuit-breaker-at-current-limit cases stay green. Non-blocked and
malformed created payloads are pinned as controls, and the gate now
rejects non-dict payloads rather than trusting `.get`.

Also make the live placement correction durable: titan-04 is cordoned
after repeated kernel undervoltage and kubelet failure and titan-19 was
probe/Longhorn unstable under worker load, so both join the hard NotIn
list; titan-05 is healthy but sits at 3592m/3600m requested CPU, so the
main hermes container gives back 50m (350m -> 300m) to schedule there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 22:42:18 +00:00
Hermes Agent
4f8dcfbbf7 hermes: harden worker isolation and blocked-task semantics
Three narrowly scoped Hermes reliability fixes backed by live evidence
from the Cassandra/titan-iac proof run.

Worker concurrency. Three simultaneous direct CLI workers on the 4-core
hermes-agent node drove load to ~45 and made the hermes and oauth2-proxy
containers fail their probes, leaving the pod 8/10 Ready; two workers
stayed at 10/10. Cap HERMES_CLI_LANE_CONCURRENCY at 2 and lower the
cli-lane-runner CPU limit from 3 to 2 so the dashboard and auth sidecars
keep a guaranteed share of the node. Requests are unchanged: the pod
still asks for 745m total, so placement does not move.

Service links. Kubernetes injects a service-link variable pair for every
service in the namespace, and hermes-claude-broker produces
HERMES_CLAUDE_BROKER_PORT=tcp://10.43.31.76:9006 — a value the broker
parses as an int. That contaminated worker and test environments even
though the deployment already addresses every service by DNS name. Set
enableServiceLinks: false on the hermes-agent pod spec.

Blocked-task scheduling. create_task(initial_status="blocked") records a
created event carrying status=blocked but never a blocked event, while
_has_sticky_block() only inspects blocked/unblocked events. recompute_ready()
considers blocked tasks, so an explicitly parked task with no incomplete
parent auto-promoted on the next dispatcher cycle. Teach _has_sticky_block()
to also recognize a created event whose payload status is blocked, which
covers tasks created before this image patch without adding a persisted
field. Dependency-driven promotion and the circuit-breaker failure-limit
guard are untouched; unblock_task() still releases either kind of block.

hermes-kanban-blocked-regression.py runs against the real upstream
kanban_db API during the image build, so the build fails if any of these
semantics regress.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 20:53:22 +00:00
jenkins
0dd6ea0f02 hermes: add durable Telegram topics 2026-08-16 15:59:09 -03:00
jenkins
ba590c2518 hermes: retain native auth failure health 2026-08-16 13:47:19 -03:00
jenkins
e8b4f0c57c hermes: widen local goal judge timeout 2026-08-16 13:29:10 -03:00
jenkins
2a103f9895 hermes: require findings in worker schema 2026-08-16 12:04:27 -03:00
jenkins
1ea8e16286 hermes: separate review findings from blockers 2026-08-16 11:54:26 -03:00
jenkins
42ac76fe67 hermes: carry goal-loop controller evidence 2026-08-16 11:27:24 -03:00
jenkins
1527fd1af0 hermes: enforce goal completion evidence 2026-08-16 11:11:38 -03:00
jenkins
2a94c7c74f hermes: isolate worker database lifetimes 2026-08-16 10:30:58 -03:00
jenkins
e758ee1059 hermes: survive transient Kanban storage faults 2026-08-16 09:33:30 -03:00
jenkins
18eeeabb62 hermes: avoid unavailable worker providers 2026-08-16 09:19:23 -03:00
jenkins
c0eda84fa1 hermes: recover stale Codex worker threads 2026-08-16 08:54:19 -03:00
jenkins
3b003b850d hermes: preserve Vault CLI credentials for workers 2026-08-16 08:39:45 -03:00
jenkins
46f37f32a3 hermes: streamline forge evidence tools 2026-08-16 08:21:33 -03:00
jenkins
c7ac16d206 hermes: harden Atlas forge workflow 2026-08-16 07:59:35 -03:00
jenkins
f35e89777b test: cover Switchyard image enum 2026-08-16 07:31:16 -03:00
jenkins
ece52b1f2e hermes: harden routed vision normalization 2026-08-16 07:24:20 -03:00
jenkins
8f7b57419a hermes: accept routed base64 vision 2026-08-16 07:12:11 -03:00
jenkins
bfd53100d9 hermes: normalize routed vision messages 2026-08-16 07:00:50 -03:00
jenkins
5dd13368c6 hermes: normalize vision requests for Codex 2026-08-16 06:55:49 -03:00
jenkins
cef7241f11 hermes: avoid empty ad hoc task lookups 2026-08-16 06:06:26 -03:00
jenkins
bebd92212e hermes: install pinned Go toolchain 2026-08-16 05:38:01 -03:00
jenkins
56a254d7d1 monitoring(ai): allow Switchyard metric scraping 2026-08-16 05:24:52 -03:00
jenkins
612cefad23 monitoring(ai): add provider quota operations dashboard 2026-08-16 05:13:20 -03:00
jenkins
012e5fc2ba hermes: recover stale kanban status pages 2026-08-16 04:49:02 -03:00
jenkins
4bab6130bc hermes: close parked kanban tasks atomically 2026-08-16 04:31:00 -03:00
jenkins
7d284871e8 hermes: show activity during dashboard bootstrap 2026-08-16 03:33:41 -03:00
jenkins
eace0ed0df hermes: scope stale activity lineage 2026-08-16 02:51:33 -03:00
jenkins
9bc47f9ce3 hermes: keep durable worker activity visible 2026-08-16 01:20:08 -03:00
jenkins
1d2d386aeb hermes: pin ARM64 runtime images 2026-08-15 22:32:08 -03:00
jenkins
e9efec4ddf hermes: keep provider lanes available under load 2026-08-15 22:15:40 -03:00
jenkins
8c73906e6e hermes: preserve exact routes and accept Telegram images 2026-08-15 22:15:40 -03:00
jenkins
89b9f1a4c7 hermes: isolate runtime access and expose activity 2026-08-15 22:15:40 -03:00
jenkins
07b64a0245 hermes: expose Vault SSH config to OpenSSH 2026-08-15 14:45:27 -03:00
jenkins
1ee766bc1e hermes: mount node access through Vault CSI 2026-08-15 14:34:49 -03:00
jenkins
d311df6c9b hermes: preserve node SSH account ownership 2026-08-15 14:27:11 -03:00
jenkins
6fd7b9bbba hermes: close stale API worker sessions 2026-08-15 14:20:12 -03:00
jenkins
6f459dfc63 hermes: fit node access on constrained workers 2026-08-15 14:17:38 -03:00
jenkins
d27a9649cf hermes: secure node access and expose live workers 2026-08-15 13:58:42 -03:00
jenkins
c7dc81c0c3 hermes: sanitize classifier tool history 2026-08-15 13:35:31 -03:00
jenkins
7dbde8e85d hermes: adaptively scale engineering routes 2026-08-15 13:28:47 -03:00
jenkins
2ae88973be hermes: add audited Atlas operator access 2026-08-15 13:22:01 -03:00
jenkins
427c68fa59 hermes: enforce maximum quality floor 2026-08-15 12:46:08 -03:00
jenkins
29eeb1ebf8 hermes: recover workers after pod restart 2026-08-15 07:07:21 -03:00
jenkins
e9b36181e4 hermes: isolate durable worker lifecycle 2026-08-15 06:31:16 -03:00
jenkins
dca4249599 hermes: recover Kanban event indexes 2026-08-15 05:37:53 -03:00
jenkins
f072685a69 hermes: resolve durable lane model ids 2026-08-15 04:07:30 -03:00
jenkins
846c890527 hermes: load tool credentials before s6 2026-08-15 03:44:00 -03:00