CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

jbaruch/herdr-policy

Herdr team coordination policy for AI coding agents

72

Quality

90%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

report_contract.pyskills/herdr-foreman/foreman/

"""Report contracts: the lines a worker report carries, parsed by owner code (#625).

The foreman gates a report on these lines, its classifier gates and the
judge's rulings, and on nothing else. This module is the one parser: it reads
text and returns what the lines say, or refuses naming every gap. It decides
nothing about the round; callers pass the role and specialty from the owner
dispatch, never from the caller's own reading.

Line forms (one per line; in a report a leading `-`, `*` or up to three spaces
of indent and trailing backticks are tolerated):

  VERDICT: blocking | approved
      Exactly one on a reviewer or tester report, and on a consultation whose
      dispatch specialty is in VERDICT_SPECIALTIES. Any other report carrying
      one has an extra line.
  ACCEPTANCE <k>/<N>: met | unmet <dash> <evidence>
      One per k in 1..N on every consultation report. The dash is an em dash,
      an en dash or a hyphen; the evidence is non-empty. N must equal the
      criteria count recorded from the dispatched brief; the report's own N
      never decides anything.
  CONTRIBUTION: none | design | implementation
      Optional, at most once. The worker's own declaration: it can add an
      exclusion, never clear one.
  CRITERION <k>: <text>
      Brief-side only, inside the brief's single `## Acceptance Criteria`
      section. `brief_criteria` counts them; a CRITERION line anywhere else in
      the brief is ignored. In a report, every CRITERION candidate is extra.

Refusal classes, each naming the gap: missing, duplicate (an identical repeat
included), extra, N mismatch, malformed candidate. A candidate is any line whose
unmarked text starts with one of the upper-case keywords above.

A report may quote the contract. These lines are illustrative, never contract
lines and never `TRIGGER_DECLARATION` evidence (#737): lines inside a fenced code
block (`` ``` `` or `~~~`, any info string), blockquote lines, lines indented four
spaces or a tab, and lines opening with an inline code span, whether it wraps the
whole line or not, and fences opened as list-item content (`- ``` `, `1. ``` `).
A fence left open runs to the end of the report. The same
classification serves every report-body scanner: `report_lines`,
`trigger_bindings` and, through them, the owners in `engagement.py` and
`triggers.py`. Briefs are foreman-composed, not quoted, and keep their own
tolerant scan (`brief_criteria`).

`declared_contributions` reads the well-formed CONTRIBUTION values anywhere in
the text, quoted or not, gap or no gap. It only ever adds an independence
exclusion, so over-reading fails safe and a declared contribution is never lost
to a refusal elsewhere.
"""

import re

from .errors import UsageError

#: The two values a VERDICT line may carry.
VERDICTS = frozenset({"blocking", "approved"})
#: The values a CONTRIBUTION line may carry.
CONTRIBUTIONS = frozenset({"none", "design", "implementation"})
#: The two values an ACCEPTANCE line may carry per criterion.
ACCEPTANCE_STATES = frozenset({"met", "unmet"})
#: Responsibilities whose report carries exactly one VERDICT and no ACCEPTANCE.
VERDICT_ROLES = frozenset({"reviewer", "tester"})
#: Consultation responsibilities: one ACCEPTANCE line per recorded criterion.
CONSULTATION_ROLES = frozenset({"advisor", "investigator", "architect"})
#: Consultation specialties whose report also carries exactly one VERDICT.
VERDICT_SPECIALTIES = frozenset({"security", "ux-product", "documentation"})
#: The brief heading the CRITERION block lives under, matched as a whole line.
CRITERIA_HEADING = "## Acceptance Criteria"

_MARKUP = re.compile(r"^[\s>*`-]*")
#: A fenced code block delimiter: up to three spaces, then three or more backticks or tildes.
FENCE = re.compile(r"^ {0,3}(`{3,}|~{3,})(.*)$")
#: A fence opened as list-item content: list markers, then the delimiter run. Its closer sits at the item's content indent.
_LIST_FENCE = re.compile(r"^ {0,3}(?:(?:[-*+]|[0-9]{1,9}[.)])[ \t]+)+(`{3,}|~{3,})(.*)$")
_ANY_INDENT_FENCE = re.compile(r"^\s*(`{3,}|~{3,})(.*)$")
#: Report-side leading markup: indent, list markers and quote marks; backticks are judged separately.
_REPORT_MARKUP = re.compile(r"^[\s>*-]*")
_INDENTED_CODE = re.compile(r"^(?: {4}|\t)")
#: The prefix of the one structured evidence line a first trigger consultation reports.
TRIGGER_PREFIX = "TRIGGER_DECLARATION: "
_KEYWORD = re.compile(r"^(VERDICT|ACCEPTANCE|CONTRIBUTION|CRITERION)\b")
_VERDICT = re.compile(r"^VERDICT: (\S+)$")
_CONTRIBUTION = re.compile(r"^CONTRIBUTION: (\S+)$")
_ACCEPTANCE = re.compile(r"^ACCEPTANCE ([0-9]+)/([0-9]+): (met|unmet)\s+[—–-]\s*(.*)$")
_CRITERION = re.compile(r"^CRITERION ([0-9]+): (\S.*)$")


