Repository navigation
Persona framework — pre-rollout review findings #755
Description
Review of the persona framework (#752, #754, .github-private#1279) before onboarding more personas. Findings are ordered by what gets worse as N grows.
The systemic one: errors read as negative answers
Not a bug — a habit, and the reason to fix this before N personas. Four instances in ~200 lines of routing:
| Where | Error | Silently becomes |
|---|---|---|
pm_manifest_query |
YAML won't parse | "manifest says no" |
manifest curl |
5xx / network blip | "not a persona" |
labels fetch (|| echo "") |
API error | "no labels" → opt-out bypassed |
| alias handle | 404 | "not a persona" |
A raw.githubusercontent hiccup silently disables every persona fleet-wide, with no error anywhere. A transient labels API failure lets an agent act on an item explicitly marked hands-off.
Owner: #754 (unmerged code) — being fixed there, not by dev-lead.
Blocking rollout
1. address.aliases[] is architecturally broken — DECISION NEEDED
#752 promises aliases as the rename migration path. #754's index-free routing cannot deliver it: alias petry-projects/qa-architect → personas/qa-architect/persona.yml → 404 → mention silently dropped. Contract and implementation contradict.
We just did the exact rename aliases exist for (murat → qa-lead); it only worked because nothing referenced it yet.
- Option A (recommended): drop
aliasesfrom the schema. A broken feature is worse than an absent one, and removing a field is cheap before N personas adopt it. - Option B: derived
personas/aliases.json, generated byvalidate-personas.py, living beside the manifests in.github-private(does not invert thecanary-rings.json→release/registry.ymlderivation direction), fetched only on 404.
2. gate_label declared but never enforced — SECURITY
Schema requires write surfaces to declare a gate label. Nothing checks it is applied. The first write-mode persona writes ungated. dev-lead is a write agent — this blocks its onboarding. Found independently by CodeRabbit. Owner: #754.
Promised but does not exist
These matter most because the standard reads as though they are real.
3. The team-property CI check — asserted in 4 places, exists nowhere
persona.schema.json, §4.1, TEMPLATE/persona.yml, and personas/qa-lead/persona.yml all claim CI verifies the addressing team. Nothing does. A persona can ship with a secret team (unmentionable → silently dead) or notifications enabled (pages humans on every mention). → .github-private story.
4. <id>:hands-off labels are inert
Schema requires opt_out_label; nothing provisions it. qa-lead:hands-off exists in zero repos; the canonical set is 7 hardcoded labels in a bash array in scripts/apply-repo-settings.sh. The mandated escape hatch does not work, and it is O(N personas × M repos). → .github story.
5. The eval gate is unenforced
Principle 5: "No persona reaches stable without an eval gate." canary-rollout never reads evals/. It is a checklist item, not a gate. (Predates this work — #670.)
6. evals.path is a single path, but the eval tree is skill-keyed
evals/ holds deep-review, triage, spec-drift — those are pr-review's evals. A persona with several skills cannot express them. Blocks pr-review onboarding. Schema gap.
7. The trigger matrix is mostly aspirational
qa-lead declares six surfaces; exactly one (mention) has an implementation. bridge is decorative — the router ignores it. N personas ⇒ N manifests claiming capabilities that do not exist.
8. Opt-out cannot work on discussions
Discussions have no labels API, so the router skips the check entirely. <id>:hands-off can never opt out a discussion.
Precision and UX
9. The router fires where GitHub renders no mention
Verified: fenced code blocks, inline code, and blockquotes all trigger. GitHub's one-click Quote reply prefixes >, so quote-replying to a comment that mentioned a persona re-fires it. Neither recursion axis catches human-quoting-human. Owner: #754.
10. review_requested has no routing path
Requesting a review from the team is the most natural way to address a persona on a PR, and §4 says "Reviewer-assignment counts here too". Not implemented.
11. No acknowledgement
Mention a persona → silence, indistinguishable from a silent skip. Fix that avoids #860: a 👀 reaction, not a comment. Reactions do not trigger workflows, so there is no loop risk.
12. No quota cap on fan-out
One comment can address N personas ⇒ N agent runs. The PR-cap gate covers PR creation, not mentions.
Verified NOT problems — do not re-litigate
author_associationworks.don-petryreturnsMEMBERdespite all three org members being private (public_membersis empty). The trust floor is sound..github-privateis PUBLIC (private: false); unauthenticated raw fetch returns 200. CodeRabbit's 🔴 Critical on Add the persona @-mention router #754 ("private repo → 404 → every persona skipped") is a false positive driven by the repo name. The index-free fetch is sound.
Ownership
- Add the persona @-mention router #754 (open, mine): systemic fail-open trio,
gate_label,contents: read, PyYAML, mention precision. - dev-lead stories: team-property CI check (
.github-private),hands-offlabel provisioning (.github). - Decision needed: aliases (A or B), eval-gate enforcement,
evals.pathmulti-skill shape.
Blocks the persona onboarding of dev-lead, pr-review, and business-analyst.
Activity
don-petry commentedon Jul 17, 2026
Work breakdown
Fixing in #754 (unmerged code — dev-lead branches from
main, so it cannot touch these):gate_labelenforcement,contents: read, PyYAML, mention precisiondev-lead stories (scoped to one repo each, real files, PR-sized):
<id>:hands-offlabels so opt-out actually worksPersona onboarding (blocked on the above):
gate_labelunenforced + no evals; highest blast radius, least governed)evals.pathsingle-path gap + pr-review has channel tags + fleet consumers + a soaking candidate but is NOT in canary-rings.json #710 registration; two-mention-path decision)Decisions needed before onboarding (not delegated — these are design calls):
personas/aliases.jsonevals.pathshape — single path vs multi-skill list (pr-review proves this is not theoretical)fix(personas): close the fail-open paths and enforce the write gate
fix(personas): drop the dead review_requested trigger from the stub
don-petry commentedon Jul 17, 2026
Filed combsmith/.github-private#1290 — PR comments from maintainers are mechanically inert.
It's the same shape as this tracker's headline finding, one layer up: an action that looks like it worked but silently did nothing. Established mechanically, not inferred:
.github's ruleset does enforcerequired_review_thread_resolution: true— so an inline review comment creates a thread that blocks merge, andprompts/dev-lead/fix-reviews.mdwalksreviewThreadsand actions it.gh pr commentand the UI's main box produce) creates no thread. So it doesn't block, andfix-reviews.mdnever reads it — verified: zero references toissues/<n>/commentsin that prompt.The same words, posted two ways, have opposite force — and the ergonomic default is the silent one.
Evidence: my fail-open finding on #757 at 03:55:10Z → merged 04:03:48Z, defect intact, now being fixed in #765.
Persona opt-out label sync must not fail open (#765)
Stop using address.aliases (half 1 of 2) (#1289)
Add the persona @-mention router (#754)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Stop using address.aliases (half 1 of 2) (#1289)
Persona opt-out label sync must not fail open (#765)