Repository navigation
feat(objectives): guard metrics in the objective join (abilityai/trinity-enterprise#731) - #3423
Merged
Merged
Conversation
…ity-enterprise#731) An objective's top-level `guard_metrics:` list is now read. Each guard joins the same `metrics` list tagged `role: "guard"`, so it is fetched and served through a grant like any other row. A guard is always judged as a hold: on_target within its tolerance or off_target, never behind or ahead, whatever the registry or its own direction says. The same metric as a primary of another objective keeps its normal direction there. - summary.guards counts guards; every other bucket counts primaries only, so an objective without guards reports exactly as before - findings: guard_metrics_invalid, guard_target_unset, guard_direction_invalid - guards have their own per-objective cap - Workspace role card: PortalRoleMetric.role (fixed guard|primary), a neutral "Guard" badge, "Target not set" for a guard with no target - MCP get_objectives description names guards and drops a sentence about a neutral/none direction pair the join never returns Mutation: with the guard-hold branch in resolve_direction removed, 20 tests in tests/unit/test_ent731_guard_metrics.py go red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vybe
approved these changes
Oct 9, 2026
vybe
left a comment
Contributor
There was a problem hiding this comment.
merge-train (2026-10-09): validated at 80825916 — /validate-pr and /review found no criticals; the tests execute the changed path and every new value has a live consumer. Merge with dev (after #3411) is clean. OSS-core placement approved by the operator.
dolho
added a commit
that referenced
this pull request
Oct 12, 2026
…merge-train review Conflicts with #3423 (ent#731 guard metrics), resolved by keeping both sides: `PortalRoleMetric` carries `label` and `role`; the key-set pins list both. The Guard badge sits on the owned objectives' metric rows, beside the plain-words line. Supported objectives show headings only, so they show no badge. The ent#812 "no seat" state keeps its sentence, without the old "Objectives" heading. Beyond the conflicts (merge-train review, 2026-10-08 / 10-10): - `tracked_by` is gone (model, projection, Vue branch, spec, requirement). The card never resolved `served_by`, so it could not produce the name. Naming another agent to an external client is a decision this card does not make. It says "Tracked by another agent". - The fleet-wide `agreed_labels` is replaced by `declarations_elsewhere(agent_name, names)`: active declarations by the SAME owner's other live agents only. An agent of another owner can no longer put text on this owner's client-facing card. - "Tracked elsewhere" is confirmed against those declarations. The join's `declared_elsewhere` is also true when no agent declares the number, so it is now only a candidate. A failed lookup makes no claim. - `findingText` loses the two strings `findingLine` filters out. - New card text uses the contract's tertiary ink (`text-gray-500 dark:text-gray-400`), not `text-gray-400` alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes abilityai/trinity-enterprise#731.
What
An objective may list
guard_metrics:: numbers that must not move while the objective's own metrics are pursued. The objective join ignored that key, so the 18 guards in the live canon were never checked or shown.metricslist withrole: "guard"(primaries getrole: "primary"). One list means guards are fetched, and served through a grant (ent#727), by the existing code. Guards have their own per-objective cap; a name in both lists keeps the primary.neutral/direction_source: objective, no mismatch, whatever the registry or its owndirection:says. It ison_targetwithintolerance(default exact) oroff_target, neverbehind/ahead. The same metric as a primary of another objective keeps its normal direction there.summary.guards = {total, on_target, off_target, not_computable, stale}. Every other summary bucket counts primaries only, so an objective without guards reports exactly what it did before. One summary factory serves the join and the empty answer.guard_metrics_invalid(section not a list),guard_target_unset(no numeric target; 11 of the 18 live guards),guard_direction_invalid(a direction other thanhold).PortalRoleMetric.rolecrosses as the fixed valueguard|primary. A guard row shows a neutral "Guard" badge;guard_target_unsetreads "Target not set".get_objectivesdescribes guards in one line. That line replaces a sentence describing aneutral/direction_source: "none"pair the join never returns, which keeps the description inside the 2048-char budget.Tests
tests/unit/test_ent731_guard_metrics.py(45): parse shapes and malformed input, the always-hold rule against every registry/declared pair, never behind/ahead, exact hold without tolerance, a metric that is a guard in one objective and a primary in another, served / stale / retired / undeclared / supporting-only guards, summary separation and empty-path parity, a guard fetched through the wholeread_objective_join, and the portalroleas a fixed value.resolve_directionremoved, 20 of those tests go red.rolekey where they pin exact row contents (test_ent527_role_card,test_ent666_objective_join,test_ent676_role_card_joinMETRIC_KEYS).portalAgentRole.spec.js: Guard badge mounted, and the two new finding sentences.Security
/cso --diff: 0 findings (docs/security-reports/cso-diff-2026-10-09-ent731-guard-metrics.md). No new endpoint, auth change, read path, dependency or workflow. Guard names reach other agents' numbers only through the existingcan_viewgrant check.Conflict note
#3271 edits the same summary block in
join_objectives; whichever lands second rebases.🤖 Generated with Claude Code