Skip to content
3 changes: 3 additions & 0 deletions .squad/agents/keaton/history.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@

## Learnings

- PAO external comms architecture decision: Phase 1 uses a scan→draft→review→post pipeline with humanizer tone enforcement, SQLite review state, append-only audit logs, and a `pao halt` freeze switch.
- Phase 1 scope and constraints: manual-trigger only, never autonomous, every draft requires explicit human approval before posting, and scheduled scans stay blocked pending Brady approval.

## 📌 v0.8.22 Release Disaster — 2026-03-07T20:50:00Z

**THE WORST RELEASE IN SQUAD HISTORY.** Brady was rightfully upset. This was a catastrophe. Full retrospective written with brutal honesty.
Expand Down
8 changes: 7 additions & 1 deletion .squad/agents/mcmanus/charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,23 @@
- Demos and examples
- Tone review and messaging
- i18n patterns
- External community responses (draft-only, human review gate)
- Tone enforcement via humanizer skill
- Community signal aggregation (unanswered issues → product signals)

## How I Work

- Tone ceiling: ALWAYS enforced — no hype, no hand-waving, no claims without citations
- Celebration blog structure: wave:null, parallel narrative
- docs/proposals/ pattern: proposals before execution
- Every public-facing statement must be substantiated
- **EXTERNAL COMMS (hard rule):** NEVER post community responses autonomously. All responses are drafted, presented in a review table with confidence flags, and require explicit human approval before posting.
- **HUMANIZER (hard rule):** All external-facing content must pass tone validation — warm, helpful, human-sounding. No corporate speak, no marketing hype, no empty acknowledgments.
- **AUDIT TRAIL (hard rule):** Every draft-review-post action is logged to `.squad/comms/audit/`. The audit log is append-only.

## Boundaries

**I handle:** Documentation, demos, messaging, tone review, developer experience, i18n.
**I handle:** README, API docs, demos, examples, tone review, community messaging, contributor recognition, external community response drafting (with human review gate).

**I don't handle:** Runtime implementation, architecture decisions, security, distribution mechanics.

Expand Down
7 changes: 7 additions & 0 deletions .squad/comms/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Runtime state (not committed)
review-state.db
review-state.db-journal
review-state.db-wal
review-state.db-shm
audit/
!audit/.gitkeep
27 changes: 27 additions & 0 deletions .squad/comms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# PAO External Communications

> Phase 1: Manual-trigger, draft-only mode with human review gate.

## Directory Structure

- `audit/` — Runtime-only audit trail for every draft-review-post action (not committed to git; keep `audit/.gitkeep`)
- `review-state.db` — SQLite-based single-reviewer lease and draft state (created at runtime)
- `templates/` — Response templates for common scenarios
- `tests/` — Comms workflow and review-state coverage

## Workflow

1. Human manually triggers PAO to scan issues and discussions for unanswered items
2. PAO drafts responses using humanizer skill
3. PAO presents review table with confidence flags
4. Human reviews, approves/edits/skips each draft
5. Human posts approved responses
6. Every action is logged to runtime-only `audit/`

## Safety

- `banana` — freezes all pending drafts (safe word)
- Phase 1 is manual-trigger only
- All responses require explicit human approval
- Audit trail is append-only and runtime-only
- SQLite lease prevents concurrent review race conditions
41 changes: 41 additions & 0 deletions .squad/comms/templates/audit-entry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
timestamp: "{ISO-8601}"
action: "scan|draft|approve|edit|skip|post|halt|resume|delete|lint_failure|expire"
---

> All other fields are conditional on the action type. See **Conditional Fields** table below.
> Frontmatter includes `timestamp` and `action` universally, plus any action-specific required fields from the table.
> Include only the body sections relevant to your action type.

## Context (draft, approve, edit, skip, post, delete actions)
- Thread depth: {comment count}
- Response type: {welcome|troubleshooting|feature-guidance|redirect|acknowledgment|closing|technical-uncertainty|empathetic-disagreement|information-request}
- Confidence: {🟢|🟡|🔴}
- Long thread flag: {true|false}

## Draft Content (draft, edit, post actions)
{full draft text}

## Reviewer Notes (approve, edit, skip actions)
{any edits or comments from reviewer, or "—" if none}

## Post Result (post, delete actions)
{link to posted comment, or original URL if deleted}

## Conditional Fields

Not all fields apply to every action. The `outcome` value is contextual per action:

| Action | Required Fields | Outcome Value | Optional Fields |
|--------|----------------|---------------|-----------------|
| scan | timestamp, action | item count found (e.g., "5 candidates") | — |
| draft | timestamp, action, item_type, item_number, draft_id, confidence, draft_content | — (no outcome for draft) | thread_depth |
| approve | timestamp, action, draft_id, reviewer | "approved" | reviewer_notes |
| edit | timestamp, action, draft_id, reviewer, draft_content | "edited" | reviewer_notes |
| skip | timestamp, action, draft_id, reviewer | "skipped" | reviewer_notes |
| post | timestamp, action, item_number, draft_id, reviewer | "posted" + post_result link | — |
| halt | timestamp, action, reviewer (halter) | "halted" | reason |
| resume | timestamp, action, reviewer (resumer) | "resumed" | — |
| delete | timestamp, action, item_number | "deleted" + original URL | reason |
| lint_failure | timestamp, action, draft_id | violation details (free text) | — |
| expire | timestamp, action, draft_id | "expired" | — |
72 changes: 72 additions & 0 deletions .squad/comms/templates/review-state-schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
-- Runtime reminder: PRAGMA foreign_keys = ON;
-- PAO External Communications: Review State Database
-- Created at runtime in .squad/comms/review-state.db
-- Zero new dependencies (Copilot CLI already uses SQLite)