def _unmarked(line):
    """The line's text with tolerated leading markup and trailing backticks removed."""
    return _MARKUP.sub("", line).rstrip().rstrip("`").rstrip()


def _candidates(lines, keywords):
    """(line number, unmarked text) for every line starting with one of `keywords`."""
    found = []
    for number, line in enumerate(lines, 1):
        text = _unmarked(line)
        match = _KEYWORD.match(text)
        if match and match.group(1) in keywords:
            found.append((number, match.group(1), text))
    return found


def _unfenced(text):
    """((line number, line) outside fenced code, opening line number of a fence left open or 0).

    CommonMark fence grammar, the one `report_delivery.bare_final` also uses: a
    closing delimiter repeats the opener's character at least as long with no
    text after it. A backtick fence's info string holds no backtick, so
    ```` ```a``` ```` is an inline span rather than an opener.
    """
    rows, fence, length, opened, nested = [], "", 0, 0, False
    for number, line in enumerate(text.splitlines(), 1):
        listed = None if fence else _LIST_FENCE.match(line)
        match = listed or (_ANY_INDENT_FENCE if nested else FENCE).match(line)
        if match:
            run, tail = match.groups()
            if fence:
                if run[0] == fence and len(run) >= length and not tail.strip():
                    fence, nested = "", False
                continue
            if run[0] != "`" or "`" not in tail:
                fence, length, opened, nested = run[0], len(run), number, listed is not None
                continue
        if not fence:
            rows.append((number, line))
    return rows, opened if fence else 0


def _operative_text(line):
    """A report line's contract text, or None when the line is quoted, indented code or inline-code prose."""
    if _INDENTED_CODE.match(line):
        return None
    unmarked = _REPORT_MARKUP.sub("", line, count=1)
    if ">" in line[:len(line) - len(unmarked)]:
        return None
    rest = unmarked.rstrip()
    if rest.startswith("`"):
        return None
    return rest.rstrip("`").rstrip()


def _report_candidates(text, keywords):
    """([(line number, keyword, unmarked text)], open fence line) for every operative report line starting with `keywords`."""
    rows, opened = _unfenced(text)
    found = []
    for number, line in rows:
        candidate = _operative_text(line)
        match = _KEYWORD.match(candidate) if candidate is not None else None
        if match and match.group(1) in keywords:
            found.append((number, match.group(1), candidate))
    return found, opened


def trigger_bindings(text):
    """Every operative `TRIGGER_DECLARATION: ` value in a report: an unfenced line starting at column 0.

    Quoted, indented, list-prefixed, inline-code and fenced copies are examples.
    This recognises lines only; `triggers.validate_bootstrap_binding` judges them.
    """
    return [line[len(TRIGGER_PREFIX):] for _number, line in _unfenced(text)[0] if line.startswith(TRIGGER_PREFIX)]


def declared_contributions(text):
    """Every value a well-formed CONTRIBUTION line in `text` declares, whatever else the report carries."""
    found = set()
    for _number, _keyword, candidate in _candidates(text.splitlines(), {"CONTRIBUTION"}):
        match = _CONTRIBUTION.match(candidate)
        if match is not None and match.group(1) in CONTRIBUTIONS:
            found.add(match.group(1))
    return found


def verdict_required(role, specialty):
    """Whether a report of this responsibility and dispatch specialty carries a VERDICT line."""
    return role in VERDICT_ROLES or role in CONSULTATION_ROLES and specialty in VERDICT_SPECIALTIES


def brief_criteria(text):
    """The criteria count N of a consultation brief, or a refusal naming the gap.

    N is the count of a contiguous `CRITERION 1..N` block in the brief's single
    `## Acceptance Criteria` section, which runs to the next `#`-heading.
    """
    lines = text.splitlines()
    headings = [index for index, line in enumerate(lines) if line.strip() == CRITERIA_HEADING]
    if len(headings) != 1:
        raise UsageError("The consultation brief carries {} `{}` sections; compose it with exactly one, holding "
                         "`CRITERION <k>: <text>` lines numbered from 1.".format(len(headings), CRITERIA_HEADING),
                         {"gaps": ["criteria section count {}".format(len(headings))]})
    section = []
    for line in lines[headings[0] + 1:]:
        if line.startswith("#"):
            break
        section.append(line)
    gaps, seen = [], {}
    for number, _keyword, candidate in _candidates(section, {"CRITERION"}):
        match = _CRITERION.match(candidate)
        if match is None:
            gaps.append("malformed CRITERION line {!r}".format(candidate))
            continue
        k = int(match.group(1))
        if k in seen:
            gaps.append("duplicate CRITERION {}".format(k))
        seen[k] = number
    count = len(seen)
    if not count:
        gaps.append("missing CRITERION lines")
    elif sorted(seen) != list(range(1, count + 1)):
        gaps.append("CRITERION numbers {} are not contiguous from 1".format(sorted(seen)))
    if gaps:
        raise UsageError("The consultation brief's acceptance criteria are not a contiguous `CRITERION 1..N` "
                         "block: {}. Recompose the brief with one numbered criterion per line and dispatch "
                         "again; nothing was sent.".format("; ".join(gaps)), {"gaps": gaps})
    return count


def report_lines(text, role, specialty=None, criteria=None):
    """What a report's contract lines say, or a refusal naming every gap.

    `role` is the dispatch's responsibility and `specialty` its requirement's
    specialty. `criteria` is the N recorded from the dispatched brief; it is
    required for a consultation and refused for a reviewer or tester.

    Returns `{"verdict", "acceptance", "contribution"}`: `verdict` is a VERDICTS
    value or None, `acceptance` a list of `{"k", "state", "evidence"}` in k order
    or None, and `contribution` a CONTRIBUTIONS value or None.
    """
    if role not in VERDICT_ROLES | CONSULTATION_ROLES:
        raise UsageError("A {} report carries no required contract line; only reviewer, tester and consultation "
                         "reports are parsed.".format(role), {"role": role})
    consultation = role in CONSULTATION_ROLES
    if consultation and (type(criteria) is not int or criteria < 1):
        raise UsageError("A consultation report is read against the criteria count its dispatched brief "
                         "recorded; none was recorded.", {"role": role})
    if not consultation and criteria is not None:
        raise UsageError("A {} report carries no ACCEPTANCE lines, so no criteria count applies.".format(role),
                         {"role": role})
    wants_verdict = verdict_required(role, specialty)
    limit = criteria if consultation and type(criteria) is int else 0
    gaps, verdicts, contributions, accepted = [], [], [], {}
    found, opened = _report_candidates(text, {"VERDICT", "ACCEPTANCE", "CONTRIBUTION", "CRITERION"})
    for _number, keyword, candidate in found:
        if keyword == "CRITERION":
            gaps.append("extra CRITERION line {!r}: criteria belong to the brief, never the report".format(candidate))
        elif keyword == "VERDICT":
            match = _VERDICT.match(candidate)
            if match is None or match.group(1) not in VERDICTS:
                gaps.append("malformed VERDICT line {!r}".format(candidate))
            elif not wants_verdict:
                gaps.append("extra VERDICT line: a {} report carries none".format(
                    role if not consultation else "{} consultation".format(specialty or "non-verdict")))
            else:
                verdicts.append(match.group(1))
        elif keyword == "CONTRIBUTION":
            match = _CONTRIBUTION.match(candidate)
            if match is None or match.group(1) not in CONTRIBUTIONS:
                gaps.append("malformed CONTRIBUTION line {!r}".format(candidate))
            else:
                contributions.append(match.group(1))
        else:
            match = _ACCEPTANCE.match(candidate)
            if match is None or not match.group(4).strip():
                gaps.append("malformed ACCEPTANCE line {!r}".format(candidate))
                continue
            k, stated = int(match.group(1)), int(match.group(2))
            if not consultation:
                gaps.append("extra ACCEPTANCE line: a {} report carries none".format(role))
            elif stated != limit:
                gaps.append("ACCEPTANCE {}/{} states N={}, and the dispatched brief recorded {}".format(
                    k, stated, stated, limit))
            elif not 1 <= k <= limit:
                gaps.append("extra ACCEPTANCE {}: the brief states criteria 1..{}".format(k, limit))
            elif k in accepted:
                gaps.append("duplicate ACCEPTANCE {}".format(k))
            else:
                accepted[k] = {"k": k, "state": match.group(3), "evidence": match.group(4).strip()}
    if wants_verdict and not verdicts:
        gaps.append("missing VERDICT line")
    if len(verdicts) > 1:
        gaps.append("duplicate VERDICT line ({} found)".format(len(verdicts)))
    if len(contributions) > 1:
        gaps.append("duplicate CONTRIBUTION line ({} found)".format(len(contributions)))
    if consultation:
        missing = [k for k in range(1, limit + 1) if k not in accepted]
        if missing:
            gaps.append("missing ACCEPTANCE {}".format(", ".join(str(k) for k in missing)))
    if gaps and opened:
        gaps.append("the code fence opened on line {} is never closed, so every line after it is illustrative".format(opened))
    if gaps:
        raise UsageError("The {} report does not meet its contract: {}. Record `needs_work` and send it back to "
                         "its responsibility with these gaps named; no assessment was recorded.".format(
                             role, "; ".join(gaps)), {"gaps": gaps})
    return {"verdict": verdicts[0] if verdicts else None,
            "acceptance": [accepted[k] for k in sorted(accepted)] if consultation else None,
            "contribution": contributions[0] if contributions else None}

skills

herdr-foreman

compose-briefs.sh

config.example.json

foreman-tier-check.py

foreman.sh

label-workspaces.sh

native-hook.sh

policy-paths.py

provision-worktree.sh

prune-report-caches.py

resolve-gates.sh

resolve-policy-paths.sh

review-package.sh

roster.sh

round-preflight.sh

SKILL.md

start-judge-worker.sh

state-schema.md

sweep-worktrees.sh

verify-authority.sh

wait-report.sh

README.md

tile.json