Skip to content

[Phase 2] Author a machine-readable interaction contract for every agentic role, per the standard #1404

Closed

Description

@github-actions

Story

As a maintainer of the agentic fleet,
I want a checked-in, machine-readable interaction contract for each agentic role, in the location and shape the standard fixes,
so that each role's triggers, timers, emitted events, idempotency key, concurrency lane, stop markers, and budget are declared and diffable, so the CI enforcer (Story 4) has something to validate against.

Acceptance Criteria

  1. Every existing agentic role has a machine-readable interaction contract checked into the repo: the personas (dev-lead, pr-review, business-analyst, devops-lead, qa-lead, scrum-master, security-lead, sre-lead) and the non-persona agents (dev-lead runtime, pr-review runtime, ci-failure-analyst) covered per the standard's location decision.
  2. Each contract declares triggers.events[], triggers.timers[] (each with cron + timer_role + justification + stop_condition + event_fast_path), emits[] (event + identity token/PAT), idempotency_key, concurrency_lane, stop_markers[], and budget.
  3. Each contract's declared triggers match the role's actual deployed on: block (verified against the workflow source), so the contract is not aspirational.
  4. The contract location matches the decision recorded in docs/agentic-interaction-model.md; if contracts extend persona.yml, the persona validator/schema dependency is respected (org-first or a standalone file), with no failing validate-personas.
  5. A hermetic parse/consistency check (or the existing persona validator, if extended) confirms every contract is well-formed.

Tasks / Subtasks

Dev Notes

  • The persona manifests already model triggers as structured data — see personas/dev-lead/persona.yml (triggers.surfaces[] with surface/events/mode/gate_label/notes). The interaction contract extends this concept with the timer/emit/idempotency fields; reuse the existing structure rather than inventing a parallel one.
  • personas/validate-personas.py fetches persona.schema.json from petry-projects/.github (SCHEMA_REPO). New persona.yml fields must be permitted by that schema or validate-personas fails — this is the cross-repo prerequisite in the epic. Prefer the location the standard chose in Story 1; do not silently pick a different one.
  • The non-persona agents' real triggers: dev-lead.yml (labeled issues, review, check_run), pr-review-trigger.yml (event fast-path), pr-review-sweep.yml (schedule + workflow_run), dev-lead-retry.yml (schedule), ci-failure-analyst.lock.yml (check_run:completed). Note ci-failure-analyst.lock.yml is a byte-frozen ring-0 caller stub — the contract must describe it, not edit it.
  • idempotency_key / concurrency_lane values already exist implicitly as concurrency.group in each workflow (e.g. ci-failure-analyst-${{ head_sha }}); source the declared values from those, do not invent new ones.
  • Testing standard: a hermetic (no-network) parse test in the bats suite, mirroring tests/test_validate_personas.bats. If extending persona.yml, add cases to the persona validator test set.
  • Split option (if the org persona.schema.json decision stalls): the three standalone runtime contracts (dev-lead, pr-review, ci-failure-analyst) have NO external-schema gate and can land in a first PR; the 8 persona.yml extensions, which depend on the org schema permitting the new fields, can follow in a second PR. Keep them one story only if the schema decision from Story 1 is already settled.

Project Structure Notes

Contracts live under personas// (extending persona.yml) and/or a standalone per-role file for the three non-persona agents, exactly as the Story 1 standard dictates. This is the data Story 4's validator consumes.

References

  • personas/dev-lead/persona.yml
  • personas/validate-personas.py
  • personas/pr-review/persona.yml
  • .github/workflows/dev-lead.yml
  • .github/workflows/pr-review-trigger.yml
  • .github/workflows/ci-failure-analyst.lock.yml

Likely target surface

  • personas/dev-lead/persona.yml
  • personas/pr-review/persona.yml
  • personas/validate-personas.py

Story prepared by the BMAD Scrum Master (Bob) for epic #1402. Status: ready-for-dev.

