@deftai/directive-content 0.91.0 → 0.92.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/QUICK-START.md +1 -1
- package/docs/deft-directive-disable.md +96 -0
- package/docs/directive-lifecycle.md +16 -0
- package/docs/getting-started.md +2 -0
- package/docs/no-deft-directive.md +1 -0
- package/docs/skill-pin-policy.md +7 -0
- package/package.json +1 -1
- package/packs/lessons/lessons-pack-0.1.json +85 -45
- package/packs/skills/skills-pack-0.1.json +6 -3
- package/skills/deft-directive-review-cycle/SKILL.md +50 -2
- package/skills/deft-directive-setup/SKILL.md +104 -1
- package/skills/deft-directive-swarm/references/core-ops.md +1 -0
- package/skills/deft-directive-swarm/references/core-phase-0.md +6 -0
- package/skills/deft-directive-swarm/references/host-openclaw.md +10 -0
- package/templates/agent-prompt-preamble.md +3 -0
- package/templates/agents-entry.md +10 -0
- package/templates/swarm-greptile-poller-prompt.md +48 -5
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"lifecycle"
|
|
14
14
|
],
|
|
15
15
|
"source": "Anthropic, \"Effective Context Engineering for AI Agents\"",
|
|
16
|
-
"body": "**Source:** Anthropic, \"Effective Context Engineering for AI Agents\"\n\n**Key insight:** Context rot is real
|
|
16
|
+
"body": "**Source:** Anthropic, \"Effective Context Engineering for AI Agents\"\n\n**Key insight:** Context rot is real — more tokens ≠ better performance. Every low-signal token actively degrades output quality. The goal is the smallest set of high-signal tokens.\n\n**What was added:** `context/` directory with five guides (context.md, working-memory.md, long-horizon.md, tool-design.md, examples.md) covering Write/Select/Compress/Isolate strategies, vBRIEF integration for structured scratchpads and checkpoints, and surgical edits to main.md and REFERENCES.md for integration."
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"id": "pr-review-process-2026-03",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"review-cycle",
|
|
26
26
|
"github"
|
|
27
27
|
],
|
|
28
|
-
"source": "Bootstrap parity PR (#83)
|
|
29
|
-
"body": "**Source:** Bootstrap parity PR (#83)
|
|
28
|
+
"source": "Bootstrap parity PR (#83) — 13-round Greptile review cycle on `fix/45-bootstrap-parity`",
|
|
29
|
+
"body": "**Source:** Bootstrap parity PR (#83) — 13-round Greptile review cycle on `fix/45-bootstrap-parity`\n\n**1. Review bots post to two channels — both MUST be checked before declaring clean**\n\nGitHub review bots (e.g. Greptile) post inline diff threads (returned by MCP `get_review_comments`) AND a separate \"Comments Outside Diff\" section in the rolling summary comment (NOT returned by MCP). A PR MUST NOT be declared review-clean until both sources are verified. The outside-diff check MUST use `do_not_summarize_output: true` to prevent summarizers silently dropping that section.\n\n**2. Wide PRs have non-linear review costs**\n\nA PR touching CLI code, TUI code, prose documents, and tests simultaneously creates combinatorial review exposure — each change can generate parity issues in other areas. A 4-surface PR does not take 4× the review effort; in practice it took 13 rounds. SHOULD split changes into focused PRs: code changes separate from prose/instructional document changes.\n\n**3. Instructional documents SHOULD be read as a consumer before opening a PR**\n\nProse files (SKILL.md, strategy files, README sections) have flow correctness that diffs do not capture — missing bridging instructions, wrong step ordering, and one-question-rule violations are all invisible in a diff view but immediately apparent when read linearly. Before opening a PR that modifies instructional documents, SHOULD read them from start to finish as the agent or user following them would.\n\n**4. Lint fixes MUST NOT weaken test fault detection without a conscious decision**\n\nWhen a linter demands an explicit parameter (e.g. `strict=` on `zip()`), the chosen value has semantic meaning. In a content-validation test, `strict=True` is more defensive — a malformed row causes an immediate, obvious failure. `strict=False` silently drops mismatched data. MUST evaluate whether a lint fix weakens fault detection; if it does, prefer the more defensive value. Satisfying a linter at the cost of test quality is not a net improvement.\n\n**5. CHANGELOG promotion is a release step, not a PR step — treat them as distinct**\n\nThe PR checklist correctly guards `[Unreleased]` entries during review. But promoting `[Unreleased]` → `[X.Y.Z]` (and updating the comparison links) is a **post-merge release step** that happens at tag time, not PR time. These two steps are easy to conflate and the promotion is easy to forget when the tag and push happen in rapid succession. Until `task release` is implemented (tracked in issue #74), the release sequence MUST be: (1) promote CHANGELOG, (2) commit, (3) tag, (4) push tag. MUST NOT tag before the CHANGELOG promotion commit is on the target branch."
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"id": "toolchain-validation-gate-2026-03",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"ci",
|
|
38
38
|
"release"
|
|
39
39
|
],
|
|
40
|
-
"source": "Issue #106
|
|
41
|
-
"body": "**Source:** Issue #106
|
|
40
|
+
"source": "Issue #106 — full DEFT workflow completed on iOS/Swift project without Xcode or task installed",
|
|
41
|
+
"body": "**Source:** Issue #106 — full DEFT workflow completed on iOS/Swift project without Xcode or task installed\n\n**The agent completed interview → PRD → SPEC → implementation without verifying the toolchain**\n\nAn agent ran the full DEFT interview (selecting strict release gate: unit + UI + accessibility + performance tests), scaffolded and implemented an iOS app, ran only `swift test` (4 tests, no coverage), and declared success. Neither `task` nor Xcode were available in the session. The quality gates the user explicitly chose were never enforceable.\n\nExisting directives (`! Run all relevant checks`, `\u2297 Claim checks passed without running them`) did not prevent this — they govern *execution*, not *prerequisite verification*. There was no rule requiring the agent to verify that the tools needed to enforce quality gates existed before implementation began.\n\n**Before beginning any implementation phase, MUST verify that the complete toolchain required for that phase is installed and functional. If the build or test toolchain is unavailable, stop and report — do not proceed. Quality gates chosen during the interview are meaningless if the tools to enforce them are absent.**"
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
"id": "build-script-output-validation-2026-03",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"tags": [
|
|
49
49
|
"agent-orchestration"
|
|
50
50
|
],
|
|
51
|
-
"source": "Issue #105
|
|
52
|
-
"body": "**Source:** Issue #105
|
|
51
|
+
"source": "Issue #105 — silent `dist/` failure in a Chrome extension build",
|
|
52
|
+
"body": "**Source:** Issue #105 — silent `dist/` failure in a Chrome extension build\n\n**AI edits to build scripts can silently drop asset copy steps — builds succeed but `dist/` is stale**\n\nAn AI edit to `build.mjs` dropped a `copyFileSync` call for `manifest.json`. The build ran without error, but `dist/manifest.json` was stale — missing `content_scripts`, `storage`, and `host_permissions`. The extension overlay silently failed with no visible error.\n\nExisting directives (`! Run all relevant checks`, `! Call out risk when touching build systems`) did not prevent this — they are process rules (run checks) not output validation rules (verify what was produced). A build exiting 0 is not proof that `dist/` is correct.\n\n**When modifying a build script, MUST verify that expected output artifacts exist and are structurally valid after the build runs. Non-compiled assets that bundlers don't track (manifests, configs, extension metadata) are especially at risk of silent omission.**"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"id": "multi-agent-orchestration-via-oz-cli-2026-04",
|
|
@@ -61,12 +61,12 @@
|
|
|
61
61
|
"swarm",
|
|
62
62
|
"review-cycle"
|
|
63
63
|
],
|
|
64
|
-
"source": "Two parallel local agents on roadmap items
|
|
65
|
-
"body": "**Source:** Two parallel local agents on roadmap items
|
|
64
|
+
"source": "Two parallel local agents on roadmap items — PR #149 (strategy consolidation) and PR #150 (content fixes)",
|
|
65
|
+
"body": "**Source:** Two parallel local agents on roadmap items — PR #149 (strategy consolidation) and PR #150 (content fixes)\n\n**1. `oz agent run --mcp` with UUID MUST NOT be used from standalone terminals**\n\nThe `--mcp` flag with a Warp-configured MCP server UUID requires Warp app context (OAuth tokens, session state). Spawning `oz agent run` in a standalone PowerShell window via `Start-Process` fails with \"Failed to start MCP servers\". Agents launched outside Warp MUST use `gh` CLI for GitHub operations instead of MCP.\n\n**2. Agent prompts MUST lead with explicit task directives, not context**\n\nAn agent given a prompt starting with \"You are working in the deft directive repository...\" followed by task instructions treated the entire message as passive context, read the directives, and stopped without doing any work. The same tasks given with a prompt starting \"TASK: You must complete 5 documentation fixes...\" executed correctly. When prompting autonomous agents via `oz agent run --prompt`, the first line MUST be an imperative action statement. Context and constraints SHOULD follow the task.\n\n**3. Agents SHOULD be isolated in separate git worktrees for parallel work**\n\nTwo agents working the same repo on different branches need separate working directories. Git worktrees (`git worktree add`) provide branch isolation without full clones. Each worktree gets its own launch script. MUST ensure no file overlap between agents' assigned tasks to avoid merge conflicts.\n\n**4. Review cycle completion is not guaranteed — monitor agent MUST be prepared to take over**\n\nAgent 1 created its PR and stopped before running the Greptile review cycle (the prompt's Step 9). Agent 2 ran 4 autonomous review rounds successfully. The difference was prompt structure. A monitoring agent MUST check whether each spawned agent completed the full workflow and be prepared to finish incomplete steps."
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
68
|
"id": "parallel-agent-swarm-first-full-run-2026-04",
|
|
69
|
-
"title": "Parallel Agent Swarm
|
|
69
|
+
"title": "Parallel Agent Swarm — First Full Run (2026-04)",
|
|
70
70
|
"date": "2026-04",
|
|
71
71
|
"issue_refs": [],
|
|
72
72
|
"tags": [
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"agent-orchestration",
|
|
75
75
|
"review-cycle"
|
|
76
76
|
],
|
|
77
|
-
"source": "4-agent swarm on Phase 1 roadmap items
|
|
78
|
-
"body": "**Source:** 4-agent swarm on Phase 1 roadmap items
|
|
77
|
+
"source": "4-agent swarm on Phase 1 roadmap items — PRs #154, #155, #156, #157 (14 issues closed)",
|
|
78
|
+
"body": "**Source:** 4-agent swarm on Phase 1 roadmap items — PRs #154, #155, #156, #157 (14 issues closed)\n\n**1. ~~`oz agent run` launches CLOUD agents~~ — CORRECTION: `oz agent run` is LOCAL; `oz agent run-cloud` is the cloud path**\n\n⚠️ **This lesson was incorrect.** Warp confirmed: `oz agent run` runs agents **locally** on the user's machine (supports `--cwd`, `--profile`, `--mcp`; gets codebase indexing and Warp Drive rules). `oz agent run-cloud` runs agents **remotely** on cloud VMs with no local context.\n\nThe original lesson was written after the 4-agent swarm (PRs #154–#157) where agents appeared to lose MCP and local context. The actual cause was not that `oz agent run` routes to cloud. **Corrected rule:** `oz agent run --cwd <path> --prompt \"...\"` is the PREFERRED automated local launch path. MUST use `oz agent run-cloud` only when cloud execution is explicitly desired. MUST NOT conflate the two commands. (#172)\n\n**2. Warp terminal tabs MUST NOT be assumed openable programmatically**\n\nThere is no API or CLI command to open a new Warp terminal tab from an agent or script. When the user said \"launch\", the monitor agent silently used `Start-Process` to open standalone PowerShell windows instead of asking the user to open Warp tabs manually. The user expected Warp tabs with full context. Agents MUST present the tradeoffs (local vs. cloud vs. standalone) and let the user choose before launching.\n\n**3. Sequential merging of PRs with shared append-only files causes rebase cascades**\n\nCHANGELOG.md and SPECIFICATION.md are \"append-only\" shared files — each agent adds entries without editing existing content. However, when PRs are merged sequentially, each merge changes the file at the same insertion point, causing merge conflicts for remaining PRs. Merging #154 conflicted #155 and #157; merging #155 conflicted #157 again. Each conflict required rebase → push → wait for checks (~3 min). Four PRs required 3 rebase cycles. SHOULD merge all PRs in rapid succession or rebase all remaining PRs before starting merges.\n\n**4. File-overlap audit MUST check transitive file touches, not just primary scope**\n\nThe file-overlap audit assigned `skills/deft-review-cycle/SKILL.md` exclusively to Agent 3. But Agent 2 (enforcement rules, #123) added a `/deft:change` verification step to the same file as part of strengthening the review cycle's Phase 1 audit. This was a transitive touch — the enforcement task's acceptance criteria required changes to a file in another agent's scope. The overlap audit MUST trace each task's acceptance criteria to specific files, not just the task's primary scope.\n\n**5. SPECIFICATION.md task status MUST be verified before assigning work**\n\nThe original Agent 2 was scoped to #31 and #50 (strategy consolidation). Both had spec tasks (t1.4.1, t1.4.2) marked `[completed]` in SPECIFICATION.md, but the ROADMAP.md still listed them as open. Verifying the spec caught this before agents wasted time reimplementing done work. The select phase MUST cross-reference ROADMAP.md against SPECIFICATION.md status before assigning.\n\n**6. PR numbers don't match agent numbers — include agent ID in branch/PR naming**\n\nGitHub assigns PR numbers in creation order, which depends on which agent finishes first. Agent 2's PR became #154 while Agent 1's became #156. This caused confusion during monitoring and merging. Branch names SHOULD include the agent number (e.g. `agent1/fix/...`) or PR titles SHOULD include `[Agent N]` for traceability.\n\n**7. ~~Cloud agents~~ Agents stopped after PR creation — likely a prompt completeness issue, not a cloud limitation**\n\n⚠️ **Context correction:** The agents in this lesson were launched via `oz agent run` which (see corrected Lesson #1) is **local**, not cloud. The two-pass behavior was likely due to incomplete prompt instructions, not an inherent limitation of the execution environment.\n\nThe core lesson remains valid: when agents stop before completing the full workflow (PR + review cycle), the monitor MUST be prepared to complete the remaining steps. Ensure the prompt's STEP 6 (review cycle) instruction is explicit enough to prevent early termination — regardless of whether agents are local or cloud. (#172)"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"id": "option-a-oz-agent-run-context-limitations-2026-04",
|
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
"github",
|
|
88
88
|
"swarm"
|
|
89
89
|
],
|
|
90
|
-
"source": "Issue #179
|
|
91
|
-
"body": "**Source:** Issue #179
|
|
90
|
+
"source": "Issue #179 — live testing of `oz agent run` during swarm orchestration",
|
|
91
|
+
"body": "**Source:** Issue #179 — live testing of `oz agent run` during swarm orchestration\n\n**1. `oz agent run` does NOT receive global Warp Drive rules, MCP UUIDs, or auto-injected context**\n\nTesting revealed that `oz agent run` launched from the terminal does not automatically receive global Warp Drive rules (personal rules stored in Warp Drive > Personal > Rules), MCP servers via UUID, or Warp Drive notebooks/workflows. The only context an Option A agent gets is: `AGENTS.md` in the `--cwd` directory, the agent profile specified with `--profile`, and codebase indexing (non-blocking, background). This makes Option A effectively as context-limited as cloud agents (`oz agent run-cloud`) — the only difference is execution location (local vs remote VM).\n\n**Option B (interactive Warp tab) is the correct choice for full local context** until a future Warp build with experimental orchestration support brings Option A to parity. Option B agents get full MCP, global rules, Warp Drive context, warm codebase indexing, and are interruptible mid-run.\n\n**2. Inline MCP JSON is a partial workaround for Option A but not zero-config**\n\nMCP servers can be passed via inline JSON instead of UUID: `--mcp '{\"github\": {\"url\": \"https://api.githubcopilot.com/mcp/\"}}'`. This works around the UUID proxy issue but requires knowing the MCP endpoint URL and managing auth separately. Not a substitute for Option B's zero-config MCP injection."
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
"id": "windows-file-editing-2026-03",
|
|
@@ -100,8 +100,8 @@
|
|
|
100
100
|
"powershell",
|
|
101
101
|
"windows"
|
|
102
102
|
],
|
|
103
|
-
"source": "ROADMAP.md edits during feat/agents-md-onboarding-54
|
|
104
|
-
"body": "**Source:** ROADMAP.md edits during feat/agents-md-onboarding-54
|
|
103
|
+
"source": "ROADMAP.md edits during feat/agents-md-onboarding-54 — three sequential failures before clean write",
|
|
104
|
+
"body": "**Source:** ROADMAP.md edits during feat/agents-md-onboarding-54 — three sequential failures before clean write\n\n**1. CRLF line endings break multi-line edit_files searches — MUST verify line endings before batch edits**\n\nThe edit_files tool matches search strings against file content byte-for-byte. Files with Windows CRLF (\\r\\n) line endings will silently fail to match search strings that assume LF (\\n) only. On any Windows repo, MUST check line endings first ((Get-Content file -Raw) -match '\\r\\n'). If CRLF is present, fall back to PowerShell Get-Content -Raw / [System.IO.File]::WriteAllText for multi-line edits rather than batching multiple edit_files diffs.\n\n**2. PowerShell 5.1 Set-Content MUST NOT be used on UTF-8 files — not even with -Encoding UTF8**\n\nGet-Content | ... | Set-Content in PowerShell 5.1 defaults to the system ANSI code page (Windows-1252), silently mangling non-ASCII characters. But using `-Encoding UTF8` is also wrong: PowerShell 5.1's UTF8 encoding writes a BOM (byte-order mark, \\xEF\\xBB\\xBF) at byte 0, corrupting every special character across the entire file when re-read by tools that don't expect a BOM. MUST use `[System.IO.File]::WriteAllText(path, content, (New-Object System.Text.UTF8Encoding $false))` — the `$false` argument explicitly disables the BOM. Never use Set-Content for UTF-8 files on Windows PowerShell 5.1.\n\n**3. Markdown table rows in files with CRLF endings MUST be inserted via PowerShell, not edit_files**\n\nThe edit_files tool matches byte-for-byte. ROADMAP.md uses CRLF line endings. When inserting new table rows using edit_files, the mismatch between LF in the search/replace strings and CRLF in the file causes row content to be inserted with a doubled leading pipe (`|| #NNN |` instead of `| #NNN |`), shifting all columns right and breaking table alignment. This has surfaced in multiple sessions (PR #130, PR #173). When appending rows to the Open Issues Index or any markdown table in a CRLF file, MUST use PowerShell `[System.IO.File]` methods or a targeted regex replace — never edit_files for table row insertions. After any table edit, MUST verify row prefixes before committing: `Select-String -Path ROADMAP.md -Pattern '\\|\\| #[0-9]'` should return no matches.\n\n**4. PowerShell 5.1 `Set-Content` corrupts UTF-8 files in TWO ways — BOM removal alone is not a fix**\n\nWhen PS5.1 `Set-Content` (or `Set-Content -Encoding UTF8`) writes a UTF-8 file, it causes two distinct corruptions: (1) a BOM is prepended at byte 0, and (2) the entire file body is re-encoded from UTF-8 to Windows-1252 (ANSI), converting every multi-byte character to mojibake (for example em-dashes `—` become `—`, arrows `→` become `→`, and other Unicode symbols are mangled similarly). These are independent corruptions — stripping the BOM does NOT restore the body. A file can have no BOM and still be corrupted throughout.\n\nThe only correct recovery from `Set-Content` corruption is: (1) restore the original file bytes via `git checkout <ref> -- path/to/file` — MUST NOT use `git show <ref>:path/to/file` piped through PowerShell, as the pipeline silently re-decodes the bytes as Windows-1252 and re-introduces the mojibake; (2) read the restored file with `[System.IO.File]::ReadAllText(path, [System.Text.Encoding]::UTF8)`; (3) apply only the intended edits as string operations; (4) write back with `[System.IO.File]::WriteAllText(path, content, (New-Object System.Text.UTF8Encoding $false))`. MUST NOT attempt to fix `Set-Content` corruption by stripping just the BOM — the body will still be corrupted throughout."
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
"id": "review-cycle-monitoring-2026-04",
|
|
@@ -113,8 +113,8 @@
|
|
|
113
113
|
"github",
|
|
114
114
|
"swarm"
|
|
115
115
|
],
|
|
116
|
-
"source": "PR #173 review cycle
|
|
117
|
-
"body": "**Source:** PR #173 review cycle
|
|
116
|
+
"source": "PR #173 review cycle — shell polling loop against static SHA failed to detect Greptile completion",
|
|
117
|
+
"body": "**Source:** PR #173 review cycle — shell polling loop against static SHA failed to detect Greptile completion\n\n**1. Greptile review completion MUST be polled via MCP `get_check_runs` against the PR head, not `gh api` with a static commit SHA**\n\nWhen a new commit is pushed while a polling loop is running, Greptile starts a fresh check run on the new head SHA. A shell `while` loop polling `gh api repos/{owner}/{repo}/commits/{old_sha}/check-runs` will never see completion because the completed run is on a different commit. MUST use MCP `pull_request_read` with `method: get_check_runs` — this always targets the current PR head regardless of how many commits have been pushed. Compare the `completed_at` field and `conclusion` to confirm the review is current and passed.\n\n**2. MUST NOT push any commit while Greptile review is in progress — even for unrelated changes**\n\nEvery push re-triggers Greptile on the new head. If additional fixes or improvements are identified while waiting for a review, stage them locally but hold the push until the review of the current head is complete and analyzed. \"Trivial\" or \"safe\" commits are not exceptions — the rule applies unconditionally. Violating this resets Greptile's clock and can create a loop where the bot never finishes reviewing a stable state. (#175, incident: PR #173)\n\n**3. Poll interval MUST include a genuine delay (≥60 seconds) between `get_check_runs` calls**\n\nGreptile reviews typically take 3–7 minutes. Calling `get_check_runs` in rapid back-to-back succession (seconds apart) adds no information and creates noise in the conversation. MUST use a real sleep between polls — `Start-Sleep -Seconds 60` (PowerShell) or equivalent. Do NOT report \"polling again\" as if time has passed when it has not. (#175, incident: PR #173 monitoring loop)\n\n**4. After pushing, agent MUST autonomously poll for review updates without stopping to ask the user**\n\nAgents dispatched with a review cycle task (especially cloud/swarm agents) stopped after pushing fix commits and asked the user \"should I continue?\" or \"want me to check the review?\" This breaks the autonomous review/fix loop and requires human intervention for every cycle iteration. The review/fix loop in `skills/deft-review-cycle/SKILL.md` is designed to run to the exit condition (no P0/P1 issues, confidence > 3) without human intervention. After pushing, the agent MUST poll for the Greptile review update, analyze findings, and continue fixing — treating the entire loop as a single autonomous operation. (#184)"
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
"id": "greptile-re-review-on-rebase-force-push-2026-04",
|
|
@@ -125,8 +125,8 @@
|
|
|
125
125
|
"review-cycle",
|
|
126
126
|
"swarm"
|
|
127
127
|
],
|
|
128
|
-
"source": "Issue #207
|
|
129
|
-
"body": "**Source:** Issue #207
|
|
128
|
+
"source": "Issue #207 — swarm merge cascade latency during PRs #154–#157",
|
|
129
|
+
"body": "**Source:** Issue #207 — swarm merge cascade latency during PRs #154–#157\n\n**1. Force-pushing a rebased branch triggers a FULL Greptile re-review, not an incremental diff**\n\nDuring merge cascades, each remaining PR must be rebased onto updated master and force-pushed. Each force-push triggers Greptile to re-review the entire PR from scratch — not just the rebase diff — because Greptile treats force-push as a new commit history. Expected latency is ~2-5 minutes per PR. For a cascade of N PRs, this adds (N-1) × ~2-5 minutes of Greptile wait time on top of CI. MUST factor Greptile re-review latency into merge cascade planning.\n\n**2. Rebase-only force-pushes MAY be annotated with a PR comment for Greptile context**\n\nWhen a force-push contains no logic changes (pure rebase onto updated master), the monitor MAY post a brief PR comment noting \"rebase-only, no logic changes\" before force-pushing. This gives human reviewers (and potentially Greptile) context that the re-review is structural, not functional. This is advisory, not mandatory — Greptile will re-review regardless.\n\n**3. Merge cascade time estimate MUST include Greptile re-review latency**\n\nThe original merge cascade lesson (#3 in Parallel Agent Swarm) documented ~3 min CI per rebase cycle. The full cost is ~3 min CI + ~2-5 min Greptile re-review per rebase. For N PRs, plan for (N-1) × (~3 min CI + ~2-5 min Greptile) total additional wait time."
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
"id": "mid-task-instant-fix-drift-2026-04",
|
|
@@ -137,8 +137,8 @@
|
|
|
137
137
|
"review-cycle",
|
|
138
138
|
"github"
|
|
139
139
|
],
|
|
140
|
-
"source": "Issues #159, #167, #184
|
|
141
|
-
"body": "**Source:** Issues #159, #167, #184
|
|
140
|
+
"source": "Issues #159, #167, #184 — agents derailed active tasks to apply instant fixes for discovered issues",
|
|
141
|
+
"body": "**Source:** Issues #159, #167, #184 — agents derailed active tasks to apply instant fixes for discovered issues\n\n**1. Discovered issues MUST be filed as GitHub issues, not fixed in-place mid-task**\n\nAgents repeatedly interrupted their current task to fix an unrelated issue they discovered along the way (e.g. a typo in another file, a missing test, a stale reference). This caused scope drift, broke the review cycle, and introduced unplanned changes into PRs scoped to specific issues. When a new issue is discovered during an active task, the agent MUST file a GitHub issue and continue the current task — do not apply an instant fix, even if it seems trivial.\n\n**2. Skill execution MUST stop at the skill's explicit instruction boundary**\n\nAgents continued executing past the final step of a skill into adjacent work — for example, after completing a review cycle, an agent started fixing unrelated issues it noticed during the review. A skill's final step is an exit condition. When the skill's steps are complete, the agent MUST stop and return to the calling context. Do not drift into adjacent work, even if it seems related. (#198)"
|
|
142
142
|
},
|
|
143
143
|
{
|
|
144
144
|
"id": "skills-scan-before-improvising-2026-04",
|
|
@@ -148,8 +148,8 @@
|
|
|
148
148
|
"tags": [
|
|
149
149
|
"review-cycle"
|
|
150
150
|
],
|
|
151
|
-
"source": "Issue #200
|
|
152
|
-
"body": "**Source:** Issue #200
|
|
151
|
+
"source": "Issue #200 — agents improvised multi-step workflows that already existed as skills",
|
|
152
|
+
"body": "**Source:** Issue #200 — agents improvised multi-step workflows that already existed as skills\n\n**1. MUST scan skills/ for existing coverage before designing a workflow from scratch**\n\nAgents were asked to run a review cycle and improvised a multi-step process from scratch, missing the existing `skills/deft-review-cycle/SKILL.md` that encodes lessons from dozens of prior review rounds. The skills/ directory contains versioned, tested workflows that encode hard-won operational lessons. Before designing any multi-step workflow, the agent MUST scan skills/ for an existing skill that covers the task. If a matching skill exists, use it — do not reinvent it. (#200)"
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
"id": "pr-merge-hygiene-2026-04",
|
|
@@ -160,8 +160,8 @@
|
|
|
160
160
|
"github",
|
|
161
161
|
"debugging"
|
|
162
162
|
],
|
|
163
|
-
"source": "Issue #167
|
|
164
|
-
"body": "**Source:** Issue #167
|
|
163
|
+
"source": "Issue #167 — PRs merged but issues not closed and roadmap not updated",
|
|
164
|
+
"body": "**Source:** Issue #167 — PRs merged but issues not closed and roadmap not updated\n\n**1. Squash merge + closing keywords can silently fail to close issues — MUST verify after every squash merge**\n\nGitHub processes closing keywords (`Closes #N`, `Fixes #N`) from the PR body when a PR is merged. For regular merge commits, this works reliably. For **squash merges**, GitHub rewrites the commit into a single squash commit and may not always process the closing keywords from the original PR body — the auto-close can silently fail with no error or notification. The PR shows as merged, but the linked issues remain open.\n\nRoot cause: GitHub's squash merge constructs a new commit message from the PR title and description. If the closing keyword appears only in the PR body (not the squash commit's final message), or if GitHub's keyword parser does not match the rewritten message format, the issue auto-close is skipped silently. This is a known GitHub behavior difference between regular merges and squash merges.\n\n**After every squash merge, MUST verify that referenced issues actually closed:** `gh issue view <N> --json state --jq .state`. If the issue is still open, close it manually with a comment referencing the merged PR: `gh issue close <N> --comment \"Closed by #<PR> (squash merge — auto-close did not trigger)\"`. (#167)"
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"id": "warp-terminal-multi-line-powershell-string-splitting-2026-04",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
"github"
|
|
175
175
|
],
|
|
176
176
|
"source": "Issue #240 -- multi-line PS here-strings pasted into Warp agent input caused syntax errors",
|
|
177
|
-
"body": "**Source:** Issue #240 -- multi-line PS here-strings pasted into Warp agent input caused syntax errors\n\n**1. Warp splits multi-line PowerShell here-strings across separate command blocks -- MUST use temp files**\n\nWhen a multi-line PowerShell string literal (here-string `@\" ... \"@`) is pasted or entered directly into the Warp agent terminal input box, Warp's input handling splits the content across separate command blocks at line boundaries. Each block is sent as a separate command, causing immediate syntax errors (the opening `@\"` is sent without its closing `\"@`) or silent truncation of the string content.\n\n**Root cause:** Warp's terminal input box treats newlines as command separators. A multi-line here-string that spans N lines becomes N separate commands, none of which is syntactically valid on its own.\n\n**Fix:** Always write multi-line PS content to a temp file first (`[System.IO.File]::WriteAllText($tmpFile, $content, [System.Text.UTF8Encoding]::new($false))`), then reference the temp file path in subsequent commands. This avoids the input splitting entirely. (#240)\n\n**Cross-reference:** `scm/github.md`
|
|
177
|
+
"body": "**Source:** Issue #240 -- multi-line PS here-strings pasted into Warp agent input caused syntax errors\n\n**1. Warp splits multi-line PowerShell here-strings across separate command blocks -- MUST use temp files**\n\nWhen a multi-line PowerShell string literal (here-string `@\" ... \"@`) is pasted or entered directly into the Warp agent terminal input box, Warp's input handling splits the content across separate command blocks at line boundaries. Each block is sent as a separate command, causing immediate syntax errors (the opening `@\"` is sent without its closing `\"@`) or silent truncation of the string content.\n\n**Root cause:** Warp's terminal input box treats newlines as command separators. A multi-line here-string that spans N lines becomes N separate commands, none of which is syntactically valid on its own.\n\n**Fix:** Always write multi-line PS content to a temp file first (`[System.IO.File]::WriteAllText($tmpFile, $content, [System.Text.UTF8Encoding]::new($false))`), then reference the temp file path in subsequent commands. This avoids the input splitting entirely. (#240)\n\n**Cross-reference:** `scm/github.md` — Warp Terminal Multi-Line String Handling subsection."
|
|
178
178
|
},
|
|
179
179
|
{
|
|
180
180
|
"id": "duplicate-tab-failure-mode-2026-04",
|
|
@@ -212,8 +212,8 @@
|
|
|
212
212
|
"lifecycle",
|
|
213
213
|
"agent-orchestration"
|
|
214
214
|
],
|
|
215
|
-
"source": "v0.20.0-rc.3 validation on MScottAdams/slizard-rc3-test
|
|
216
|
-
"body": "**Source:** v0.20.0-rc.3 validation on MScottAdams/slizard-rc3-test
|
|
215
|
+
"source": "v0.20.0-rc.3 validation on MScottAdams/slizard-rc3-test — issues #566, #567, #571, #572, #574",
|
|
216
|
+
"body": "**Source:** v0.20.0-rc.3 validation on MScottAdams/slizard-rc3-test — issues #566, #567, #571, #572, #574\n\n**1. Frameworks that vendor-require a task runner MUST have explicit platform-matrix CI on that runner**\n\nLanguage-level tests (pytest, go test, etc.) do not catch task-runner-specific defects: template-expansion quirks, path normalization on Windows, shell interpretation differences across OSes. A framework that documents \"use go-task\" (or make, just, etc.) MUST include CI jobs that exercise the runner on every supported OS — at minimum Linux + macOS + Windows if the consumer audience spans those. #566 was a go-task + Windows `GetFullPathNameW` + mixed-separator-normalization interaction; the existing Linux-only CI would never have caught it. Added the `windows-task-dispatch` job in #568 as the regression guard; that pattern MUST be preserved and extended as new render / migration / lifecycle tasks ship.\n\n**2. go-task `vars:` templates re-evaluate at use site in included subfiles — path vars MUST be defined per-subfile with eager `joinPath`**\n\nA `vars:` entry like `DEFT_ROOT: '{{.TASKFILE_DIR}}'` declared in a root Taskfile does NOT hold the root's TASKFILE_DIR value when referenced from an included subfile — go-task re-expands the template in the subfile's scope, where TASKFILE_DIR points at the subfile's own directory. To stabilize a path var across the include hierarchy, define it in each subfile that uses it via the eager form `DEFT_ROOT: '{{joinPath .TASKFILE_DIR \"..\"}}'`. `joinPath` is evaluated at template-expansion time with Go's `filepath.Clean`, producing a native-separator, `..`-free absolute path.\n\nCorollary: **pytest guard-rails on task file *content* are insufficient** for template-expansion correctness. A test that verifies `{{joinPath .TASKFILE_DIR \"..\"}}` appears in the file tells you nothing about what it expands to at runtime. MUST pair static content checks with a live subprocess dispatch test that invokes the task through `task --dry-run` or equivalent. This near-miss was caught in #568's pre-push local validation, not by the pytest guard-rail — which passed green on the wrong configuration.\n\n**3. A task that accepts user recovery flags in CLI_ARGS MUST NOT declare `sources:`/`generates:` incremental-build keys**\n\ngo-task's `sources:` / `generates:` declarations cause the task runner to skip `cmds:` entirely when inputs haven't changed and outputs exist — printing `Task \"X\" is up to date` without dispatching anything. CLI_ARGS (`-- --force`, `-- --rebuild`, etc.) are relayed only if `cmds:` actually runs, so any user recovery flag documented in a script's error message (e.g. the `#539` \"Re-run with --force\" pattern) will silently no-op when the task is cached. Every task whose script emits \"Re-run with --force\"-style error messages MUST declare neither `sources:` nor `generates:`. See `deft/conventions/task-caching.md` (scaffolded in the #574 fix) for the canonical rule and the regression guard-rail. (#539, #573, #574)\n\n**4. Error messages that prescribe a recovery command are a contract — they MUST be regression-tested**\n\nWhen a tool emits an error of the shape \"to recover, run X\", following X literally MUST actually recover. A documented recovery command that doesn't work is worse than no recovery message at all — it sends the operator down a dead-end path believing they've followed the correct fix. MUST add a regression test for every prescriptive error message: reproduce the error, run the command the message suggests literally, assert the expected post-recovery state. Applies equally to operator-facing errors and agent-facing errors. (#539, #574)\n\n**5. Heuristics that detect \"machine-generated\" by fishing for substrings MUST be part of a canonical marker contract shared with the writers**\n\nWhen code like `migrate_vbrief.py::_is_user_customized()` decides preservation vs overwrite based on whether a file contains strings such as `\"Generated by\"` or `\"spec_render.py\"`, those strings MUST be part of a canonical banner contract that the relevant writers (`spec_render.py`, `prd_render.py`, `roadmap_render.py`, `migrate_vbrief.py` deprecation stubs, and any future render / stub emitters) actually emit. A detector-writer asymmetry — where the detector fishes for text nobody writes — is a latent correctness bug waiting to misclassify operator edits as auto-generated content or vice versa. MUST co-locate the marker specification (as a `deft/conventions/<topic>.md` doc), the writers that emit it, and the detectors that consume it, with a regression test asserting every writer's output matches what every detector expects. (#572)"
|
|
217
217
|
},
|
|
218
218
|
{
|
|
219
219
|
"id": "github-closing-keyword-false-positive-in-negation-context-2026-04",
|
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
"swarm"
|
|
227
227
|
],
|
|
228
228
|
"source": "PR #697 -- issue #642 (a tracking umbrella for PR #401) was auto-closed on squash merge despite the PR body intentionally avoiding closing keywords. Recurrence record extended in PR #735 (#737 deterministic encoding gap-closer); see the third bullet below.",
|
|
229
|
-
"body": "**Source:** PR #697 -- issue #642 (a tracking umbrella for PR #401) was auto-closed on squash merge despite the PR body intentionally avoiding closing keywords. Recurrence record extended in PR #735 (#737 deterministic encoding gap-closer); see the third bullet below.\n\n**1. GitHub's closing-keyword parser is substring-based -- the literal token `Closes #N` MUST NOT appear in the PR body even inside a negation, quotation, or example**\n\nThe PR body for #697 contained the parenthetical `` (Intentionally not `Closes #642` -- #642 is a tracking umbrella that should remain open until PR #401's full scope is merged or split into linked follow-up issues.) ``. The text was negating the closing keyword in plain English, but GitHub's auto-close parser operates on token presence, not surrounding semantics. The squash merge processed the literal `Closes #642` substring and closed the issue. The same hazard applies to `Fixes #N`, `Resolves #N`, and the past-tense / lowercase variants (`closed`, `fixed`, `resolved`, etc. -- see GitHub's full keyword list).\n\n**Rule:** When a PR body needs to discuss what it intentionally does NOT close (e.g. tracking umbrellas, partial scope, deferred follow-ups), MUST phrase the disclaimer without using any closing keyword token at all. Use phrasings like:\n\n- \"Intentionally NOT using a closing keyword for #N\" (omits the trigger token entirely)\n- \"Refs #N (tracking umbrella; remains open)\" (use `Refs` only)\n- \"#N stays open as the umbrella anchor for follow-up work\" (no trigger token)\n\n\u2297 MUST NOT write `Closes #N`, `Fixes #N`, `Resolves #N`, or any GitHub closing keyword in a PR body even when negating, quoting, or showing as an example -- the parser does not respect surrounding context.\n\n**2. Post-merge issue-state verification MUST run for every squash merge regardless of intent**\n\nThe existing post-merge verification rule (Lesson: PR Merge Hygiene #1, #167) was framed around closing-keyword failures (issues that should have closed but didn't). The opposite failure mode -- issues that should have stayed open but were auto-closed -- is just as real and is caught by the same check. After every squash merge, MUST verify the state of every issue mentioned in the PR body matches intent: closed if a closing keyword was used; open if only `Refs` was used. If an issue was closed in error, reopen it with a comment referencing the PR and explaining why it should remain open (e.g. tracking umbrella, partial scope). (#697)\n\n**3. Recurrence (#735): the squash-commit body for that PR contained a negation-context clause referencing #734 in a way that auto-closed it on merge despite intent (the issue was the parent for the in-flight #737 work and had to be reopened manually). #737 closes this gap structurally with a deterministic pre-PR lint (`scripts/pr_check_closing_keywords.py`, surfaced via `task pr:check-closing-keywords`) that scans both the PR body AND every commit message for closing-keyword tokens followed by `#\\d+` in negation / quotation / example / code-block contexts and refuses to push when findings surface. The lint is wired into `skills/deft-directive-pre-pr/SKILL.md` Phase 4 (Diff) and cross-referenced from `skills/deft-directive-swarm/SKILL.md` Phase 6 Step 1 as the Layer 0 (prevention) surface alongside the existing Layer 3 (recovery) `task pr:check-protected-issues` (#701).**\n\n**Cross-reference:** existing lesson \"PR Merge Hygiene\" #1 (#167); `scm/github.md` PR conventions; `skills/deft-directive-review-cycle/SKILL.md` Post-Merge Verification; `skills/deft-directive-pre-pr/SKILL.md` Phase 4 (Layer 0 prevention, #737); `skills/deft-directive-swarm/SKILL.md` Phase 6 Step 1 (Layer 3 recovery, #701).\n\n**4. Class D (#3015): premature *real* `Closes #N` with conditional / multi-phase English is a different failure than class A negation FP**\n\nenterprize PR #30 body contained `Closes #29 Phase A intake only if you want intake closed
|
|
229
|
+
"body": "**Source:** PR #697 -- issue #642 (a tracking umbrella for PR #401) was auto-closed on squash merge despite the PR body intentionally avoiding closing keywords. Recurrence record extended in PR #735 (#737 deterministic encoding gap-closer); see the third bullet below.\n\n**1. GitHub's closing-keyword parser is substring-based -- the literal token `Closes #N` MUST NOT appear in the PR body even inside a negation, quotation, or example**\n\nThe PR body for #697 contained the parenthetical `` (Intentionally not `Closes #642` -- #642 is a tracking umbrella that should remain open until PR #401's full scope is merged or split into linked follow-up issues.) ``. The text was negating the closing keyword in plain English, but GitHub's auto-close parser operates on token presence, not surrounding semantics. The squash merge processed the literal `Closes #642` substring and closed the issue. The same hazard applies to `Fixes #N`, `Resolves #N`, and the past-tense / lowercase variants (`closed`, `fixed`, `resolved`, etc. -- see GitHub's full keyword list).\n\n**Rule:** When a PR body needs to discuss what it intentionally does NOT close (e.g. tracking umbrellas, partial scope, deferred follow-ups), MUST phrase the disclaimer without using any closing keyword token at all. Use phrasings like:\n\n- \"Intentionally NOT using a closing keyword for #N\" (omits the trigger token entirely)\n- \"Refs #N (tracking umbrella; remains open)\" (use `Refs` only)\n- \"#N stays open as the umbrella anchor for follow-up work\" (no trigger token)\n\n\u2297 MUST NOT write `Closes #N`, `Fixes #N`, `Resolves #N`, or any GitHub closing keyword in a PR body even when negating, quoting, or showing as an example -- the parser does not respect surrounding context.\n\n**2. Post-merge issue-state verification MUST run for every squash merge regardless of intent**\n\nThe existing post-merge verification rule (Lesson: PR Merge Hygiene #1, #167) was framed around closing-keyword failures (issues that should have closed but didn't). The opposite failure mode -- issues that should have stayed open but were auto-closed -- is just as real and is caught by the same check. After every squash merge, MUST verify the state of every issue mentioned in the PR body matches intent: closed if a closing keyword was used; open if only `Refs` was used. If an issue was closed in error, reopen it with a comment referencing the PR and explaining why it should remain open (e.g. tracking umbrella, partial scope). (#697)\n\n**3. Recurrence (#735): the squash-commit body for that PR contained a negation-context clause referencing #734 in a way that auto-closed it on merge despite intent (the issue was the parent for the in-flight #737 work and had to be reopened manually). #737 closes this gap structurally with a deterministic pre-PR lint (`scripts/pr_check_closing_keywords.py`, surfaced via `task pr:check-closing-keywords`) that scans both the PR body AND every commit message for closing-keyword tokens followed by `#\\d+` in negation / quotation / example / code-block contexts and refuses to push when findings surface. The lint is wired into `skills/deft-directive-pre-pr/SKILL.md` Phase 4 (Diff) and cross-referenced from `skills/deft-directive-swarm/SKILL.md` Phase 6 Step 1 as the Layer 0 (prevention) surface alongside the existing Layer 3 (recovery) `task pr:check-protected-issues` (#701).**\n\n**Cross-reference:** existing lesson \"PR Merge Hygiene\" #1 (#167); `scm/github.md` PR conventions; `skills/deft-directive-review-cycle/SKILL.md` Post-Merge Verification; `skills/deft-directive-pre-pr/SKILL.md` Phase 4 (Layer 0 prevention, #737); `skills/deft-directive-swarm/SKILL.md` Phase 6 Step 1 (Layer 3 recovery, #701).\n\n**4. Class D (#3015): premature *real* `Closes #N` with conditional / multi-phase English is a different failure than class A negation FP**\n\nenterprize PR #30 body contained `Closes #29 Phase A intake only if you want intake closed…`. Layer 0 FP mode (#737) exited 0 (no negation/quote/example/code context). GitHub still matched `Closes #29` and completed multi-phase issue #29 while Phase B/C remained undone.\n\n- Class A = keyword in negation/quote/example/code (FP) — #737\n- Class D = bare or conditional real closing keyword without full DoD — #3015 intent mode\n\n**Rule:** Default PR body uses `Tracking: #N` / `Related: #N` / `Refs #N`. Use `Closes`/`Fixes`/`Resolves #N` only at full issue DoD, and pass `--allow-close N` on the lint (CLI allowlist only). \u2297 `Closes #N Phase A` / `only if` / partial English around a real closing keyword.\n\n`task pr:check-closing-keywords` default mode is `both` (FP + intent). `--mode fp` is the class-A-only regression path."
|
|
230
230
|
},
|
|
231
231
|
{
|
|
232
232
|
"id": "github-closing-keyword-false-positive-layer-3-persistent-closingissuesreferences-link-2026-04",
|
|
@@ -265,7 +265,7 @@
|
|
|
265
265
|
"swarm"
|
|
266
266
|
],
|
|
267
267
|
"source": "#910 -- v0.25.1 swarm session 2026-05-04 (4-agent cohort #899/#900/#901/#902 -> PRs #906/#907/#908/#909) produced THREE false-negatives in a single session because the badge-only detector in `templates/swarm-greptile-poller-prompt.md` missed Greptile findings rendered as markdown bullets (#907 first review, #908 first review) and inline prose (#908 retrigger, sentinel-only signal `Not safe to merge until ...`). Each false-negative cost ~30 min poll budget plus a fresh review-cycle agent dispatch.",
|
|
268
|
-
"body": "**Source:** #910 -- v0.25.1 swarm session 2026-05-04 (4-agent cohort #899/#900/#901/#902 -> PRs #906/#907/#908/#909) produced THREE false-negatives in a single session because the badge-only detector in `templates/swarm-greptile-poller-prompt.md` missed Greptile findings rendered as markdown bullets (#907 first review, #908 first review) and inline prose (#908 retrigger, sentinel-only signal `Not safe to merge until ...`). Each false-negative cost ~30 min poll budget plus a fresh review-cycle agent dispatch.\n\n**Failure mode:** Greptile renders findings in at least THREE distinct surface forms across review passes on the same PR (HTML severity badges; markdown-bullet bold like `- **P1 -- ...**`; inline prose like `Three P1 findings ...` or `Not safe to merge`). The pre-#910 detector covered only Tier 1 (badges); the markdown-bullet handling lived in the Notes section but NOT in the prescribed detector code path; inline-prose was not covered at all. Single-tier detection is structurally insufficient against a reviewer that switches rendering modes between passes.\n\n**Canonical encoding (strongest-applicable layer):** the rule body lives in the template artifact -- `templates/swarm-greptile-poller-prompt.md` `### P0/P1 findings detection (TRIPLE-TIER -- #910)` -- which prescribes Tier 1 (badge count), Tier 2 (markdown-bullet bold scan with line-scoped negation guards), and Tier 3 (inline-prose sentinels: `Not safe to merge` substring, `(One|Two|...|\\d+) P[01] findings?` count regex with negation + leading-`0` guards, `^P[01] -- ` line-anchored regex), combined via `has_blocking = (max(tier1_p0, tier2_p0) + max(tier1_p1, tier2_p1)) > 0 or tier3_sentinel`. Tier 1 deterministic enforcement: `tests/content/test_swarm_poller_template.py` ships 14 regression tests covering the six behaviour-matrix cases from the #910 acceptance criteria (markdown-bullet only / `Not safe to merge` only / count-prose only / negation-guard / clean / pure-badge) PLUS eight synchronization tests asserting the template encodes the canonical regex strings + sentinels verbatim AND a `str.format(...)` render guard so a future unescaped `{` in the code block fails CI immediately.\n\n**Why this is a short cross-reference, not a full prose rule:** per the Rule Authority [AXIOM] block in `main.md`, every rule MUST use the strongest applicable layer (deterministic > Taskfile > vBRIEF > RFC2119 > prose). The rule body lives in the template artifact + the deterministic content tests; this lessons entry exists for discoverability + recurrence-record citation only.\n\n**Cross-references:** `templates/swarm-greptile-poller-prompt.md` (rule body); `tests/content/test_swarm_poller_template.py` (deterministic regression coverage); `tests/content/test_skills.py` `test_swarm_greptile_poller_prompt_*` lane (existing #727 placeholder + parsing-fix coverage, kept verbatim); existing `## Orchestrator Role Separation + Canonical Poller Template (2026-04)` lesson (parent context, #727); v0.25.1 swarm session anchor (2026-05-04); recurrence record (#907 first review, #908 first review, #908 retrigger); this lesson (#910). Second-recurrence extension (#1035, PR #1034 -- 2026-05-11): Tier 2.5 SLizard `### P[01]
|
|
268
|
+
"body": "**Source:** #910 -- v0.25.1 swarm session 2026-05-04 (4-agent cohort #899/#900/#901/#902 -> PRs #906/#907/#908/#909) produced THREE false-negatives in a single session because the badge-only detector in `templates/swarm-greptile-poller-prompt.md` missed Greptile findings rendered as markdown bullets (#907 first review, #908 first review) and inline prose (#908 retrigger, sentinel-only signal `Not safe to merge until ...`). Each false-negative cost ~30 min poll budget plus a fresh review-cycle agent dispatch.\n\n**Failure mode:** Greptile renders findings in at least THREE distinct surface forms across review passes on the same PR (HTML severity badges; markdown-bullet bold like `- **P1 -- ...**`; inline prose like `Three P1 findings ...` or `Not safe to merge`). The pre-#910 detector covered only Tier 1 (badges); the markdown-bullet handling lived in the Notes section but NOT in the prescribed detector code path; inline-prose was not covered at all. Single-tier detection is structurally insufficient against a reviewer that switches rendering modes between passes.\n\n**Canonical encoding (strongest-applicable layer):** the rule body lives in the template artifact -- `templates/swarm-greptile-poller-prompt.md` `### P0/P1 findings detection (TRIPLE-TIER -- #910)` -- which prescribes Tier 1 (badge count), Tier 2 (markdown-bullet bold scan with line-scoped negation guards), and Tier 3 (inline-prose sentinels: `Not safe to merge` substring, `(One|Two|...|\\d+) P[01] findings?` count regex with negation + leading-`0` guards, `^P[01] -- ` line-anchored regex), combined via `has_blocking = (max(tier1_p0, tier2_p0) + max(tier1_p1, tier2_p1)) > 0 or tier3_sentinel`. Tier 1 deterministic enforcement: `tests/content/test_swarm_poller_template.py` ships 14 regression tests covering the six behaviour-matrix cases from the #910 acceptance criteria (markdown-bullet only / `Not safe to merge` only / count-prose only / negation-guard / clean / pure-badge) PLUS eight synchronization tests asserting the template encodes the canonical regex strings + sentinels verbatim AND a `str.format(...)` render guard so a future unescaped `{` in the code block fails CI immediately.\n\n**Why this is a short cross-reference, not a full prose rule:** per the Rule Authority [AXIOM] block in `main.md`, every rule MUST use the strongest applicable layer (deterministic > Taskfile > vBRIEF > RFC2119 > prose). The rule body lives in the template artifact + the deterministic content tests; this lessons entry exists for discoverability + recurrence-record citation only.\n\n**Cross-references:** `templates/swarm-greptile-poller-prompt.md` (rule body); `tests/content/test_swarm_poller_template.py` (deterministic regression coverage); `tests/content/test_skills.py` `test_swarm_greptile_poller_prompt_*` lane (existing #727 placeholder + parsing-fix coverage, kept verbatim); existing `## Orchestrator Role Separation + Canonical Poller Template (2026-04)` lesson (parent context, #727); v0.25.1 swarm session anchor (2026-05-04); recurrence record (#907 first review, #908 first review, #908 retrigger); this lesson (#910). Second-recurrence extension (#1035, PR #1034 -- 2026-05-11): Tier 2.5 SLizard `### P[01] ·` heading detector + confidence-heading parser fallback added under #1035; rule body lives in `templates/swarm-greptile-poller-prompt.md` and the deterministic content tests at `tests/content/test_swarm_poller_template.py`. Third-recurrence extension (#1039, PR #1038 -- 2026-05-11): the canonical poller's (5)-condition CLEAN gate could not distinguish a parse-gap from \"Greptile still working\" -- both kept `has_blocking_combined = False` AND `is_clean = False` and the poller burned its full 30-minute cap on a textbook clean review (poller agent `5794b0e7-...`; maintainer intervened out-of-band). Resolved under #1039 by adding (a) a Tier 1 per-poll instrumentation log line (`[poll i/cap] last_reviewed_sha=... head=... sha_match=... confidence=... has_blocking=... p0=... p1=... errored=... ci_failures=... is_clean=... clean_gate_holdout=...`) so the operator can grep the transcript and see WHICH of the five conditions held the gate; (b) the (5) STALL terminal exit -- a bounded fail-loud exit at ~4.5 min (N=3 consecutive wedged polls at the 90s interval) carrying the canonical subject `PR #<N> poll loop wedged -- terminal-condition detection failure`; (c) Tier 3 per-condition fail-loud -- BOTH (4) TIMEOUT AND (5) STALL exit messages surface `clean_gate_holdout` naming the FIRST failing condition among (1) `sha_match` / (2) `has_blocking` / (3) `confidence` / (4) `ci_failures` / (5) `errored`. Per the Rule Authority [AXIOM] strongest-applicable-layer rule, the rule body lives in `templates/swarm-greptile-poller-prompt.md`'s `## CLEAN gate evaluation, clean_gate_holdout, and per-poll instrumentation (#1039)` + `### (5) STALL` blocks, with deterministic regression coverage in `tests/content/test_swarm_poller_template.py` (behaviour-matrix lane covers AC-1 through AC-4; synchronization-test lane pins the template encoding). The #727 Sub-Agent Role Separation rule that mandates use of this canonical template means a detector gap is a silent false-negative for every conformant sub-agent until landed -- the architectural fix is to surface the gap LOUD via the STALL exit rather than pretend the prescribed parser set is exhaustive across all Greptile / SLizard rendering modes."
|
|
269
269
|
},
|
|
270
270
|
{
|
|
271
271
|
"id": "vbrief-lifecycle-drift-on-release-2026-04",
|
|
@@ -318,8 +318,8 @@
|
|
|
318
318
|
"ci",
|
|
319
319
|
"swarm"
|
|
320
320
|
],
|
|
321
|
-
"source": "PR #652 incident 2026-05-01 -- the directive agent attempted to start a merge cascade against `Confidence: 3/5 + 1
|
|
322
|
-
"body": "**Source:** PR #652 incident 2026-05-01 -- the directive agent attempted to start a merge cascade against `Confidence: 3/5 + 1
|
|
321
|
+
"source": "PR #652 incident 2026-05-01 -- the directive agent attempted to start a merge cascade against `Confidence: 3/5 + 1×P1 + 2×P2` because the GitHub `Greptile Review` CheckRun was SUCCESS. Symmetric blind spot to the NEUTRAL-CheckRun case codified in #526: both are wrong-oracle failures where the agent trusts a CheckRun status as proxy for review approval.",
|
|
322
|
+
"body": "**Source:** PR #652 incident 2026-05-01 -- the directive agent attempted to start a merge cascade against `Confidence: 3/5 + 1×P1 + 2×P2` because the GitHub `Greptile Review` CheckRun was SUCCESS. Symmetric blind spot to the NEUTRAL-CheckRun case codified in #526: both are wrong-oracle failures where the agent trusts a CheckRun status as proxy for review approval.\n\n**Generalizable pattern:** ANY reviewer-posted CheckRun is a **completion** signal, not an **approval** signal. The CheckRun goes green when the bot finishes its review pass, irrespective of findings or confidence. For Greptile specifically: SUCCESS can hide unresolved P0/P1 + low confidence in the comment body; NEUTRAL can hide a service-side error in the comment body (#526). Both require parsing the body, not the status.\n\n**Canonical encoding (strongest-applicable layer):** the operative `!` MUST rules and `\u2297` MUST NOT anti-patterns live in `skills/deft-directive-swarm/SKILL.md` Phase 5->6 -- programmatic gate (`task pr:merge-ready -- <N>`), atomic-shell-call freshness window (`task pr:merge-ready -- <N> && gh pr merge <N>` chained in the same shell call), SUCCESS-CheckRun-alone prohibition, upstream-batched-readiness-check prohibition. Tier 1 deterministic enforcement: `scripts/pr_merge_readiness.py` parses the Greptile rolling-summary comment body (badge-count P0/P1 detection, structured-section heading fallback, errored-sentinel detection, HEAD-SHA freshness, confidence parse) and exits non-zero on any gate failure; `tests/cli/test_pr_merge_readiness.py` regression-tests the PR #652 incident signature so the same wording cannot pass through the gate again.\n\n**Why this is a short cross-reference, not a full prose rule:** per the Rule Authority [AXIOM] block in `main.md`, every rule MUST use the strongest applicable layer (deterministic > Taskfile > vBRIEF > RFC2119 > prose). The rule body lives in the deterministic gate (`scripts/pr_merge_readiness.py`) wrapped by the `task pr:merge-ready` Taskfile target and surfaced in the swarm SKILL section above; this lessons entry exists for discoverability + recurrence-record citation only.\n\n**Cross-references:** `skills/deft-directive-swarm/SKILL.md` Phase 5->6 (primary encoding); `scripts/pr_merge_readiness.py` (deterministic gate); `tasks/pr.yml::merge-ready` (Taskfile surface); `tests/cli/test_pr_merge_readiness.py` (regression coverage); existing #526 NEUTRAL-CheckRun lesson (symmetric blind spot); #796 (sibling late-arriving-bot-review re-check gap, separate fix); PR #652 incident (recurrence record)."
|
|
323
323
|
},
|
|
324
324
|
{
|
|
325
325
|
"id": "review-cycle-fail-closed-exit-and-non-greedy-sha-2026-06",
|
|
@@ -376,7 +376,7 @@
|
|
|
376
376
|
"agent-orchestration"
|
|
377
377
|
],
|
|
378
378
|
"source": "#796 -- the `skills/deft-directive-review-cycle/SKILL.md` Phase 2 Step 1 dual-source-fetch contract (which correctly catches the `Comments Outside Diff` case via `gh pr view --comments` + MCP `get_review_comments` or `gh api` fallback) does not cover the cold-start case where the agent's first fetch lands BEFORE the bot reviewer (Greptile) has posted. Both sources return zero findings; the Step 6 exit condition false-positively declares the PR review-clean even though the bot review is still in flight. The Step 4 polling loop covers any cycle that includes a push, but the cold-start one-shot review-cycle entry path is uncovered.",
|
|
379
|
-
"body": "**Source:** #796 -- the `skills/deft-directive-review-cycle/SKILL.md` Phase 2 Step 1 dual-source-fetch contract (which correctly catches the `Comments Outside Diff` case via `gh pr view --comments` + MCP `get_review_comments` or `gh api` fallback) does not cover the cold-start case where the agent's first fetch lands BEFORE the bot reviewer (Greptile) has posted. Both sources return zero findings; the Step 6 exit condition false-positively declares the PR review-clean even though the bot review is still in flight. The Step 4 polling loop covers any cycle that includes a push, but the cold-start one-shot review-cycle entry path is uncovered.\n\n**Canonical encoding (strongest-applicable layer):** the operative `~` SHOULD rule (`Late-arriving bot review re-check`) and the matching `\u2297` MUST NOT rule (no exit on a single empty fetch -- re-fetch at least once after a ~60s delay first) live in `skills/deft-directive-review-cycle/SKILL.md` Phase 2 Step 1, before the Step 6 exit-condition evaluation. Tier 1 deterministic enforcement: `tests/content/test_review_cycle_skill.py` regex-asserts the rule presence + canonical phrasing tokens (`re-fetch`, `60s`, `before evaluating`, `re-fetch at least once`) plus a defence-in-depth guard against the cp1252 mojibake form `\
|
|
379
|
+
"body": "**Source:** #796 -- the `skills/deft-directive-review-cycle/SKILL.md` Phase 2 Step 1 dual-source-fetch contract (which correctly catches the `Comments Outside Diff` case via `gh pr view --comments` + MCP `get_review_comments` or `gh api` fallback) does not cover the cold-start case where the agent's first fetch lands BEFORE the bot reviewer (Greptile) has posted. Both sources return zero findings; the Step 6 exit condition false-positively declares the PR review-clean even though the bot review is still in flight. The Step 4 polling loop covers any cycle that includes a push, but the cold-start one-shot review-cycle entry path is uncovered.\n\n**Canonical encoding (strongest-applicable layer):** the operative `~` SHOULD rule (`Late-arriving bot review re-check`) and the matching `\u2297` MUST NOT rule (no exit on a single empty fetch -- re-fetch at least once after a ~60s delay first) live in `skills/deft-directive-review-cycle/SKILL.md` Phase 2 Step 1, before the Step 6 exit-condition evaluation. Tier 1 deterministic enforcement: `tests/content/test_review_cycle_skill.py` regex-asserts the rule presence + canonical phrasing tokens (`re-fetch`, `60s`, `before evaluating`, `re-fetch at least once`) plus a defence-in-depth guard against the cp1252 mojibake form `\u2297` of the `\u2297` glyph (the corruption fixed in PR #844 review-cycle on the same cohort's pending vBRIEFs). The poller template at `templates/swarm-greptile-poller-prompt.md` already handles the same case for push-driven cycles via its loop body -- the SKILL rule above closes the orthogonal cold-start path.\n\n**Why this is a short cross-reference, not a full prose rule:** per the Rule Authority [AXIOM] block in `main.md`, every rule MUST use the strongest applicable layer (deterministic > Taskfile > vBRIEF > RFC2119 > prose). The rule body lives in the SKILL Phase 2 Step 1 rules + the content test; this lessons entry exists for discoverability + recurrence-record citation only.\n\n**Cross-references:** `skills/deft-directive-review-cycle/SKILL.md` Phase 2 Step 1 (primary encoding); `tests/content/test_review_cycle_skill.py` (deterministic contract); `templates/swarm-greptile-poller-prompt.md` (no-op for the poller -- loop body already handles this; positive guidance for the one-shot review-cycle entry path); user rule `KthiAoZEVMVffm0rv4vxQ6` (qualitative precedent); existing `## PR Review Process (2026-03)` #1 lesson (sibling: dual-source fetching + Comments Outside Diff); this lesson (#796)."
|
|
380
380
|
},
|
|
381
381
|
{
|
|
382
382
|
"id": "ps-5-1-non-ascii-round-trip-corruption-elevated-to-deterministic-tier-2026-05",
|
|
@@ -401,8 +401,8 @@
|
|
|
401
401
|
"encoding",
|
|
402
402
|
"powershell"
|
|
403
403
|
],
|
|
404
|
-
"source": "mid-session 2026-05-07
|
|
405
|
-
"body": "**Source:** mid-session 2026-05-07
|
|
404
|
+
"source": "mid-session 2026-05-07 — `gh issue create` against `deftai/webinstaller` returned `GraphQL: API rate limit already exceeded for user ID ...` while `gh api rate_limit` reported `core: 4996/5000 remaining`, `graphql: 0/5000 remaining`. The same operation completed instantly via `gh api repos/<owner>/<repo>/issues --method POST --input <payload.json>`. Same identity drove both surfaces; the rate-limit failure was bucket-specific, not global.",
|
|
405
|
+
"body": "**Source:** mid-session 2026-05-07 — `gh issue create` against `deftai/webinstaller` returned `GraphQL: API rate limit already exceeded for user ID ...` while `gh api rate_limit` reported `core: 4996/5000 remaining`, `graphql: 0/5000 remaining`. The same operation completed instantly via `gh api repos/<owner>/<repo>/issues --method POST --input <payload.json>`. Same identity drove both surfaces; the rate-limit failure was bucket-specific, not global.\n\n**1. Many `gh` subcommands route through GraphQL — the `core` REST bucket is independent**\n\n`gh issue create`, `gh issue close`, `gh issue comment`, `gh pr ready`, `gh pr merge`, and most other write operations issue a GraphQL mutation, billing the `graphql` bucket (5000 points/hr per user). The `gh api ...` family (default REST) bills the `core` REST bucket (5000 calls/hr per user). The two are independent. When `graphql` is exhausted, `gh issue ...` fails hard but `gh api repos/<owner>/<repo>/issues --method POST/PATCH/GET ...` continues to work. MUST inspect `gh api rate_limit` per-bucket `remaining` rather than treating the failure message as a global rate-limit signal.\n\n**2. REST fallback for issue mutations**\n\nWhen the `graphql` bucket is contended (parallel agents on shared identity, swarm-shaped polling, etc.) MUST prefer REST equivalents:\n- Create issue: `gh api repos/<owner>/<repo>/issues --method POST --input <payload.json>`\n- Post comment: `gh api repos/<owner>/<repo>/issues/<N>/comments --method POST --input <payload.json>`\n- Close issue: `gh api repos/<owner>/<repo>/issues/<N> --method PATCH -f state=closed -f state_reason=completed`\n- Open PR: `gh api repos/<owner>/<repo>/pulls --method POST --input <payload.json>` with `{title, head, base, body}`\n\nClosing-keyword auto-close on PR squash merge runs server-side and is unaffected by the agent's bucket choice.\n\n**3. UTF-8 safe `gh api --input` payload pattern on PS 5.1**\n\n`gh api --input <file>` reads a JSON file; building that file via PS 5.1 inline string operations corrupts non-ASCII content (em dashes, arrows, smart quotes — see existing PS 5.1 lessons #236 / #240 / #283 / PR #795 / #798). The canonical UTF-8 safe pattern is:\n\n(a) Write the markdown body to a temp file via the `create_file` tool OR Python `pathlib.Path(p).write_text(text, encoding='utf-8')`.\n(b) Build the JSON wrapper via Python: `import json, pathlib; pathlib.Path(payload).write_text(json.dumps({'body': pathlib.Path(body).read_text(encoding='utf-8')}), encoding='utf-8')`.\n(c) Invoke `gh api ... --input <payload>`.\n\nMUST NOT round-trip non-ASCII content through PS 5.1 `Get-Content` / `Set-Content` / `-replace` / backtick-n interpolation as the JSON wrapper.\n\n**Cross-references:** `scripts/verify_encoding.py` (sibling deterministic gate, #798); existing #236 / #240 / #283 / PR #795 / #798 PS 5.1 chain; existing `## Windows File Editing` #2 / #4 (write-side prose-tier rules); 2026-05-07 mid-session surfacing (deftai/webinstaller#171 filing + deftai/directive#884 closeout via REST)."
|
|
406
406
|
},
|
|
407
407
|
{
|
|
408
408
|
"id": "cross-machine-parallel-agents-single-agent-swarm-pattern-2026-05",
|
|
@@ -414,8 +414,8 @@
|
|
|
414
414
|
"swarm",
|
|
415
415
|
"github"
|
|
416
416
|
],
|
|
417
|
-
"source": "2026-05-07 session running #884 closeout in parallel with another agent's #947 cache-cap implementation on a different machine. Both agents authenticated as the same GitHub identity. The closeout used `skills/deft-directive-swarm/SKILL.md` with N=1 sub-agent
|
|
418
|
-
"body": "**Source:** 2026-05-07 session running #884 closeout in parallel with another agent's #947 cache-cap implementation on a different machine. Both agents authenticated as the same GitHub identity. The closeout used `skills/deft-directive-swarm/SKILL.md` with N=1 sub-agent
|
|
417
|
+
"source": "2026-05-07 session running #884 closeout in parallel with another agent's #947 cache-cap implementation on a different machine. Both agents authenticated as the same GitHub identity. The closeout used `skills/deft-directive-swarm/SKILL.md` with N=1 sub-agent — not the multi-agent vBRIEF allocation the skill was designed for, but the orchestrator-yields pattern and the REST-only sub-agent dispatch worked cleanly.",
|
|
418
|
+
"body": "**Source:** 2026-05-07 session running #884 closeout in parallel with another agent's #947 cache-cap implementation on a different machine. Both agents authenticated as the same GitHub identity. The closeout used `skills/deft-directive-swarm/SKILL.md` with N=1 sub-agent — not the multi-agent vBRIEF allocation the skill was designed for, but the orchestrator-yields pattern and the REST-only sub-agent dispatch worked cleanly.\n\n**1. Cross-machine parallel agents share API quota when they share identity**\n\nTwo agents on different machines but the same GitHub user share the `core` (5000/hr) and `graphql` (5000pts/hr) buckets at the personal-account level. Local file overlap is impossible (different filesystems), but API contention is real — the closeout session's `graphql` exhaustion was plausibly driven by the other agent's polling on the other machine. MUST treat shared-identity multi-machine agents as competing for the same API quota, even though file and branch isolation are automatic. SHOULD prefer GraphQL-light paths (REST mutations, ghx-cached reads, longer poll intervals) when running concurrent shared-identity sessions, and SHOULD agree explicit ownership of shared append-only files (CHANGELOG.md `[Unreleased]`) before launching the parallel work.\n\n**2. Single-agent swarm-skill use is a legitimate steerability primitive**\n\n`skills/deft-directive-swarm/SKILL.md` is documented as \"parallel local agent orchestration\" and the Phase 0–6 ladder is sized for N≥2. But the Phase 6 Sub-Agent Role Separation pattern (#727) — parent dispatches a fresh sub-agent via `start_agent`, parent yields with no tool calls, sub-agent reports back via messaging — works as a general orchestration primitive even at N=1, because it preserves the parent's steerability while the sub-agent runs the API-bound work. The Phase 0–3 implementation ladder is skipped when the sub-agent's task is non-code (administrative closeout, polling, observation). MAY use single-agent dispatch under this skill when the user explicitly directs it; the swarm-vs-direct decision is about steerability and conversation isolation, not parallelism.\n\n**3. Non-code sub-agents do not require the implementation preflight gate (#810)**\n\nThe implementation preflight gate (`scripts/preflight_implementation.py`, surfaced via `task vbrief:preflight`) is documented as a precondition for \"code-writing tool calls or `start_agent` dispatch for implementation\". Administrative closeout sub-agents (post comment + PATCH state, run smoke commands, verify deliverables, file follow-up issues) are not implementation — they write no repo files, branch nothing, open no PR. MUST NOT require a scope vBRIEF for a non-code sub-agent. MUST still require an explicit action-verb directive from the user before dispatching a non-code sub-agent that has potential side effects on shared state (issue mutations, force-pushes, deletions, branch deletes).\n\n**4. Constrain sub-agent prompts with `\u2297` MUST-NOT lines around scope expansion**\n\nA closeout sub-agent given freedom to \"expand scope as appropriate\" can drift into an adjacent issue's territory (broader migration, related cache work, unrelated polish) if the prompt does not name the boundaries. MUST encode the boundaries as explicit `\u2297` MUST NOT lines in the dispatch prompt: which files NOT to touch, which adjacent issues are out of scope, which CHANGELOG/branch surfaces are off-limits, and a halt-on-deliverable-missing rule that surfaces the gap to the parent rather than improvising a fix. Explicit constraints are cheaper than retroactive rebasing or scope-creep cleanup.\n\n**Cross-references:** `skills/deft-directive-swarm/SKILL.md` Phase 6 Sub-Agent Role Separation (#727 primary encoding); `scripts/preflight_implementation.py` (#810 implementation gate); 2026-05-07 #884 closeout sub-agent (REST-only, comment + PATCH, halt-on-deliverable-missing pattern); 2026-05-07 #947 sibling implementation on second machine (shared-identity coordination via explicit CHANGELOG ownership disclaim)."
|
|
419
419
|
},
|
|
420
420
|
{
|
|
421
421
|
"id": "ghx-within-session-cache-vs-deft-cache-cross-session-persistence-2026-05",
|
|
@@ -428,7 +428,7 @@
|
|
|
428
428
|
"encoding"
|
|
429
429
|
],
|
|
430
430
|
"source": "#884 (ghx adoption) and #883 (deft-cache) both shipped at v0.26.0; #884 closeout 2026-05-07 surfaced confusion about whether the two layers are redundant.",
|
|
431
|
-
"body": "**Source:** #884 (ghx adoption) and #883 (deft-cache) both shipped at v0.26.0; #884 closeout 2026-05-07 surfaced confusion about whether the two layers are redundant.\n\n**1. ghx and deft-cache target orthogonal failure modes**\n\n`ghx` (brunoborges/ghx, adopted via #884) is a `gh` proxy that adds in-memory read cache + singleflight coalescing + auto-invalidation on mutations. State lives only for the life of the daemon; no persistence; no quarantine. It saves the same-process / multi-agent polling case (5 swarm agents calling `gh pr checks` on the same PR collapse to 1 API call). It does NOT save a single mutation's GraphQL cost, since mutations invalidate cache entries rather than consume them.\n\n`deft-cache` (designed in #883, completed at v0.26.0) is a cross-session on-disk cache + quarantine layer. Each entry is split into `raw.json` (immutable audit, never LLM-fed) and `content.md` (post-quarantine, LLM-safe). ETag refresh; mutation-triggered invalidation; versioned scanner with append-only `quarantine-audit.jsonl`. Saves the cross-session re-fetch cost AND provides a uniform security-quarantine surface for ingested content.\n\nThe two layers stack: `scm:*` tasks (#881)
|
|
431
|
+
"body": "**Source:** #884 (ghx adoption) and #883 (deft-cache) both shipped at v0.26.0; #884 closeout 2026-05-07 surfaced confusion about whether the two layers are redundant.\n\n**1. ghx and deft-cache target orthogonal failure modes**\n\n`ghx` (brunoborges/ghx, adopted via #884) is a `gh` proxy that adds in-memory read cache + singleflight coalescing + auto-invalidation on mutations. State lives only for the life of the daemon; no persistence; no quarantine. It saves the same-process / multi-agent polling case (5 swarm agents calling `gh pr checks` on the same PR collapse to 1 API call). It does NOT save a single mutation's GraphQL cost, since mutations invalidate cache entries rather than consume them.\n\n`deft-cache` (designed in #883, completed at v0.26.0) is a cross-session on-disk cache + quarantine layer. Each entry is split into `raw.json` (immutable audit, never LLM-fed) and `content.md` (post-quarantine, LLM-safe). ETag refresh; mutation-triggered invalidation; versioned scanner with append-only `quarantine-audit.jsonl`. Saves the cross-session re-fetch cost AND provides a uniform security-quarantine surface for ingested content.\n\nThe two layers stack: `scm:*` tasks (#881) → `ghx` (within-session dedup) → `cache:put` (cross-session persistence + quarantine) → consumers (`candidates.jsonl` from triage #845, wiki pages from #610, etc.). MUST NOT treat `ghx` as a substitute for deft-cache or vice versa — they share zero failure modes.\n\n**2. ghx does not save the rate-limit-during-mutation case**\n\nThe 2026-05-07 session surfaced the `graphql` bucket exhaustion failure mode for `gh issue create`. `ghx` would not have prevented it, because `ghx` caches reads and invalidates on writes — a single mutation is on the cost path of `ghx`, not the cache-hit path. The right reflex for graphql-bucket exhaustion is REST fallback (see `## gh CLI GraphQL Bucket Exhaustion + REST Fallback + UTF-8 Payload Pattern (2026-05)`), not `ghx` adoption. MUST treat `ghx` adoption as an optimization for the polling / read-heavy case (swarm monitoring, status checks, repeated `pr view` / `pr checks` / `issue view` calls), not a rate-limit panacea.\n\n**Cross-references:** #884 (ghx adoption — AGENTS.md prefer rule + `task setup` install + CI install pinned to `v1.5.1`); #883 (deft-cache design + completion at v0.26.0); #881 (`scm:*` task namespace, the consumer of both layers); existing `## gh CLI GraphQL Bucket Exhaustion + REST Fallback + UTF-8 Payload Pattern (2026-05)` (sibling lesson on the orthogonal mutation-cost failure mode); brunoborges/ghx (upstream)."
|
|
432
432
|
},
|
|
433
433
|
{
|
|
434
434
|
"id": "rest-fallback-module-surface-2026-05",
|
|
@@ -600,11 +600,11 @@
|
|
|
600
600
|
"scm"
|
|
601
601
|
],
|
|
602
602
|
"source": "Issue #2646 (absorbs #1417). Dogfood on Cursor + Windows PowerShell 2026-07-19 while filing/updating the issue.",
|
|
603
|
-
"body": "**Source:** Issue #2646 (absorbs #1417). On Windows PowerShell, agents fail when authoring multi-line git/gh payloads via bash heredocs, `<<<` redirection, inline multi-line `--body` flags, or multi-line PS here-strings in the agent command box. Host/agent shell wrappers can also rewrite shell-embedded commit/issue prose before PowerShell executes.\n\n**Failure modes:** (1) Bash heredoc / `<<<` under PowerShell -- parse abort before any gh call. (2) Long inline `gh issue create` / `gh pr create --body` -- argument splitting, angle-bracket parse errors, silent truncation (#1417). (3) Host wrapper injection into shell-embedded git/gh prose (Co-authored-by / Made-with fragments) corrupting PATCH payloads. (4) Partial fixes (escaping, backtick-n, PS here-strings) reintroduce #240 or #798 damage.\n\n**Rule:** never put multi-line markdown inline in a PowerShell agent command. Write a UTF-8 (no BOM) temp file in the OS temp directory via editor/Write/Node (outside the shell), then pass `git commit -F`, `gh --body-file`, or `gh api --input`. Verify posted bodies after PATCH when wrappers may have corrupted earlier attempts.\n\n**Canonical encoding (strongest-applicable layer):** rule body in `content/scm/github.md`
|
|
603
|
+
"body": "**Source:** Issue #2646 (absorbs #1417). On Windows PowerShell, agents fail when authoring multi-line git/gh payloads via bash heredocs, `<<<` redirection, inline multi-line `--body` flags, or multi-line PS here-strings in the agent command box. Host/agent shell wrappers can also rewrite shell-embedded commit/issue prose before PowerShell executes.\n\n**Failure modes:** (1) Bash heredoc / `<<<` under PowerShell -- parse abort before any gh call. (2) Long inline `gh issue create` / `gh pr create --body` -- argument splitting, angle-bracket parse errors, silent truncation (#1417). (3) Host wrapper injection into shell-embedded git/gh prose (Co-authored-by / Made-with fragments) corrupting PATCH payloads. (4) Partial fixes (escaping, backtick-n, PS here-strings) reintroduce #240 or #798 damage.\n\n**Rule:** never put multi-line markdown inline in a PowerShell agent command. Write a UTF-8 (no BOM) temp file in the OS temp directory via editor/Write/Node (outside the shell), then pass `git commit -F`, `gh --body-file`, or `gh api --input`. Verify posted bodies after PATCH when wrappers may have corrupted earlier attempts.\n\n**Canonical encoding (strongest-applicable layer):** rule body in `content/scm/github.md` § Windows PowerShell: safe multi-line git/gh bodies (#2646); agent pointer in `templates/agent-prompt-preamble.md` § 3.9 and `templates/agents-entry.md` Contextual guardrails lazy-load trigger.\n\n**Cross-references:** #240 (Warp here-string splitting), #798 (PS 5.1 encoding safe write path), #1417 (long gh --body quoting, closed duplicate), #2646."
|
|
604
604
|
},
|
|
605
605
|
{
|
|
606
606
|
"id": "release-check-failure-file-and-merge-2026-07",
|
|
607
|
-
"title": "Release Phase 1 check failure
|
|
607
|
+
"title": "Release Phase 1 check failure — file-and-merge, not inline hotfix (2026-07)",
|
|
608
608
|
"date": "2026-07",
|
|
609
609
|
"issue_refs": [
|
|
610
610
|
"#2859",
|
|
@@ -615,12 +615,12 @@
|
|
|
615
615
|
"release",
|
|
616
616
|
"documentation"
|
|
617
617
|
],
|
|
618
|
-
"source": "Issue #2859. During v0.86.0 Phase 1, task check failed on #2858-class hang; orchestrator led with inline hotfix / skip-ci instead of file
|
|
619
|
-
"body": "**Source:** Issue #2859 (recurrence during v0.86.0 cut; concrete hang #2858).\n\n**Failure mode:** Release Phase 1 `task check` / `ci:local` fails on a fixable defect. Agent offers inline hotfix, timeout tweaks, or untracked `--skip-ci` before filing a tracked issue and driving merge-ready.\n\n**Rule:** Pause the cut. File GitHub issue
|
|
618
|
+
"source": "Issue #2859. During v0.86.0 Phase 1, task check failed on #2858-class hang; orchestrator led with inline hotfix / skip-ci instead of file → PR → merge → resume.",
|
|
619
|
+
"body": "**Source:** Issue #2859 (recurrence during v0.86.0 cut; concrete hang #2858).\n\n**Failure mode:** Release Phase 1 `task check` / `ci:local` fails on a fixable defect. Agent offers inline hotfix, timeout tweaks, or untracked `--skip-ci` before filing a tracked issue and driving merge-ready.\n\n**Rule:** Pause the cut. File GitHub issue → xBRIEF → feature branch → PR → merge → confirm check green → resume Phase 1. `--allow-skip-ci=#N` stays incident-only with a tracked issue (Phase 4); never the first suggestion for a shippable bug.\n\n**AGENTS.md bulk rejected:** Always-pin expansion in AGENTS.md / agents-entry for this reminder was considered and rejected (#2859).\n\n**Canonical encoding:** `skills/deft-directive-release/SKILL.md` § Fixable check failure — file-and-merge before resume (#2859); `docs/RELEASING.md` § Fixable check failure during release."
|
|
620
620
|
},
|
|
621
621
|
{
|
|
622
622
|
"id": "release-coverage-debt-hatch-2026-07",
|
|
623
|
-
"title": "Release Step 5 coverage hairline
|
|
623
|
+
"title": "Release Step 5 coverage hairline — open-issue ledger hatch (2026-07)",
|
|
624
624
|
"date": "2026-07",
|
|
625
625
|
"issue_refs": [
|
|
626
626
|
"#2866",
|
|
@@ -633,7 +633,47 @@
|
|
|
633
633
|
"documentation"
|
|
634
634
|
],
|
|
635
635
|
"source": "Issue #2866. Hairline branch-coverage misses at release Step 5 repeatedly interrupted cuts; operator approved file-#N-then-hatch when no open debt issue exists.",
|
|
636
|
-
"body": "**Source:** Issue #2866 (operator-approved 2026-07-27).\n\n**Failure mode:** `task release` Step 5 fails on Vitest branch coverage below 85% (hairline miss). Agent treats it like a #2859 file-and-merge product defect or attempts consecutive `--allow-coverage-debt` soft-passes while a prior hatch debt issue is still open.\n\n**Rule (release-scoped only):** Hatch applies only when branches is the sole metric below 85%. Query open issues via `coverage-debt in:title,body` and `allow-coverage-debt in:body`; file new debt with title prefix `coverage-debt:` and both markers in body. If no open debt
|
|
636
|
+
"body": "**Source:** Issue #2866 (operator-approved 2026-07-27).\n\n**Failure mode:** `task release` Step 5 fails on Vitest branch coverage below 85% (hairline miss). Agent treats it like a #2859 file-and-merge product defect or attempts consecutive `--allow-coverage-debt` soft-passes while a prior hatch debt issue is still open.\n\n**Rule (release-scoped only):** Hatch applies only when branches is the sole metric below 85%. Query open issues via `coverage-debt in:title,body` and `allow-coverage-debt in:body`; file new debt with title prefix `coverage-debt:` and both markers in body. If no open debt → file `#N`, continue with `--allow-coverage-debt=#N` (PowerShell: `N` or `\"#N\"`). If open debt from prior hatch → restore all four metrics ≥ 85% before reusing hatch. Multi-metric misses, hangs, and failing tests stay under #2859 file-and-merge.\n\n**Canonical encoding:** `skills/deft-directive-release/SKILL.md` § Step 5 branch-coverage threshold — open-issue ledger hatch (#2866); `docs/RELEASING.md` § Coverage debt hatch during release."
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
"id": "through-merge-parent-must-dispatch-2026-08",
|
|
640
|
+
"title": "Through-merge / drive-to:merge-ready parent must dispatch worker (2026-08)",
|
|
641
|
+
"date": "2026-08",
|
|
642
|
+
"issue_refs": [
|
|
643
|
+
"#3032",
|
|
644
|
+
"#1880",
|
|
645
|
+
"#3027"
|
|
646
|
+
],
|
|
647
|
+
"tags": [
|
|
648
|
+
"agent-experience",
|
|
649
|
+
"harness",
|
|
650
|
+
"agent-safety",
|
|
651
|
+
"swarm",
|
|
652
|
+
"multi-agent"
|
|
653
|
+
],
|
|
654
|
+
"source": "Issue #3032. Observed on directive maintainer session for coverage-debt #3027: operator said take through merge; parent implemented partial product work instead of dispatching a drive-to:merge-ready worker. Operator re-stated use subagents and swarm skill even if just one.",
|
|
655
|
+
"body": "**Source:** Issue #3032. Recurrence on #3027 through-merge session before operator re-instruction.\n\n**Failure mode:** Operator intent equivalent to through merge / drive to merge / land-ship / drive-to:merge-ready is treated as parent-implements authorization. Parent edits product code, runs partial CI/coverage loops, stashes WIP, and never opens a merge-ready worker with worktree isolation. N=1 is misread as skip swarm.\n\n**Rule:** Parent MUST NOT implement as the leaf. Parent MUST dispatch (or re-dispatch) a worker with drive-to: merge-ready, worktree isolation when available, xBRIEF preflight, pre-pr + review-cycle, merge/scope:complete per #1880 Gap C. Even if cohort size is 1, use the swarm/solo-worker launch path.\n\n**Canonical encoding:** AGENTS.md / templates/agents-entry.md ## Through-merge worker dispatch (#3032); maintainer Multi-agent #1880 bullets; skills/deft-directive-swarm/references/core-phase-0.md Through-merge / N=1; core-ops anti-pattern; content/docs/skill-pin-policy.md Through-merge is false-negative sensitive; agents_entry_contract markers.\n\n**Cross-references:** #1880 Gap C/D, #2508 skill pin policy, #954 multi-agent, #3027 session recurrence, #3032."
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
"id": "empty-review-monitor-announce-single-lease-2026-08",
|
|
659
|
+
"title": "Empty review-monitor announce ≠ done + single lease (2026-08)",
|
|
660
|
+
"date": "2026-08",
|
|
661
|
+
"issue_refs": [
|
|
662
|
+
"#3044",
|
|
663
|
+
"#2874",
|
|
664
|
+
"#2876",
|
|
665
|
+
"#2814",
|
|
666
|
+
"#2943"
|
|
667
|
+
],
|
|
668
|
+
"tags": [
|
|
669
|
+
"review-cycle",
|
|
670
|
+
"harness:openclaw",
|
|
671
|
+
"agent-experience",
|
|
672
|
+
"operational",
|
|
673
|
+
"agent-safety"
|
|
674
|
+
],
|
|
675
|
+
"source": "Issue #3044. Recurrence: deftai/enterprize PR #43 babysit (2026-08-02) after #2874/#2876 OpenClaw Approach 1 spawn routing shipped.",
|
|
676
|
+
"body": "**Source:** Issue #3044. Recurrence: deftai/enterprize PR #43 babysit (2026-08-02) after #2874/#2876 OpenClaw Approach 1 spawn routing shipped.\n\n**Failure mode:** Parent correctly spawns Approach 1 review-monitor via sessions_spawn, but host settle arrives empty / (no output) / status unknown. Parent treats empty as terminal failure and spawns a **second** monitor with the same taskName while the first may still be running or only falsely settled. Dual <!-- deft:review-owner --> thrash; PR stays open; babysit looks owned twice.\n\n**Rule:** Empty announce is **FC04 residual**, not DONE/CLEAN/merge-ready. Parent MUST same-turn ground truth (gh pr view + checks + HEAD). One sticky review-owner lease; pre-spawn list active same-task / lease holder; forbid second monitor while prior running or last settle empty/unknown without terminal ground truth. Dead owner + open PR → one replacement with force lease takeover + lease update. Monitor handback MUST include non-empty STATUS/HEAD/CHECKS/MERGE. Prefer visible:true on Control UI.\n\n**Canonical encoding:** skills/deft-directive-review-cycle/SKILL.md Empty announce / Single lease / Required handback; skills/deft-directive-swarm/references/host-openclaw.md Babysit residual; templates/swarm-greptile-poller-prompt.md handback; templates/agent-prompt-preamble.md §11 thin pointer.\n\n**Cross-references:** #3044, #2874, #2876, #2814, #2943, FC04 / growth friction R1 + R10, enterprize PR #43.\n"
|
|
637
677
|
}
|
|
638
678
|
]
|
|
639
679
|
}
|