-- Single global review lease — only ONE reviewer at a time
CREATE TABLE IF NOT EXISTS review_lease (
id INTEGER PRIMARY KEY CHECK (id = 1),
status TEXT NOT NULL DEFAULT 'available' CHECK (status IN ('available', 'held')),
reviewer TEXT,
hostname TEXT,
pid INTEGER,
acquired_at TEXT,
expires_at TEXT
);

-- Initialize the single lease row
INSERT OR IGNORE INTO review_lease (id, status) VALUES (1, 'available');

-- Acquire: UPDATE review_lease
-- SET status = 'held', reviewer = ?, hostname = ?, pid = ?, acquired_at = datetime('now'), expires_at = datetime('now', '+1 hour')
-- WHERE id = 1 AND (status = 'available' OR expires_at < datetime('now'));
-- Release: UPDATE review_lease
-- SET status = 'available', reviewer = NULL, hostname = NULL, pid = NULL, acquired_at = NULL, expires_at = NULL
-- WHERE id = 1;
-- Check: SELECT * FROM review_lease WHERE id = 1;
-- Cleanup expired lease before work: UPDATE review_lease
-- SET status = 'available', reviewer = NULL, hostname = NULL, pid = NULL, acquired_at = NULL, expires_at = NULL
-- WHERE id = 1 AND status = 'held' AND expires_at < datetime('now');

-- Draft tracking table
CREATE TABLE IF NOT EXISTS draft_queue (
id INTEGER PRIMARY KEY AUTOINCREMENT,
reviewer TEXT,
item_type TEXT NOT NULL CHECK (item_type IN ('issue', 'discussion')),
item_number INTEGER NOT NULL,
item_url TEXT,
response_type TEXT NOT NULL,
confidence TEXT NOT NULL CHECK (confidence IN ('high', 'medium', 'low')),
draft_content TEXT NOT NULL,
thread_depth INTEGER DEFAULT 0,
long_thread_flag INTEGER DEFAULT 0,
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'approved', 'edited', 'skipped', 'posted', 'halted', 'deleted')),
reviewed_at TEXT,
posted_url TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

-- Halt state (safe word "banana" mechanism)
CREATE TABLE IF NOT EXISTS halt_state (
id INTEGER PRIMARY KEY CHECK (id = 1),
halted INTEGER NOT NULL DEFAULT 0,
halted_by TEXT,
halted_at TEXT,
reason TEXT
);

-- Initialize halt state (not halted by default)
INSERT OR IGNORE INTO halt_state (id, halted) VALUES (1, 0);

