Repository navigation
Conversation
Add the GitOps half of ADR 007 (mctl-agents
docs/adr/007-agent-definition-execution-profile-contract.md): a reviewed
platform-gitops/agent-platform/ catalog of agents.mctl.ai/v1alpha2
ExecutionProfile and ReleaseBindingIntent resources, the policy ceilings
and reference catalogs they are checked against, and
scripts/validate-agent-platform.py wired into validate-manifests.yml.
- policy.yaml: budget/timeout ceilings, known tools/skills/policies/
mutation-scopes/approval-gates/model-policy-tasks, approved sandbox
CWFTs. Every reference an ExecutionProfile or ReleaseBindingIntent
makes is checked against this and fails closed if unknown.
- schemas/: JSON Schema for both resource kinds. Neither permits a
global lifecycleState field -- registry version state and
environment-derived active state stay in mctl-api, never here.
- execution-profiles/{issue-investigator,implementer,shepherd}-default:
behavior-preserving migration of today's effective values (implementer
stays $20/2400s because the production CWFT override wins over the
Python $3/900s default; investigator and shepherd keep their $3/$5
budgets and the shared 7200s activeDeadlineSeconds).
- releases/shadow/*.yaml: non-promotable compatibility-fixture
ReleaseBindingIntents pinning sourceManifest {repo, path, gitSha} plus
one exact (definition, profile) pair each, with a local history ledger
used only to validate exact-pair rollback semantics ahead of a real
mctl-api registry.
- scripts/validate-agent-platform.py + scripts/tests/fixtures/
agent-platform/{valid,invalid}/: fail-closed validation (unknown
references, budget/timeout ceilings, mutation-without-approval,
unapproved sandbox, ambiguous/incompatible/disabled profile versions,
independent-half rollback) plus one fixture per ADR 007 expectation,
replayed via --selftest in CI.
This is additive and not runtime-load-bearing: no AgentDefinition body is
mirrored, no release-history store is created, no existing mctl-api
operation or running agent behavior changes.
Proposal: platform-gitops/agents-state/mctl-gitops/proposals/issue-950-feat-agent-platform-add-gitops-agentdefi/
|
Claude finished @mctl-agents[bot]'s task in 5m 15s —— View job Reviewing PR #953
Note on diff resolution: this checkout is shallow, and the given SummaryThis is a clean, additive-only PR implementing the GitOps half of ADR 007: an Posted 2 inline findings:
Verdict: Changes requested (1 P2, 1 P3) — submitted via |
| errors.append(f"{path}: unknown evidence kind {kind!r} (not in policy.yaml knownEvidenceKinds)") | ||
|
|
||
| # -- budget / timeout ceilings -- | ||
| if policy.max_budget_usd is not None and spec["budgetUsd"] > policy.max_budget_usd: |
There was a problem hiding this comment.
P2: policy.yaml has no JSON Schema, and Policy.__init__ reads limits.get("maxBudgetUsd")/limits.get("maxTimeoutSeconds") (lines 117-118) with no default-object validation. If a future edit to policy.yaml typos or drops spec.limits.maxBudgetUsd/maxTimeoutSeconds, policy.max_budget_usd/max_timeout_seconds silently becomes None, and the ceiling checks here (if policy.max_budget_usd is not None and ...) are skipped entirely rather than failing closed — the one place in this validator that fails open on missing config, contradicting the module docstring's "never a silent fallback" guarantee for "a budget or timeout above the policy ceiling." Every other policy list (knownTools, knownMutationScopes, approvedSandboxes, etc.) defaults to an empty collection on a missing/malformed key, which correctly fails closed (everything becomes "unknown"); only these two scalar ceilings degrade to unconstrained. Consider raising in Policy.__init__/load_policy when limits.maxBudgetUsd/maxTimeoutSeconds are absent or non-numeric, and add a selftest fixture for it alongside the existing missing-bounds/budget-exceeds-ceiling cases.
| SCHEMAS = CATALOG / "schemas" | ||
| FIXTURES_ROOT = ROOT / "scripts" / "tests" / "fixtures" / "agent-platform" | ||
|
|
||
| NAME_RE = re.compile(r"^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$") |
There was a problem hiding this comment.
P3: NAME_RE is defined but never referenced anywhere else in the file — metadata.name patterning is already enforced by the JSON Schema's own pattern (same regex, duplicated as a string literal in both schema files). Dead code; either wire it up as a redundant belt-and-braces check or drop it.
There was a problem hiding this comment.
Has P1/P2 findings, changes requested: 1 P2 (policy.yaml's budget/timeout ceilings fail open, not closed, if maxBudgetUsd/maxTimeoutSeconds are ever typo'd or dropped from policy.yaml — the one exception to this validator's otherwise-consistent fail-closed design), 1 P3 (dead NAME_RE regex).
P2: fail closed when policy.yaml drops or mistypes a ceiling. Policy.__init__ read limits.maxBudgetUsd/maxTimeoutSeconds with no validation, so a missing ceiling left the value None and skipped the budget/timeout checks entirely -- the one place this validator failed open. require_limit() now raises CatalogValidationError, which load_policy() reports as a catalog error. Adds an invalid selftest fixture (policy-missing-ceiling) alongside the existing missing-bounds/budget-exceeds-ceiling cases; the selftest picks up a fixture-local policy.yaml when one is present.
|
@claude review |
|
Claude finished @mctl-claude-remote[bot]'s task in 1m 52s —— View job Reviewing PR #953 (commit
|
There was a problem hiding this comment.
No P1/P2 findings (1 pre-existing P3, non-blocking). The prior P2 (policy.yaml budget/timeout ceilings failing open on a missing/non-numeric maxBudgetUsd or maxTimeoutSeconds) is fixed: Policy.init now routes both through a new require_limit() that raises CatalogValidationError when the value is missing, non-numeric, or a bool, restoring fail-closed behavior consistent with every other policy list. A new invalid/policy-missing-ceiling selftest fixture (only maxTimeoutSeconds declared) exercises the fix via load_policy's existing try/except, correctly surfacing as an invalid-fixture failure. The now-unconditional ceiling checks in validate_profile_file are safe given require_limit guarantees a numeric value. Scope of the fix commit is minimal (2 files, +48/-8) and touches nothing else. The unused NAME_RE regex (P3, dead code) from the previous review is still present but remains a non-blocking nit.
Implements accepted proposal
mctl-gitops/issue-950-feat-agent-platform-add-gitops-agentdefi.Spec: https://github.com/mctlhq/mctl-gitops/tree/main/platform-gitops/agents-state/mctl-gitops/proposals/issue-950-feat-agent-platform-add-gitops-agentdefi/
Generated by mctl-agents Tier 2 implementer. Review carefully — this PR was opened automatically and the spec may have gaps.
Closes #950