This commit is contained in:
111
docs/ux-refactor/p5-skill-governance-plan.md
Normal file
111
docs/ux-refactor/p5-skill-governance-plan.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# P5 — D4 Skill-Write Governance · Build Plan
|
||||
|
||||
> Phase sequence (open-questions.md:574): P1=D3 ✅ · P2=verify+J08 ✅ · P3=D2 ✅ ·
|
||||
> P4=D11/D12 ✅ · **P5=D4** ← here · P7=D15 (card risk-taxonomy alignment, deferred).
|
||||
> Decision text: `docs/ux-refactor/deltas/open-questions.md` §D4 (lines 537–543).
|
||||
|
||||
## What D4 ratified (four bindings)
|
||||
|
||||
- **(i) Policy.** `create_skill` — normal = ask (in-chat approval card), trusted/yolo =
|
||||
auto-execute. `delete_skill` — always ask, every autonomy level. `read_skill` ungated.
|
||||
Always-audit all three with `initiator:'agent'`.
|
||||
- **(ii) Surface.** In-chat SSE approval card is canonical. Card↔`ui/approval-modal.tsx`
|
||||
risk-taxonomy alignment is **D15/P7 — explicitly deferred, NOT P5.**
|
||||
- **(iii) One write path.** Do NOT route the agent tool through HTTP. Extract a **shared
|
||||
skill-write service module** (create/update/delete + redaction + audit inside the
|
||||
service), consumed by both `routes/skills.ts` and `skill-tools.ts`. One module, one
|
||||
audit trail, two callers.
|
||||
- **(iv) Endpoint consolidation (absorbs D14).** `POST /api/skills` delegates to the
|
||||
audited service. `PUT`/`DELETE /api/skills/:name` enter the audit trail. **Provenance:**
|
||||
frontmatter `initiator`/`source` + `GET /api/skills` returns it + Skills Hub badge
|
||||
("created by agent — review"), replacing the name-heuristic "Custom" classification.
|
||||
- **Persona exception** (already shipped): read-only personas keep losing
|
||||
`create_skill`/`delete_skill`, retain `read_skill`.
|
||||
- **PM residual** (no code): skill creation stays FREE at launch — tier gate unchanged.
|
||||
|
||||
## Recon — current seams (verified 2026-06-12)
|
||||
|
||||
| Seam | File | State |
|
||||
|------|------|-------|
|
||||
| Agent tool | `packages/agent/src/skill-tools.ts` | create/delete write to disk + redact; **no audit, no provenance, no gate** |
|
||||
| HTTP routes | `packages/server/src/local/routes/skills.ts` | `POST /api/skills`, `PUT`/`DELETE /:name` redact but **don't audit**; `POST /api/skills/create` (structured) DOES audit `action:'installed'` |
|
||||
| Autonomy gate | `packages/agent/src/confirmation.ts` | declarative sets; chat.ts:900 calls `needsConfirmationWithAutonomy` |
|
||||
| Frontmatter | `packages/agent/src/skill-frontmatter.ts` | parser+serializer; has name/description/scope/promoted_from/permissions — **no initiator/source** |
|
||||
| Audit store | `packages/core/src/install-audit.ts` | `record()`; action enum **lacks a delete value** |
|
||||
| Skills Hub UI | `apps/web/src/components/os/apps/skills/SkillRow.tsx`, `routes/SkillsRoute.tsx` | `custom` badge driven by name-heuristic |
|
||||
|
||||
## Decisions
|
||||
|
||||
### DEC-1 — Audit `action` for delete (the one real fork)
|
||||
|
||||
`AuditAction = 'proposed'|'approved'|'installed'|'rejected'|'failed'|'blocked'` — no
|
||||
delete/uninstall value. The CHECK is duplicated in `packages/core/src/install-audit.ts`
|
||||
**and** `packages/hive-mind-core/src/mind/schema.ts` (OSS-synced, §7.5). SQLite CHECK
|
||||
can't be ALTERed → widening needs a table-rebuild migration on existing installs.
|
||||
|
||||
- create / update → `action:'installed'` (established convention — `routes/skills.ts`
|
||||
structured-create already does this; a skill on disk = installed).
|
||||
- delete → **needs a decision** (see status note). Options:
|
||||
- **A (recommended): add `'uninstalled'`** to `AuditAction` + both schema CHECKs +
|
||||
a rebuild migration. Fills a genuine pre-existing gap (no uninstall of ANY capability
|
||||
is auditable today); additive/backward-compatible; honest trail. Cost: migration in
|
||||
2 files + OSS drift check.
|
||||
- **B: reuse `'rejected'`** with `detail:'deleted by agent'`. Zero migration, but
|
||||
semantically muddy and pollutes rejection queries.
|
||||
|
||||
### DEC-2 — Shared service location
|
||||
|
||||
`packages/agent/src/skill-write-service.ts`. The agent package is already a server
|
||||
dependency (`@waggle/agent` imported by `routes/skills.ts`), so one module serves both
|
||||
callers. Signature (pure, deps injected — no hidden globals):
|
||||
|
||||
```
|
||||
createSkillWrite({ skillsDir, name, content, initiator, source, auditStore?,
|
||||
skillHashStore?, onChange? }) → { path, redactions, action }
|
||||
updateSkillWrite({ … }) ; deleteSkillWrite({ skillsDir, name, initiator, auditStore?, … })
|
||||
```
|
||||
|
||||
Redaction (`redactSkillContent`) + provenance frontmatter stamp + audit `record()` all
|
||||
live inside the service. Callers stop doing these by hand.
|
||||
|
||||
### DEC-3 — Provenance frontmatter
|
||||
|
||||
Add `initiator?: 'agent'|'user'` and `source?: string` to `SkillFrontmatter` + parser +
|
||||
`serializeFrontmatter`. The service stamps them on create (preserves on update). Legacy
|
||||
skills with no frontmatter → treated as `initiator:'user'` (no badge). Name-heuristic
|
||||
"Custom" classification retired in favor of `initiator==='agent'`.
|
||||
|
||||
## Build order (TDD, commit per step)
|
||||
|
||||
1. ✅ **D4(i) gating** — `confirmation.ts` sets + tests. (`73f2ed5`)
|
||||
2. ✅ **DEC-1 audit enum** — founder picked **Option A**: `'uninstalled'` + widen-CHECK
|
||||
migration in core `install-audit.ts` (belt-and-suspenders rebuild) AND hive-mind-core
|
||||
`db.ts` runMigrations sentinel + `schema.ts` DDL. (`658884f`)
|
||||
3. ✅ **DEC-3 frontmatter** — `initiator`/`source` in parser/serializer. (`f3bda5b`)
|
||||
4. ✅ **DEC-2 service** — `skill-write-service.ts` (lossless provenance stamp). (`2b56b78`)
|
||||
5. ✅ **Rewire agent** — `skill-tools.ts` create/delete via service. (`2b56b78`)
|
||||
6. ✅ **Rewire HTTP** — `routes/skills.ts` POST/create/PUT/DELETE via service; `GET
|
||||
/api/skills` returns provenance. (`29313a9`)
|
||||
7. ✅ **UI badge** — `SkillRow.tsx` "agent · review" off provenance. (`48292ef`)
|
||||
8. ⏳ Adversarial review workflow → record → final gates. (pending — needs opt-in)
|
||||
|
||||
## Status — implementation COMPLETE (2026-06-12)
|
||||
|
||||
All four D4 bindings shipped in 7 commits (`73f2ed5`→`48292ef`), NOT pushed.
|
||||
Gates: tsc 0 across shared/hive-mind-core/core/agent/server/apps-web · 147 P5 tests
|
||||
green (agent 96, core 22, server 20, FE 9) · lint 0.
|
||||
|
||||
**Remaining for P5 closeout:**
|
||||
- **OSS re-split (§7.5):** `hive-mind-core/src/mind/{schema.ts,db.ts}` changed here first
|
||||
(the `'uninstalled'` CHECK + migration sentinel). The `marolinik/hive-mind` mirror must
|
||||
be regenerated via subtree-split before the next OSS release.
|
||||
- **Adversarial review** (step 8) — every prior P-phase ran a multi-agent review workflow;
|
||||
deferred pending explicit opt-in.
|
||||
- **Decision-log + open-questions** phase-line update marking P5 done.
|
||||
- **D4(ii)** card↔modal risk-taxonomy alignment stays **P7/D15** (out of P5 scope).
|
||||
|
||||
## Out of scope (ledgered)
|
||||
|
||||
- D4(ii) card↔modal risk-taxonomy alignment → **P7/D15**.
|
||||
- Marketplace install PRO-gate (unchanged).
|
||||
- `promote_skill`/`auto_extract_skills`/`retire_skills` audit (not named by D4; leave).
|
||||
Reference in New Issue
Block a user