From fb141969f59043005b911d149d8c7039d41aec35 Mon Sep 17 00:00:00 2001 From: Sean Gearin Date: Thu, 13 Aug 2026 07:37:15 -0400 Subject: [PATCH] =?UTF-8?q?fix(skills):=20company-brainify=20=E2=80=94=20c?= =?UTF-8?q?lose=20three=20sanitization-defeating=20defects=20(#4048)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(skills): company-brainify — close three sanitization-defeating defects 1. Scope truncation: the first structural grep used '>' and overwrote the retrieval-discovered scope list; Phase 1 now writes retrieval paths to /tmp/brainify-scope.txt explicitly and both greps append. 2. Facts reconciliation: the skill claimed 'gbrain sync' makes the DB stop serving deleted Facts-fence rows. Sync's convergence contract covers page import only — fact extraction is explicitly decoupled (src/commands/sync.ts CONVERGENCE CONTRACT); the reconcile lives in the extract-facts sweep (src/core/cycle/extract-facts.ts). The procedure now triggers the sweep and verifies removal with 'gbrain recall --grep' before certifying. 3. Backup retention glob: the backup is created as shared-brain-history-backup-.git but cleanup documented brain-history-backup-.git — a pattern that matches nothing, silently retaining the pre-sanitization history mirror forever. Globs now agree. Co-Authored-By: Claude Fable 5 * chore(skills): regenerate skills.lock.json after master fix-wave Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Claude Fable 5 --- skills/company-brainify/SKILL.md | 41 ++++++++++++++++++++++---------- skills/skills.lock.json | 2 +- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/skills/company-brainify/SKILL.md b/skills/company-brainify/SKILL.md index 0bcef5eeb..0a160015a 100644 --- a/skills/company-brainify/SKILL.md +++ b/skills/company-brainify/SKILL.md @@ -139,13 +139,17 @@ cd "$BRAIN" gbrain recall --grep "salary" ``` - Collect every returned slug into the scope list. + Resolve every returned slug to its repo-relative file path and write the + paths into `/tmp/brainify-scope.txt` (one per line). This file is the + scope list; the structural pass below APPENDS to it — nothing later in + the procedure may truncate it, or the retrieval-discovered pages + silently drop out of scope. 2. Structural discovery — people files that belong to the company, plus keyword hits across the wider scan scope: ```bash - grep -rli 'company: *"acme-example"' people/ --include="*.md" | sort > /tmp/brainify-scope.txt + grep -rli 'company: *"acme-example"' people/ --include="*.md" | sort >> /tmp/brainify-scope.txt grep -rli -E 'salary|equity|carry|retention|underperform|performance review|hard conversation' \ meetings/ daily/ companies/ projects/ analysis/ --include="*.md" 2>/dev/null >> /tmp/brainify-scope.txt sort -u -o /tmp/brainify-scope.txt /tmp/brainify-scope.txt @@ -254,16 +258,22 @@ For sanitization, sensitive fact rows must be ACTUALLY REMOVED: find them (`gbrain recall --grep`), then delete the row from the page's Facts fence (step 5), exactly like a sensitive take. On an in-place shared brain, the page edit must then be re-synced (`gbrain sync` re-imports the edited page) -so the shared database no longer serves the row — an edited page over an -un-synced DB still leaks through retrieval. `forget` alone can never certify -a brain clean. +AND the facts index reconciled — sync's convergence contract covers page +import only; downstream fact extraction is explicitly decoupled +(`src/commands/sync.ts`, "CONVERGENCE CONTRACT"), so the DB keeps serving +the deleted row until the extract-facts reconcile runs. Trigger it +(`gbrain sweep`, or wait for the serve-resident sweep), then confirm with +`gbrain recall --grep` that the row is actually gone. An edited page over +an un-reconciled facts index still leaks through retrieval. `forget` alone +can never certify a brain clean. After edits: on the **staging-copy** path the fact rows are removed by editing the copied markdown directly (there is no live DB to re-sync yet — the team DB is built fresh when Phase 5 Step 0 turns the export into a source). On the -**in-place shared-brain** path, `gbrain sync` re-imports the changed pages so -the DB matches the markdown. Either way, run `gbrain check-backlinks check` to -catch pages still pointing at removed content. +**in-place shared-brain** path, run `gbrain sync` so the page content matches +the markdown, then reconcile and verify the facts index as above. Either way, +run `gbrain check-backlinks check` to catch pages still pointing at removed +content. ### Phase 4: Verify @@ -502,7 +512,10 @@ recovery line. mirror-clone backup in `~/.gbrain/backups/` for a retention window (~30 days is a sane default), then delete it — it contains the pre-sanitization history and should not accumulate indefinitely: - `rm -rf ~/.gbrain/backups/brain-history-backup-.git` + `rm -rf ~/.gbrain/backups/shared-brain-history-backup-.git` + (the glob must match the `shared-brain-history-backup-*` name the backup + step created — a mismatched pattern deletes nothing and silently retains + the pre-sanitization history forever) - If the repo carries push hooks or auto-hardening wiring, re-verify remotes and hooks survived the rewrite before handing the repo to the team @@ -592,9 +605,11 @@ This skill guarantees: covered by the sanitization scan; everything else is excluded by default, and the Phase 4 verification greps run against the exported tree before the first push. -- Sensitive fact rows are deleted from the page's Facts fence and re-synced, - never merely expired — `gbrain forget` retains the row (struck through, - served via `--include-expired`) and can never certify clean. +- Sensitive fact rows are deleted from the page's Facts fence, re-synced, + and the facts index reconciled (extract-facts sweep) with the removal + verified via `gbrain recall --grep`, never merely expired — `gbrain + forget` retains the row (struck through, served via `--include-expired`) + and can never certify clean. - The history-purge filter list and its restore manifest both derive from the COMPLETE set of sanitized paths, never a subset. - Every strip decision is a per-file model judgment grounded in a full read; @@ -623,7 +638,7 @@ Three artifacts: - Scope: [N files scanned across people/, meetings/, daily/, ...] - Flagged: [M files with hits] (triage list attached) -- Edited: [K files sanitized; T takes removed; F fact rows removed + re-synced] +- Edited: [K files sanitized; T takes removed; F fact rows removed + re-synced + facts index reconciled] - Verification: [grep residuals: 0 confirmed-sensitive; retrieval checks: clean] - History: [not purged | fresh-export | purged after confirmed gate — backup at ] - Next re-audit: [date / cron slot] diff --git a/skills/skills.lock.json b/skills/skills.lock.json index 553c5e462..111f17f5f 100644 --- a/skills/skills.lock.json +++ b/skills/skills.lock.json @@ -36,7 +36,7 @@ "citation-graph-ingest/SKILL.md": "849b0cdc64b7ff14d0e6771bde15f0edc3c2fc29af08be015753a5f88a03205f", "citation-graph-ingest/routing-eval.jsonl": "a1ba605d35e736b741b9e8aac1e7d50b61a7cbcada893d67099b55bf5a0d2635", "cold-start/SKILL.md": "20be3d1b637621fd9fbd268072f6647533a23f596e30cb593523b051708aaddd", - "company-brainify/SKILL.md": "2c058b39f5364b8ceb5c53b4525cce8645734f16cc3c229a490b005d58a78311", + "company-brainify/SKILL.md": "ae48372512645f532820e43faaf18a8fa768a691b2144973dfc89465f84d84c6", "company-brainify/routing-eval.jsonl": "6f27f835eda9ae77a2b694534c78a043a871349820e8c638c3d8bbba6d3aa17b", "concept-synthesis/SKILL.md": "ed02d2e385143b16a1e69ee5934288fb4d0b755f68c4312faff663e6b2d7c4ed", "concept-synthesis/routing-eval.jsonl": "96dbd7d9c1b606e9e06262d0c06282399741e2bccb8eeb7b9ca88c20f44cda0e",