Activity

  1. don-petry commented on Aug 2, 2026

    @don-petry
    Collaborator

    Dev-Lead Implementation Plan

    Issue: #1404 — [Phase 2] Author a machine-readable interaction contract for every agentic role, per the standard

    Scope

    Author a standalone, machine-readable interaction: contract for each of the 11 agentic roles (8 personas + 3 non-persona runtimes) per the schema fixed in docs/agentic-interaction-model.md §8.1, using the standard's §8.2 location decision (option b: standalone repo-local files, not persona.yml) — so there is no cross-repo persona.schema.json dependency and validate-personas.py is untouched — plus a hermetic well-formedness validator + bats test.

    Location decision (per §8.2)

    • Persona contracts (8): personas/<id>/interaction.yml — co-located, standalone (NOT a persona.yml block).
    • Runtime contracts (3): interaction-contracts/{dev-lead,pr-review,ci-failure-analyst}.yml — standalone, keyed by workflow path.

    Trigger cross-check (AC #3 — matched against real on: blocks)

    • dev-lead persona → dev-lead.yml (Class 1: pull_request, pull_request_review, pull_request_review_comment, issue_comment, issues, check_run, repository_dispatch; no schedule).
    • pr-review persona → pr-review-trigger.yml (Class 1: check_suite, pull_request_review, pull_request, workflow_dispatch, repository_dispatch:pr-review-mention).
    • business-analyst / devops-lead / qa-lead / scrum-master / security-lead / sre-lead → persona-mention.yml (Class 1: issue_comment, pull_request_review_comment, discussion_comment) → persona-runner. Contracts declare the deployed router triggers, reconciling the broader-but-not-wired surfaces in persona.yml.
    • dev-lead runtime → dev-lead.yml + dev-lead-retry.yml (Class 2 self-heal cron 15 */2 * * *, event_fast_path: null — the §6.3 leak).
    • pr-review runtime → pr-review-trigger.yml + pr-review-sweep.yml (Class 2 backstop cron 2,17,32,47 * * * *, event_fast_path: workflow_run:[completed]).
    • ci-failure-analyst → ci-failure-analyst.lock.yml (Class 1: check_run:[completed]; byte-frozen ring-0 stub — described, never edited).

    idempotency_key / concurrency_lane sourced from each workflow's real concurrency.group (dev-lead-reusable per-PR/per-issue lanes, pr-review per-PR lane, ci-failure-analyst-${head_sha}, dev-lead-retry, pr-review-sweep-${branch}, persona-runner lane). stop_markers from the human-gate markers in use (needs-human-review, dev-lead:needs-human, <id>:hands-off). budget: pr-automation-budget for write runtimes, none for advisory mention personas.

    Implementation Checklist

    • interaction-contracts/validate-interaction-contracts.py — hermetic (no-network) well-formedness validator: required fields, timer sub-fields, Class-2 timers carry timer_role+stop_condition, emits/events disjointness (narrow §7-rule-1 guard), workflows[] paths exist. Deep on:-block match is Story 4 ([Phase 3] Add scripts/validate-interaction-model.sh + bats, wired into lint.yml as a PR-triggered check #1406).
    • personas/<id>/interaction.yml × 8
    • interaction-contracts/{dev-lead,pr-review,ci-failure-analyst}.yml × 3
    • .github/workflows/lint.yml — add validate-interaction-contracts job (mirrors validate-personas) + register the new bats file in the bats job list.

    Tests to Write

    • tests/test_validate_interaction_contracts.bats — hermetic, mirrors tests/test_validate_personas.bats: accepts a well-formed fixture; rejects missing required field, malformed timer, Class-2 timer with no timer_role, emit that self-triggers, non-existent workflow path.

    Test Command

    bats tests/test_validate_interaction_contracts.bats (full suite: scripts/run-bats.sh tests/*.bats); lint gate: bash .dev-lead/scripts/dev-lead-lint.sh; contracts checked live via python3 interaction-contracts/validate-interaction-contracts.py.

  2. don-petry commented on Aug 2, 2026

    @don-petry
    Collaborator

    Story 2 / #1404 — complete

    Authored a machine-readable interaction contract for every agentic role and wired a hermetic CI gate to keep them honest.

    What shipped

    11 contracts (§8.2 decision: option (b) — standalone repo-local files, so persona.schema.json / validate-personas.py are untouched, no cross-repo dependency):

    • 8 persona lenses — personas/<id>/interaction.yml for dev-lead, pr-review, business-analyst, devops-lead, qa-lead, scrum-master, security-lead, sre-lead.
    • 3 runtime lenses — interaction-contracts/{dev-lead,pr-review,ci-failure-analyst}.yml (deployment view; dev-lead/pr-review fold in their Class-2 backstop timers, ci-failure-analyst has no persona manifest).

    Each contract declares the full §8.1 shape: triggers.events[], triggers.timers[] (cron + role + justification + stop_condition + event_fast_path), emits[], idempotency_key, concurrency_lane, stop_markers[], budget.

    Acceptance criteria

    • AC#1 — every agentic role has a contract (8 personas + 3 runtimes). ✅
    • AC#2 — every declared field present and typed. ✅
    • AC#3 — declared triggers verified against each role's deployed on: block, not aspiration. The advisory personas record only persona-mention.yml's wired issue_comment/pull_request_review_comment/discussion_comment; the broader persona.yml surfaces (reviewer-assignment etc.) are noted as not-yet-wired (finding 10 / Persona framework — pre-rollout review findings .github#755). ✅
    • AC#4 — location matches the §8.2 decision; persona validator dependency respected (no persona.yml extension). ✅
    • AC#5 — hermetic parse/consistency check interaction-contracts/validate-interaction-contracts.py, gated in lint.yml (new validate-interaction-contracts job + tests/test_validate_interaction_contracts.bats registered in the bats job). ✅

    Modeling notes

    Verification

    • bats tests/test_validate_interaction_contracts.bats → 13/13 pass (TDD: written red before the validator existed).
    • python3 interaction-contracts/validate-interaction-contracts.py . → OK: 11 interaction contract(s) valid, invariants hold.
    • bash .dev-lead/scripts/dev-lead-lint.sh → all checks passed (shellcheck 98 files + agent-profile/CODEOWNERS frontmatter).
    • lint.yml re-validated as YAML after the edits.

    CI owns the commit/PR.

  3. added a commit that references this issue on Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    dev-leadFor dev-lead agent pickupinitiativeEpic / initiative tracking issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions