chore(prompts): rewrite friction guidance to be action-triggered#1305
Merged
Conversation
Live signal from prod 2026-05-10 PR #1303 (a4585987 implementation run): the agent encountered a textbook incidental papercut — `CASCADE_ORG_ID=mongrel` leaking from worker env into `tests/unit/cli/dashboard/config.test.ts`, worked around with `env -u CASCADE_ORG_ID npm test` — but reported it in the PR body instead of via `ReportFriction`. The plumbing was correct (capability scoped, gadget surfaced, sidecar env var injected, CLI installed); the prompt just wasn't recruiting the agent. The prior text framed reporting as a constraint, not a trigger: > When the ReportFriction tool is available, use it ONLY for > incidental papercuts in the environment, tooling, repository setup, > documentation, or developer workflow that make the work harder > than it should be. > > Do not report core task difficulty, expected debugging effort, > product ambiguity that belongs in the current work item, or issues > you can resolve directly as part of the assigned task. > > Keep working after reporting friction unless the issue blocks > progress. ... Three problems with this framing — verified by reading other agent prompt sections that DO recruit action well (`## Git`, `### Service Recovery`, `### Test Writing Protocol`): 1. "use it only for ..." reads as a SCOPING CONSTRAINT, not an action trigger. Agents default to "skip if uncertain." 2. Three negative clauses ("Do not report ...") with zero positive trigger language. Bias is toward not reporting. 3. "When the ReportFriction tool is available" hedge — but the guidance is only injected when the capability IS effective, so the conditional just creates agent doubt. New text drops all three. Action-trigger framing, "when in doubt, report" calibration, "better to over-report initial papercuts" license, non-blocking semantic preserved. No example list — would create pattern-match traps that narrow the use; the gadget's `category` enum (tooling | environment | permissions | dependency | test-failure | pm-data | scm-data | other) provides the categorical anchoring at invocation time. Tests updated: - `tests/unit/agents/shared/frictionGuidance.test.ts` — flipped from "expect old text" to assert the action-trigger framing + the intentional removal of the prior under-reporting clauses. - `tests/unit/backends/secretOrchestrator.test.ts:260` — flipped the prompt-assembly test's `toContain('incidental papercuts')` style assertions to the new content. No code wiring changes. The plumbing stays exactly as PR #1296/#1298/#1300 shipped it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 10, 2026
zbigniewsobiecki
added a commit
that referenced
this pull request
May 10, 2026
…dy, opt-in label PRs #1305 + #1311 closed the recruit→fire loop. Looking at the 5 reports filed live in prod 2026-05-10 (Trello cascade + Linear mongrel): - Title slugs read `frictionlow-...` because `[Friction][severity]` put brackets adjacent with no separator. Category — the most useful triage signal — wasn't in the title at all. - Body had 5 sections including `## What happened` (just repeats the summary already in the title), `## Classification` (now-redundant category/severity + the useful-but-buried whileDoing), and `## Timestamp` (the PM provider's native createdAt already shows this). - No PM-side label, so operators couldn't filter friction cards even though the alert flow already established the cascade-alert opt-in pattern via spec 019. Agents are already writing structured prose in `details` voluntarily (what they tried, error, workaround, impact). The win is in rendering, not in tightening the gadget input. Changes: - src/friction/format.ts: - Title: `[Friction · ${category} · ${severity}] ${summary}` — one bracket pair, dot separators, all three classification facets surfaced. Slugifies as `friction-tooling-low-...`. - Body has only two sections: `## Details` (agent prose verbatim, first because it's the most worth reading) and `## Run context` (bold-keyed bullets — Run / Work item / PR / Project / While doing). Italic `_Reported {iso}_` footer. Lines for absent fields drop entirely; no `_not provided_` placeholders for conditional context. - Compact bullets mirror src/integrations/alerting/_shared/format.ts. - src/pm/config.ts: add `getFrictionLabelId(project)` mirroring the `getAlertLabelId` opt-in pattern from spec 019. Reads `labels['cascade-friction']` (Trello) / `labels.cascadeFriction` (JIRA, Linear). Returns undefined when unconfigured — current prod cascade & ucho behavior is preserved. - src/integrations/pm/{jira,linear}/config-schema.ts: extend Zod schemas with the optional `cascadeFriction` label key. - src/friction/materialize.ts: pass `[labelId]` to createWorkItem when configured, `[]` otherwise. Back-compat — projects without the label configured continue to file unlabeled cards exactly as before. Tests: - tests/unit/friction/format.test.ts: re-pin title + body invariants (only `## Details` + `## Run context` headings; no `## What happened` / `## Classification` / `## Timestamp`), Run-context bullet shape (run link, work item with monospaced id, PR with branch + 12-char SHA, project key/repo/pmType, whileDoing). Pin absence of prior bracket-concat title form as a regression net. - tests/unit/friction/materialize.test.ts: add label-applied paths for Trello + JIRA + a label-absent regression net pinning `labels: []`. - tests/unit/pm/config-friction-slot.test.ts: cover getFrictionLabelId across providers + Zod schema acceptance for `labels.cascadeFriction`. Hand-rendered against a prod-shaped fixture confirms the new title slug (`friction-tooling-low-pm-add-checklist-...`) and dense body shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
a4585987) hit a textbook env friction (CASCADE_ORG_ID=mongrelleaking into a test, worked around withenv -u) but reported it in the PR body instead of viaReportFriction.filterTools,CASCADE_FRICTION_SIDECAR_PATHenv var injected, CLI installed in the container). Verified by re-runninggetToolManifests()+filterTools(integrationChecker=true)locally with the exact deployed code —ReportFrictionIS in the implementation agent's toolset.Why the old prompt under-recruited
New framing
Action-trigger first, with explicit calibration toward over-reporting:
No example list — would create pattern-match traps that narrow the use to the listed buckets. The gadget's
categoryenum (tooling | environment | permissions | dependency | test-failure | pm-data | scm-data | other) already provides categorical anchoring at invocation time, where the agent will see it.Test plan
npm run lintcleannpm run typecheckcleantests/unit/agents/shared/frictionGuidance.test.ts— asserts the new action-trigger content + intentionally pins the removal of the old under-reporting clauses (Do not report/only for incidental papercuts/When the ReportFriction tool is available) so a future revert would fail loudly.tests/unit/backends/secretOrchestrator.test.ts:260— prompt-assembly test flipped to the new content.cascade-tools pm report-frictioninvocation. With the new prompt, the agent that hits the next eligible papercut should fire it instead of writing a PR-body note.Out of scope
cascade runs llm-callsCLI,request: nullfor codex runs, no boot-time[FrictionGadget]log, silent drainer on empty sidecar) — those still stand and would let passive monitoring distinguish "wired but unused" without waiting for a real invocation. Worth a follow-up but separate from the prompt-effectiveness fix.statuses.frictionon the ucho project (currently unconfigured — Linear-based reports wouldqueued_slot_missing). Operator config, not a code change.🤖 Generated with Claude Code