Commit Graph
5 Commits
Author SHA1 Message Date
Hotragn Pettugani 1f92396556 fix(convert): two color names fall through to grey, and nothing checked (#872)
* fix(convert): two color names fall through to grey, and nothing checked

resolve_opencode_color() maps a name it does not recognise to #6B7280 and
says nothing about it. Four agents ask for a name it has never known:

  engineering/engineering-minimal-change-engineer.md   slate
  specialized/operations-manager.md                    slate
  gis/gis-technical-consultant.md                      navy
  specialized/chief-financial-officer.md               navy

All four render grey in the OpenCode integration, which reads as a
deliberate grey rather than a miss — and some agents do choose grey, so
there was nothing to notice.

`slate` and `navy` are now in the map. Values follow the CSS named color
where one exists (navy -> #000080, matching how teal already works) and
Tailwind's 500 shade otherwise (slate -> #64748B, matching gray).

Adding two names does not stop the next one, so two checks now cover it:

  - lint-agents.sh rejects a color that is neither #RRGGBB nor a name the
    converter knows, and prints the names it knows. The list is read out
    of resolve_opencode_color() rather than copied, so it cannot drift
    from the map that does the work. This runs on changed files in agent
    PRs, which is where a new color arrives.

  - test-convert-outputs.sh fails when an opencode output is #6B7280 and
    the source did not ask for grey. Grey stays a legitimate choice; the
    check is "grey only when the source said so".

CONTRIBUTING now says which color values actually work, since the template
just said `colorname or "#hexcode"`.

Verified: all 279 agents pass the new lint rule, and no opencode output
falls through to grey by accident.

* ci(lint): run the whole roster when the linter itself changes

The lint job scopes itself to the agent files a PR touched, which is right
for an agent PR and wrong for a rule change. A new rule lands without ever
having run against the other 278 agents — it either breaks a division
nobody edited or quietly does nothing, and either way CI is silent.

The colour check in the previous commit is the case in point: it changes
scripts/, so the lint workflow's path filter did not even fire, and the
rule would have merged without CI looking at a single agent.

Adds a lint-all job that runs the full-roster lint when scripts/
lint-agents.sh, convert.sh, or lib.sh is part of the diff, and says why it
is skipping when they are not. Those three paths are in the workflow's
trigger list now so the job can fire at all.
2026-09-20 18:35:13 -05:00
Hotragn Pettugani d3a3f573e3 fix(aider): CONVENTIONS.md is a roster index, not 3.8 million characters of agents (#871)
Aider loads a conventions file into context and keeps it there for the whole
session — that is what the file is for, and the docs say to load it with
--read so prompt caching can hold it. This integration concatenated every
agent body into it. At 279 agents that is 3,816,372 characters, roughly a
million tokens. No model takes that. Anyone who ran

    ./scripts/install.sh --tool aider

got a CONVENTIONS.md that either blows the context window on the first turn
or bills for a million tokens trying.

CONVENTIONS.md is now the roster index it was described as: one entry per
agent with the name, the description, the division, and the path to the
agent file. 96,823 characters, down from 3.8 million. The header explains
how to pull a single agent's full instructions into the session:

    /read-only /path/to/agency-agents/engineering/engineering-frontend-developer.md

Naming an agent in a prompt still works the way it did — the description is
what the model needed for that, and it is still there.

test-convert-outputs.sh now holds the index to being an index: it fails if
CONVENTIONS.md grows past 250,000 characters, if it does not list exactly
one path per roster agent, or if any path it prints does not resolve. The
existing round-trip check on the accumulated file still covers the names and
descriptions.
2026-09-20 18:35:10 -05:00
ad9264e309 fix(convert): track code fences when splitting OpenClaw sections, and pin it with an invariant (#855)
convert_openclaw() split on `## ` without tracking fenced code blocks, tearing six fenced examples across SOUL.md/AGENTS.md in five agents and leaving dangling fences in each. Implementation from #854 (@guozi-lab): fence helpers in lib.sh used by convert.sh and lint-agents.sh, CommonMark indent aware. Regression test from #853 (@dajiaohuang): every source fenced block must land whole in exactly one output file — verified to fail on the unfixed converter.

Reported by @AmineOzil. Closes #849. Supersedes #853 and #854.

Co-Authored-By: fruit <200041037+guozi-lab@users.noreply.github.com>
Co-Authored-By: Wu Shuwen <108231307+dajiaohuang@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 11:57:20 -05:00
Michael SitarzewskiandClaude Fable 5.1 449e0c71b1 test(convert): manifest v2 — one line per agent, platform-neutral hashes, advisory drift on PRs (#844)
See the PR for the why/what/proof. Contributors no longer touch scripts/convert-outputs.sha256; drift is advisory on pull requests and strict on main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 18:59:03 -05:00
Michael SitarzewskiandClaude Fable 5.1 04eadbd3e5 test(convert): regression eval for generated outputs + app contracts; fix two get_field bugs it found (#829)
Adds scripts/test-convert-outputs.sh, the output half of the regression eval
(the install half landed in #828), and wires it plus the previously
un-wired test-agent-selection.sh (#779) into CI.

Why an eval at all: every converter bug so far passed lint and the existing
tests while the installed product was broken. #778 shipped a double-wrapped
description that was valid YAML, so a wrapper check passed; #817 dropped a
whole tool from --parallel and every remaining tool looked fine. Those are
invariant violations, not syntax errors.

Layer A (no history needed), for every agent x every converted tool:
  round-trip   parsed(generated).description == source description
  strict-parse every generated frontmatter / TOML / YAML parses with a real
               parser (kimi/vibe carry only an identifier: id == slug and the
               prose file exists; aider/windsurf: "## Name" + description line)
  count        every tool emits exactly one output per roster agent
  source       every SOURCE frontmatter strict-parses and carries no leaked
               quote — the desktop app reads sources with js-yaml (#473)
Layer B: scripts/convert-outputs.sha256, one aggregate hash per tool plus
divisions.json / tools.json / runbooks.json. A flipped line means outputs or a
contract changed; --update regenerates deliberately so review sees the blast
radius. Date-stable (no generated file embeds a date).

The expected side is derived by an INDEPENDENT strict parse of each source,
never by lib.sh's get_field: the generator uses get_field, so an expected
value derived the same way would move with a get_field bug and hide it —
which is exactly how #778 stayed invisible. That independence found two
shipping defects on the first green run:

- get_field returned only the first line of a multi-line plain scalar.
  Three healthcare agents write their description as an indented
  continuation; every generated output for them shipped it truncated
  mid-sentence while the app showed the whole thing. get_field now folds
  continuation lines the way YAML does (newline -> single space).
- get_field stripped only "field: " (one space). The same three files use
  column-aligned frontmatter (name:        X), so their generated names
  carried leading whitespace in every tool's output. Plain-scalar padding
  is now trimmed.

After both fixes get_field agrees with PyYAML on name and description for
all 273 sources. Acceptance: re-introducing #778's double-wrap, a dropped
tool, a divisions.json change, and an unquoted source each fail the eval
(the double-wrap via Layer A round-trip, not only the manifest).

Refs #778 #817 #473 #810 #826 #828 #779

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 07:58:13 -05:00