-- Audit log (append-only, mirrors runtime audit files)
CREATE TABLE IF NOT EXISTS audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL DEFAULT (datetime('now')),
action TEXT NOT NULL,
item_type TEXT,
item_number INTEGER,
draft_id INTEGER,
reviewer TEXT,
outcome TEXT,
details TEXT
);
88 changes: 88 additions & 0 deletions .squad/comms/templates/tone-validation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"version": 1,
"description": "Tone validation patterns for PAO external communications",
"reject_patterns": [
{
"id": "corporate-speak",
"pattern": "(?:[Ww]e appreciate your patience|[Pp]lease be advised|[Pp]er our discussion|[Aa]s per|[Kk]indly note|[Pp]lease do not hesitate)",
"message": "Corporate speak detected. Use conversational tone instead."
},
{
"id": "passive-voice-formal",
"pattern": "(?:[Ii]t has been determined|[Ii]t was decided|[Hh]as been escalated|[Ii]s being investigated|[Hh]as been noted)",
"message": "Formal passive voice detected. Use active voice: 'We determined...' or 'We're looking into...'"
},
{
"id": "marketing-hype",
"pattern": "(?:[Bb]est[- ]in[- ]class|[Cc]utting[- ]edge|[Rr]evolutionary|[Gg]ame[- ]changing|[Ii]ndustry[- ]leading|[Nn]ext[- ]generation|[Aa]mazing feature)",
"message": "Marketing hype detected. Be specific about what the feature does, not how great it is."
},
{
"id": "empty-acknowledgment",
"pattern": "^\\s*(?:[Tt]hanks for your feedback\\.?|[Tt]hank you for reaching out\\.?)\\s*$",
"message": "Empty acknowledgment without substance. Add specific context or next steps."
},
{
"id": "robot-signature",
"pattern": "(?:[Bb]est regards|[Ss]incerely|[Kk]ind regards|[Rr]espectfully|[Ww]arm regards)\\s*[,.]?\\s*(?:[Pp][Aa][Oo]|[Tt]he [Ss]quad [Tt]eam|[Ss]quad [Bb]ot)",
"message": "Robot signature detected. Responses should end naturally, not with formal sign-offs."
},
{
"id": "over-promising",
"pattern": "(?:[Ww]e will ship|[Ww]e'll release|[Cc]oming soon|[Ii]n the next release|[Dd]efinitely fix|[Gg]uaranteed)",
"message": "Over-promising detected. Only commit to what the team has explicitly agreed to."
},
{
"id": "dismissive",
"pattern": "(?:[Ww]orks as designed|[Nn]ot a bug|[Ww]on't fix|[Tt]hat's expected|[Uu]ser error)",
"message": "Dismissive language detected. Acknowledge the experience before explaining the design."
},
{
"id": "profanity",
"pattern": "\\b(?:[Dd]amn|[Hh]ell|[Cc]rap|[Ss]hit|[Ff]uck|[Aa]ss|[Bb]astard|[Bb]itch)\\b",
"message": "Profanity detected. Never include profanity, even when quoting."
}
],
"require_patterns": [
{
"id": "acknowledgment",
"pattern": "(?:[Tt]hanks|[Tt]hank you|[Gg]ood catch|[Gg]reat question|[Ii]nteresting|[Aa]ppreciate|[Ww]elcome)",
"message": "Response should include acknowledgment of the author's contribution.",
"applies_to": ["welcome", "troubleshooting", "acknowledgment"]
},
{
"id": "action-oriented",
"pattern": "(?:[Ll]et us know|[Ff]eel free|[Hh]appy to help|[Ww]e'll update|[Rr]each out|[Ww]e'll dig|[Kk]eep us posted)",
"message": "Response should end with an action-oriented close.",
"applies_to": ["troubleshooting", "feature-guidance", "technical-uncertainty"]
},
{
"id": "context-provided",
"pattern": "(?:[Cc]urrently|[Rr]ight now|[Aa]t the moment|[Aa]s of|[Tt]he way it works)",
"message": "Feature guidance should provide context on current state.",
"applies_to": ["feature-guidance"]
},
{
"id": "uncertainty-honest",
"pattern": "(?:[Nn]ot sure|[Nn]ot 100%|[Dd]on't know yet|[Ss]till investigating|[Uu]nclear|[Hh]aven't determined)",
"message": "Technical uncertainty should be honest about unknowns.",
"applies_to": ["technical-uncertainty"]
}
],
"confidence_thresholds": {
"high": {
"description": "Answered before, clear docs, community consensus",
"min_similarity": 0.8,
"baseline_blocking": true
},
"medium": {
"description": "Technically sound but minor uncertainty or tone-dependent",
"min_similarity": 0.6
},
"low": {
"description": "Technical uncertainty, policy decision, reputational risk",
"min_similarity": 0.0,
"requires_review": true
}
}
}
54 changes: 54 additions & 0 deletions .squad/comms/tests/ci-gate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# CI Tone Lint Gate

> Automated quality checks for PAO community response drafts.

## When This Runs

- Before any draft enters the review table
- As part of PR review when modifying humanizer or external-comms skills
- Weekly tone analytics (manual trigger via `pao analytics`)

## Checks

### Mandatory (blocks draft)

1. **Anti-pattern scan** — Run all `reject_patterns` from `tone-validation.json` against draft
2. **Profanity filter** — Zero tolerance, even in quotes
3. **Minimum substance** — Draft must be >50 characters (no empty acknowledgments)
4. **Thread read verification** — Confirm all comments in thread were read before drafting

### Mandatory for High-Confidence Drafts (🟢 only)

5. **Baseline similarity** — Block if tone similarity to gold standard <80% for high-confidence (🟢) drafts. Aligns with `baseline_blocking: true` in `tone-validation.json`.

### Warning (flags but doesn't block)

1. **Positive pattern check** — Warn if response type should contain patterns from `require_patterns`
2. **Length check** — Warn if draft >500 words (may be too verbose for a GitHub comment)
3. **Emoji count** — Warn if >2 emoji in draft
4. **Similarity check** — Warn if tone similarity to gold standard <80% for medium/low-confidence drafts

### Informational

1. **Response type classification** — Log which template was used
2. **Confidence level** — Log confidence flag and rationale
3. **Thread depth** — Log comment count for analytics

## Output Format

```
✅ PASS: Anti-pattern scan (0 violations)
✅ PASS: Profanity filter (clean)
✅ PASS: Minimum substance (127 chars)
⚠️ WARN: Positive pattern — missing action-oriented close
⚠️ WARN: Similarity to GS-2: 72% (threshold: 80%)
ℹ️ INFO: Response type: troubleshooting | Confidence: 🟡 | Thread: 4 comments
```

## Failure Mode

If ANY mandatory check fails:
1. Draft is NOT added to review table
2. Error message shown to PAO with specific violation
3. PAO must redraft before presenting to reviewer
4. Failure logged to audit trail (action: "lint_failure")
Loading