diff --git a/agent/managed-skills/gitea-api-pr-operations/SKILL.md b/agent/managed-skills/gitea-api-pr-operations/SKILL.md index a2a5c32..52fc9be 100644 --- a/agent/managed-skills/gitea-api-pr-operations/SKILL.md +++ b/agent/managed-skills/gitea-api-pr-operations/SKILL.md @@ -1,6 +1,6 @@ --- name: gitea-api-pr-operations -description: "Open, list, merge, and diagnose issues/PRs on the Dankclaw Gitea API (192.168.0.143:3000, repo dank/command-center) with the token stored in ~/.config/secrets/gitea — incl. the required merge payload and where review comments actually live on 1.27.3." +description: "\"Open, list, merge, and diagnose issues/PRs on the Dankclaw Gitea API (192.168.0.143:3000, repo dank/command-center) with the token stored in ~/.config/secrets/gitea — incl. the required merge payload, where review comments actually live on 1.27.3, and how to recover the session id for the mandatory body footer.\"" --- # Gitea API PR operations (Dankclaw `dank/command-center`) @@ -25,11 +25,13 @@ description: "Open, list, merge, and diagnose issues/PRs on the Dankclaw Gitea A fold footers into the --arg string instead.) - **List open PRs**: `GET /pulls?state=open` → `jq -r '.[] | "#\(.number) \(.head.ref) \(.title)"'`. - **Read PR**: `GET /pulls/` (no token; public repo) → `jq -c '{state,merged,mergeable,head:.head.ref}'`. + `mergeable:false` is often Gitea's *not-yet-checked* state, not a conflict — prove a real + conflict locally with `git merge-tree --write-tree HEAD origin/main` before believing it. - **MERGE**: `POST /pulls//merge` with `-H 'Content-Type: application/json'` and body **`{"Do":"merge"}`** — this build REQUIRES the `Do` field: `{}` or `{"DoNotMerge":false,...}` → 422; `{"Do":"merge"}` → 200 + - `{"state":"closed","merged":true,"merge_commit_sha":"..."}`. Verify with a - plain GET /pulls/ afterwards (merge endpoint's own stdout may not parse). + `{"state":"closed","merged":true,"merge_commit_sha":"..."}`. Verify with a plain + GET /pulls/ afterwards (merge endpoint's own stdout may not parse). Merge is the `--no-ff` merge commit on main; then `git -C ~/.omp fetch && git merge --ff-only origin/main` propagates the live deployment. - **Issues**: same shape at `/issues` (`POST {title, body}`), `/issues//comments` @@ -51,6 +53,13 @@ description: "Open, list, merge, and diagnose issues/PRs on the Dankclaw Gitea A Every issue/PR body ends with `---` line then `cwd: · session: `. Keep it inside the --arg string (not a `---` CLI arg). +`cwd` is THIS session's own working directory (note a build worktree separately if they +differ). When `/status` is unreachable (headless/subagent context), recover the session id +from the session store instead of inventing one: +`ls -t ~/.omp/agent/sessions// | head -2` → `_` (the same uuid as +`.jsonl`); the slug is the cwd with `/` replaced by `-`. Subagent files live under the +**parent** session's directory, so the newest entry there is the parent id. + ## Gotchas - Content-Type: POSTs with `-d @file.json` MUST carry `-H 'Content-Type: application/json'` on the command line. `-H` entries put in diff --git a/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md b/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md index 27b1217..ce57051 100644 --- a/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md +++ b/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md @@ -1,6 +1,6 @@ --- name: vault-one-fact-one-owner-dedupe -description: "Collapse per-payload/per-attempt vault pages into one owner page per endpoint without losing a fact: port-before-cut orphan census, index regeneration, the one-page seam, and the merge-resolution order." +description: "\"Collapse per-payload/per-attempt vault pages into one owner page per endpoint without losing a fact: port-before-cut orphan census, doubled-page repair, trash-aware tools, delegated-write verification, index regeneration, and the merge-resolution order.\"" --- # One fact, one owner: dedupe the vault without losing a fact @@ -18,6 +18,9 @@ mechanics are general. table or boot ledger**. - `log.md` owns incidents and laws only. A swap is an Eras row, never a log entry. - `AGENTS.md` carries operator-critical numbers + cross-border laws; everything else links. +- A **retired** endpoint still gets one locator page: era windows quoted verbatim from each + era page's own banner, no numbers restated, and any date conflict recorded as an open + question instead of silently resolved. Never pick a winner between two primary sources. ## 2. Single-writer rule (the mistake that costs the most) @@ -29,56 +32,71 @@ to be reconciled by hand. ## 3. Port-before-cut census (proves nothing was lost) -For every deleted line, extract distinctive keys (integers ≥ 4 digits with commas stripped, -decimals with ≥ 2 fraction digits) and check them against the whole vault minus the file -being rewritten. Any line with **no** surviving key is an orphan → port, or accept -deliberately and say so. +For every deleted line, extract distinctive keys and check them against the vault minus the +file being rewritten. Any line with **no** surviving key is an orphan → port, or accept +deliberately and say so. Use `scripts/port-census.py ` (numbers +with ≥ 4 int digits, decimals, flags, paths, backticked spans, `--`, ALL-CAPS, or ≥ 2 hyphens). -```python -num = re.compile(r'\d[\d,]*(?:\.\d+)?') -def keys(line): - out = set() - for n in num.findall(line): - i = n.split('.')[0].replace(',', '') - if len(i) >= 4: out.add(i) - if '.' in n and len(n.split('.')[1]) >= 2: out.add(n.replace(',', '')[:6]) - return out -# orphan = deleted line whose keys are absent from corpus(vault minus target file, minus .AGENTTRASH) -``` +Two calibration traps: +- **Prose words are not facts.** A hyphen or trailing period inside a word (`long-standing`, + `deployed:`) was counted as a tracked token while real identifiers hid behind it; that noise + buried 300 real lines under 979 fake ones. Strip punctuation, require fact shape. +- **The corpus decides the question.** Corpus = the new file only → "what did this rewrite + drop?" Corpus = whole vault → "is the dropped fact orphaned repo-wide?" Ask one at a time. -Expect ~30 orphans per 1,000 deleted lines, of which ~40 % are process trivia recoverable -from git (PR/commit hashes, per-boot log lines). Port the measurement/law ones to the owner -page's Laws/Eras, and list the accepted losses in the commit message and PR body. Also grep -`AGENTS.md` separately — a fact it carries is not an orphan. +Also grep `AGENTS.md` separately — a fact it carries is not an orphan. -## 4. Deletion mechanics +## 4. When a page is the same page twice -- Trash is **gitignored** (`.gitignore` has `.AGENTTRASH/`). Move with plain `mv` into the - repo-root dated dir, e.g. `.AGENTTRASH/-topic/LLM/`. `git mv` a tracked page into - it stages a rename *into an ignored path* (index entry the next agent cannot see); undo with - `git restore --staged ` and let the deletion be the change. -- Never `rm`, never `git clean -f`. +Signature: a page whose `wc -l` is ~2× its `HEAD` size, with a **second frontmatter block in +the body** whose closing `---` is glued onto the end of a body/timestamp line. Cause chain: a +frontmatter rewrite that re-reads the file it just wrote (so its own output becomes the body), +then a fence-repair pass keyed on `line == "---"` that cannot see a glued fence and inserts a +fence mid-page, so the next pass treats the tail as a new document. -## 5. Rewire + indexes mechanically +Un-double rule that worked: find the first frontmatter's close (accepting a glued fence), then +the first `type:` line after it that has more keys (`title|description|tags|timestamp`) behind +it — that is the second copy, and a stray `type:` in a code block has no key run. Keep the copy +whose body is a **superset** (compare after stripping the dropped copy's own frontmatter), +un-glue the fence, and prove `0` census losses before writing. Refuse to guess: if the halves +differ materially, stop. + +## 5. `.AGENTTRASH` is not vault content + +Every tool that walks the vault must exclude it — **both the scan set and the resolution +index**. The link checker resolving links *into* the trash turns "live page points at a +deleted page" into a false PASS, which is worse than a false alarm. The `docs_completeness` +seam's `find` must carry `-not -path '*/.AGENTTRASH/*'` in both walks, or a trashed page +demands an index row and a trashed page can satisfy the docs requirement for a live service. + +Trash is gitignored; move with plain `mv` into the dated dir. `git mv` into an ignored path +stages a rename the next agent cannot see (`git restore --staged `). Never `rm`, +never `git clean -f`. + +## 6. Rewire + regenerate indexes mechanically ```bash grep -rnoE "\[\[(page-a|page-b|...)\]\]" --include="*.md" serverAppConfigs-docs | grep -v AGENTTRASH grep -rnoE "\((page-a|page-b|...)\.md\)" --include="*.md" serverAppConfigs-docs | grep -v AGENTTRASH ``` -Both wikilinks and markdown path refs must be repointed (Research `See Also` lists and -`ubatch`-style bench pages are where path refs hide). Then **regenerate** index pages with a -script that walks the vault (`os.walk`, skip `.obsidian`/`.AGENTTRASH`, one row = `[[basename]]` -+ first-sentence description stripped of markdown links) rather than hand-editing rows — the -`docs index links every docs page` seam fails on any row left behind. -## 6. Enforce the law with a seam +Both wikilinks and markdown path refs must be repointed (Research `See Also` lists and bench +pages are where path refs hide). Then **regenerate** index rows with a script, never by hand. +The generator bug to check for: presence tested as a **bare stem substring** — a page whose +name prefixes another's (`frank-medium` inside `frank-medium-rocmfpx`) then silently never +gets a row. Test the wikilink form `[[]]`. + +## 7. Enforce the law with a seam `tests/docs_completeness.bats`: derive the live set instead of hardcoding it — an endpoint is live when `scripts/` holds **both** `.env` and `.service`; fail if any -`-*.md` page exists in the vault, and guard against a vacuous derivation -(`derived -ge 3`). A re-created era page then cannot pass tests. +`-*.md` page exists, and guard against a vacuous derivation (`derived -ge 3`). A +re-created era page then cannot pass tests. For the length hint, prefer **derived** exemptions +(live endpoint, or a `retired-endpoint` tag: a campaign ledger that exists nowhere else is +owned by the page that measured it) plus one documented per-page opt-out; never let a size +ceiling force a ledger to be split across two owners. -## 7. Edit-tool hazard (costs the most time) +## 8. Edit-tool hazard (costs the most time) Body rows beginning with `-` or `+` are op markers. The documented `+-` escape **writes a literal `+`** — do not use it. Safe rewrites inside an existing bullet: keep the `- ` opener @@ -86,30 +104,49 @@ line untouched and PUT only the indented continuation lines, or convert the note bullet whose body lines start with two/four spaces. If a wrapped `[[Two Word Page]]` shows up as an unresolved link, the target was hard-wrapped across lines — unwrap it. -## 8. Merge order (a long-lived branch under a moving main) +## 9. Delegated writes: verify bytes, never narrative + +Measured in one campaign, all four failure modes live: +- A subagent killed by the runtime limit yielded a 495-line owner page, a verified era table + and a byte census — **the file did not exist** and its table was self-referential. +- Another wrote its output to disk and died without reporting, leaving a rewritten `log.md`; + the census showed it had dropped laws held nowhere else. +- Verdict tables claimed "0 sole records / no contradictions" while missing the contradiction + sitting in their own evidence row, and invented bullet IDs — one renamed a bullet to the + **opposite** claim. +- A scout called accurate docs "WRONG" because the docs said `wip: "down"`. + +Rules: after ANY delegated write run `wc`/`ls` + the orphan census yourself; re-grep every +claimed holder before cutting a line; treat `cancelled`/timed-out yields as unverified no +matter how concrete they read; and re-read the source bullet before trusting a table's ID. + +## 10. Merge order (a long-lived branch under a moving main) 1. Commit your work in atomic groups **before** merging (a dirty tree cannot merge cleanly). -2. Inspect the incoming commits first: `git log --oneline --stat HEAD..origin/main`. If they - modify a page you deleted, **port their additions into the owner page**, then merge and - resolve the modify/delete as `git rm`. +2. Inspect the incoming commits: `git log --oneline --stat HEAD..origin/main`. If they modify + a page you deleted, **port their additions into the owner page**, then merge and resolve + the modify/delete as `git rm`. 3. Resolve a content block with `write conflict://` (`@ours` / `@theirs` / explicit text), - then **`git add` the file** — resolving content does not stage it, and `git commit` refuses - with "you have unmerged files". -4. `git * --no-verify` is forbidden here; commit hooks are fine. -5. Sweep for dead paths left in `AGENTS.md`: `grep -oE "[A-Za-z0-9._-]+\.md" AGENTS.md | sort -u` - then `find` each. Expect false positives from names hard-wrapped across two lines — confirm - each with `ls` before "fixing". + then **`git add` the file** — resolving content does not stage it. +4. **Re-probe live state after the merge, before you write any number.** A campaign that + reported fleet shapes at the start was made stale by a mid-campaign reslice on main: probe + `/slots` and `tr '\0' '\n' < /proc/$(pidof )/cmdline` again at the end, and let the + live answer beat both your earlier probe and the docs. +5. `git * --no-verify` is forbidden here. Sweep dead paths in `AGENTS.md` + (`grep -oE "[A-Za-z0-9._-]+\.md" AGENTS.md | sort -u`, then `find` each; hard-wrapped names + are false positives — confirm with `ls`). -## 9. Verify, open, land +## 11. Verify, open, land -- `./tests/run.sh` (full suite) + `bats tests/docs_completeness.bats` + - `python3 scripts/check-vault-links.py serverAppConfigs-docs` → must print `0 unresolved links`. -- Env trims: prove value-neutrality mechanically — `git show HEAD:scripts/.env | grep -E - '^[A-Z_]+=' | sort` vs the working copy, diff must be empty, then run that service's seam. - **Warn that `scripts/.env` is a deploy-planner path**: a comment-only trim makes the - next service-scoped deploy restart a healthy endpoint for identical values. +- `./tests/run.sh` (full suite) + `python3 scripts/check-vault-links.py serverAppConfigs-docs` + → must print `0 unresolved links`, and the OKF linter `0 violations`. +- Env trims: prove value-neutrality mechanically (`git show HEAD:scripts/.env | grep -E + '^[A-Z_]+=' | sort` vs working copy, diff empty). **`scripts/.env` is a deploy-planner + path**: a comment-only trim makes the next service-scoped deploy restart a healthy endpoint. - Open the PR through the API with a 600-perm curl config (managed skill `gitea-api-pr-operations`), end the body with the `cwd:` / `session:` footer, then - `xdg-open ` the instant it exists. + `xdg-open ` the instant it exists. Never merge without Frank's current explicit OK. - Docs-only change ⇒ **no deploy**. Fast-forward the deploy checkout only (`git -C ~/Projects/serverAppConfig merge --ff-only origin/main`). +- Say what was NOT done, in the PR body: soft lint tallies left (missing `## Citations`), + conflicts left standing, repo config that was never installed on a host. diff --git a/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json b/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json index d9cc3aa..c8713ba 100644 --- a/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json +++ b/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json @@ -1,6 +1,6 @@ { "v": 1, - "lastConsolidatedAt": 1792411412495, + "lastConsolidatedAt": 1792415312526, "lastResult": { "at": 1792401456699, "sessions": 1, diff --git a/agent/memories/sharpshooter/wt-20261019-020309-6d1fc1f-8knxmfcrfa1k/state.json b/agent/memories/sharpshooter/wt-20261019-020309-6d1fc1f-8knxmfcrfa1k/state.json index d47eb0f..3929eb9 100644 --- a/agent/memories/sharpshooter/wt-20261019-020309-6d1fc1f-8knxmfcrfa1k/state.json +++ b/agent/memories/sharpshooter/wt-20261019-020309-6d1fc1f-8knxmfcrfa1k/state.json @@ -1,6 +1,6 @@ { "v": 1, - "lastConsolidatedAt": 1792411509877, + "lastConsolidatedAt": 1792415169883, "lastResult": { "at": 1792402864677, "sessions": 1, diff --git a/agent/memories/sharpshooter/wt-20261019-021028-6d1fc1f-3p69q8c3d94kw/state.json b/agent/memories/sharpshooter/wt-20261019-021028-6d1fc1f-3p69q8c3d94kw/state.json index 2d18ae0..9f27130 100644 --- a/agent/memories/sharpshooter/wt-20261019-021028-6d1fc1f-3p69q8c3d94kw/state.json +++ b/agent/memories/sharpshooter/wt-20261019-021028-6d1fc1f-3p69q8c3d94kw/state.json @@ -1,6 +1,6 @@ { "v": 1, - "lastConsolidatedAt": 1792411648565, + "lastConsolidatedAt": 1792415248646, "lastResult": { "at": 1792401394555, "sessions": 1, diff --git a/dotfiles/noctalia/.local/state/noctalia/settings.toml b/dotfiles/noctalia/.local/state/noctalia/settings.toml index d563e09..24ed69c 100644 --- a/dotfiles/noctalia/.local/state/noctalia/settings.toml +++ b/dotfiles/noctalia/.local/state/noctalia/settings.toml @@ -275,10 +275,10 @@ transition = [ "fade" ] interval_seconds = 1200 [wallpaper.default] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_odl3r9.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_6kzekl.jpg" [wallpaper.last] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_odl3r9.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_6kzekl.jpg" [wallpaper.monitors.DP-1] path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_y8ewzk.jpg" @@ -290,7 +290,7 @@ transition = [ "fade" ] path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_v9e2w3.jpg" [wallpaper.monitors.eDP-1] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_odl3r9.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_6kzekl.jpg" [weather] unit = "imperial"