From a6b549761ac3bcc1bfb6abacbe64a420ad3b1db0 Mon Sep 17 00:00:00 2001 From: Vadim Zolotokrylin <1125014+zolotokrylin@users.noreply.github.com> Date: Wed, 5 Aug 2026 13:48:46 +0800 Subject: [PATCH 1/2] docs(rules): read a Problem and know what the business gains DEV-160 held the Problem statement to a business inability but left the Solution section unbounded, so it came back as a list of steps to perform. Cap both sections, require the Solution to open with the outcome, and hold PR descriptions to the same bar. Also scopes DEV-050 to rule files, so its 250-character cap is not confused with the new issue-level caps. --- docs/rules/DEV-050.md | 20 +++++++++------- docs/rules/DEV-160.md | 54 +++++++++++++++++++++++++++++++++++-------- docs/rules/DEV-360.md | 13 ++++++++--- docs/rules/README.md | 2 +- 4 files changed, 67 insertions(+), 22 deletions(-) diff --git a/docs/rules/DEV-050.md b/docs/rules/DEV-050.md index b013be9..4646df7 100644 --- a/docs/rules/DEV-050.md +++ b/docs/rules/DEV-050.md @@ -1,6 +1,6 @@ --- id: DEV-050 -title: "Keep the Problem Statement Short" +title: "Keep a Rule's Problem Statement Short" status: "active" enforcement: "manual" severity: "warning" @@ -9,18 +9,22 @@ depends_on: ["DEV-020"] ## Problem -A long Problem statement buries the point in qualifiers and restated context. A -reader cannot tell in one pass what is actually broken. +A long `## Problem` section in a rule file buries the point in qualifiers and +restated context. A reader cannot tell in one pass what is actually broken. ## Solution -A Problem earns its place only if a reader gets the break in one pass. Name the -single broken thing and stop. Motivation, context, alternatives, and any -restating of the title belong in the Solution, or nowhere. The character cap is -the forcing function: if you are over it, you are explaining, not stating. +A rule's Problem section earns its place only if a reader gets the break in one +pass. Name the single broken thing and stop. Motivation, context, alternatives, +and any restating of the title belong in the Solution, or nowhere. The character +cap is the forcing function: if you are over it, you are explaining, not +stating. + +This governs the rule file itself. For the `# Problem` section of a Problem +issue, see [DEV-160](./DEV-160.md), which sets its own cap. ### Acceptance Criteria -- [ ] The Problem paragraph is 250 characters or fewer +- [ ] The rule's Problem paragraph is 250 characters or fewer - [ ] It states only what is broken, with no background or justification - [ ] It does not restate the title diff --git a/docs/rules/DEV-160.md b/docs/rules/DEV-160.md index 1e2e50c..1c6bc8e 100644 --- a/docs/rules/DEV-160.md +++ b/docs/rules/DEV-160.md @@ -1,6 +1,6 @@ --- id: DEV-160 -title: "Write a Clear Problem Statement" +title: "Write a Problem Issue Stakeholders Can Act On" status: "active" enforcement: "manual" severity: "error" @@ -9,14 +9,24 @@ depends_on: ["DEV-150"] ## Problem -A Problem titled "missing balance API" or "pinned post needs upgrade" tells a -stakeholder nothing about what a user cannot do. Neither names the user or -business outcome being blocked, so neither can be prioritized. +A Problem titled "missing balance API" names no user and no outcome, so it +cannot be prioritized. Its Solution section drifts the same way, arriving as a +list of steps to perform, so a reviewer cannot tell what the business gains when +it merges. ## Solution -Write each Problem so a non-technical stakeholder understands it at a glance. If -you cannot state an inability, there is nothing to file: routine work an +Write each Problem so a non-technical stakeholder understands it at a glance. +The issue carries the pain and the direction. How to execute belongs to the pull +request that resolves it, per [DEV-170](./DEV-170.md). + +Both halves fail the same way. A title that names a missing artifact, and a +Solution that lists accounts to provision and READMEs to update, describe steps +performed rather than outcome delivered, which is what [DEV-440](./DEV-440.md) +says not to do. Length is what lets it happen: given room, the inability and the +outcome end up buried under execution detail. The caps below take the room away. + +If you cannot state an inability, there is nothing to file: routine work an experienced person would simply do is process, not a barrier, and belongs in the work itself. @@ -25,10 +35,17 @@ work itself. of the work, do it instead of filing it. 1. Title it `Problem: [statement]`, under 65 characters. 1. State what the user or business cannot do, in plain terms, not the solution's - technicalities. + technicalities. Keep the `# Problem` prose to 300 characters or fewer. +1. Open the `# Solution` section with one sentence naming what the user or + business can do once this merges. Any recommended direction follows that + sentence. Keep the Solution prose to 450 characters or fewer. 1. Open it as a sub-issue of the Goal and link the Goal in the description. -1. Give the body a `# Problem` section and a `# Solution` section describing the - recommended approach before work begins. + +The caps count prose only. Importance, urgency, and priority lines, the +references list, and links do not count against them. They are deliberately +tight: at this length there is no room for implementation steps, which is the +point. Detail that does not fit was never the statement, it was the execution, +and it belongs in the pull request. ```text Good: Problem: operators can't view their account balance @@ -37,17 +54,34 @@ Bad: Problem: CSV export missing (no actor, no action) Bad: Problem: pinned post needs upgrade (routine work, not a barrier) ``` +For the Solution's opening sentence: + +```text +Good: The platform stays reachable under attack and our servers cannot be + targeted directly. +Bad: Put both domains behind Cloudflare and accept origin traffic only from + Cloudflare. (a provisioning step, not an outcome) +``` + Filing routine work as Problems splits the work into micro-chunks. Each one adds an issue to track, a notification on every PR that touches it, and a status nobody updates, while tracking nothing that was ever blocked. Three open issues asking for a pinned post to be swapped are not three barriers; they are one unperformed task. +The character caps are machine-checkable and are stated as numbers so they can +be enforced automatically later. Until then, the reviewer checks them. + ### Acceptance Criteria - [ ] The title is `Problem: ...`, under 65 characters - [ ] It names a barrier that blocks the goal, not routine work a doer would simply perform - [ ] It states a user or business inability, not a solution technicality -- [ ] A non-technical stakeholder can understand it +- [ ] The Problem prose is 300 characters or fewer +- [ ] The Solution's first sentence states what the user or business can do once + this merges +- [ ] The Solution prose is 450 characters or fewer +- [ ] A non-technical stakeholder understands both sections without asking a + follow-up - [ ] It is a sub-issue of the Goal and has a Problem and a Solution section diff --git a/docs/rules/DEV-360.md b/docs/rules/DEV-360.md index 6fe2ab8..3af0d60 100644 --- a/docs/rules/DEV-360.md +++ b/docs/rules/DEV-360.md @@ -9,9 +9,10 @@ depends_on: ["DEV-170"] ## Problem -Work started without a draft PR, or a PR that never links its Problem, is -invisible: no one can see it is underway, and it does not close its Problem when -it merges. +Work with no draft PR, or a PR that never links its Problem, is invisible: no +one sees it is underway, and merging it does not close its Problem. A +description opening with edits performed hides it too: no reviewer can tell what +the business gains. ## Solution @@ -24,9 +25,15 @@ track progress and lets the merge close its Problem. 1. Link the PR to its Problem issue with a closing keyword (for example `Closes #123`), so merging the PR closes the Problem. 1. Assign yourself, so it is clear who owns it. +1. Open the description with one sentence naming what the user or business can + do once this merges, in the same plain terms the Problem uses per + [DEV-160](./DEV-160.md). The changes made follow that sentence, and are the + evidence for it, not a substitute. ### Acceptance Criteria - [ ] A draft PR is opened at the start of the work - [ ] It links its Problem issue with a closing keyword - [ ] The author is assigned to it +- [ ] The description opens with the outcome the merge delivers, not the list of + changes made diff --git a/docs/rules/README.md b/docs/rules/README.md index dcf5d3d..7882268 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -36,7 +36,7 @@ Solution, Spec. - [DEV-140](./DEV-140.md): give an ETA once the goal is clear - [DEV-150](./DEV-150.md): map every barrier blocking the goal - [DEV-155](./DEV-155.md): log a bottleneck as a Problem and design it out -- [DEV-160](./DEV-160.md): write a clear Problem statement +- [DEV-160](./DEV-160.md): write a Problem issue stakeholders can act on - [DEV-170](./DEV-170.md): deliver work as a pull request - [DEV-180](./DEV-180.md): keep the Spec as unimplemented behavior and graduate it From 13a48dae5efdd8864f8241c11a49b5525e27aac8 Mon Sep 17 00:00:00 2001 From: Vadim Zolotokrylin <1125014+zolotokrylin@users.noreply.github.com> Date: Wed, 5 Aug 2026 15:49:21 +0800 Subject: [PATCH 2/2] docs(rules): find the Problem length limit in one place The Problem cap was stated twice: 250 in DEV-050 for a rule file, 300 in DEV-160 for a Problem issue. Same principle, since a rule is a Problem whose barrier recurs on the ops side rather than in the product, so the two numbers were one fact with two homes. DEV-050 becomes canonical and governs any Problem statement at 250 chars. DEV-160 references it instead of restating a number. Its severity moves to error, matching what the rules audit already does: check-rules.mjs hardcodes PROBLEM_MAX = 250 against DEV-050 and blocks the push. The 450-char Solution cap stays in DEV-160. A rule's Solution carries method and reasoning; an issue's states an outcome. --- docs/rules/DEV-050.md | 26 ++++++++++++++------------ docs/rules/DEV-160.md | 15 ++++++++------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/docs/rules/DEV-050.md b/docs/rules/DEV-050.md index 4646df7..edb934c 100644 --- a/docs/rules/DEV-050.md +++ b/docs/rules/DEV-050.md @@ -1,30 +1,32 @@ --- id: DEV-050 -title: "Keep a Rule's Problem Statement Short" +title: "Keep the Problem Statement Short" status: "active" enforcement: "manual" -severity: "warning" +severity: "error" depends_on: ["DEV-020"] --- ## Problem -A long `## Problem` section in a rule file buries the point in qualifiers and -restated context. A reader cannot tell in one pass what is actually broken. +A long Problem statement buries the point in qualifiers and restated context. A +reader cannot tell in one pass what is actually broken. ## Solution -A rule's Problem section earns its place only if a reader gets the break in one -pass. Name the single broken thing and stop. Motivation, context, alternatives, -and any restating of the title belong in the Solution, or nowhere. The character -cap is the forcing function: if you are over it, you are explaining, not -stating. +A Problem earns its place only if a reader gets the break in one pass. Name the +single broken thing and stop. Motivation, context, alternatives, and any +restating of the title belong in the Solution, or nowhere. The character cap is +the forcing function: if you are over it, you are explaining, not stating. -This governs the rule file itself. For the `# Problem` section of a Problem -issue, see [DEV-160](./DEV-160.md), which sets its own cap. +This governs every Problem statement, whatever carries it: the `## Problem` +section of a rule file, and the `# Problem` section of a Problem issue written +per [DEV-160](./DEV-160.md). A rule is a Problem too; it is a rule only because +the barrier recurs on the ops side instead of in the product, which does not +change what its statement has to do. One cap, one place. ### Acceptance Criteria -- [ ] The rule's Problem paragraph is 250 characters or fewer +- [ ] The Problem paragraph is 250 characters or fewer - [ ] It states only what is broken, with no background or justification - [ ] It does not restate the title diff --git a/docs/rules/DEV-160.md b/docs/rules/DEV-160.md index 1c6bc8e..9b3d8d7 100644 --- a/docs/rules/DEV-160.md +++ b/docs/rules/DEV-160.md @@ -4,7 +4,7 @@ title: "Write a Problem Issue Stakeholders Can Act On" status: "active" enforcement: "manual" severity: "error" -depends_on: ["DEV-150"] +depends_on: ["DEV-150", "DEV-050"] --- ## Problem @@ -35,15 +35,15 @@ work itself. of the work, do it instead of filing it. 1. Title it `Problem: [statement]`, under 65 characters. 1. State what the user or business cannot do, in plain terms, not the solution's - technicalities. Keep the `# Problem` prose to 300 characters or fewer. + technicalities. Keep it within the Problem cap in [DEV-050](./DEV-050.md). 1. Open the `# Solution` section with one sentence naming what the user or business can do once this merges. Any recommended direction follows that sentence. Keep the Solution prose to 450 characters or fewer. 1. Open it as a sub-issue of the Goal and link the Goal in the description. -The caps count prose only. Importance, urgency, and priority lines, the +Both caps count prose only. Importance, urgency, and priority lines, the references list, and links do not count against them. They are deliberately -tight: at this length there is no room for implementation steps, which is the +tight: at that length there is no room for implementation steps, which is the point. Detail that does not fit was never the statement, it was the execution, and it belongs in the pull request. @@ -69,8 +69,9 @@ nobody updates, while tracking nothing that was ever blocked. Three open issues asking for a pinned post to be swapped are not three barriers; they are one unperformed task. -The character caps are machine-checkable and are stated as numbers so they can -be enforced automatically later. Until then, the reviewer checks them. +Both caps are machine-checkable, and the Problem cap already is: the rules audit +enforces [DEV-050](./DEV-050.md) on every rule file it checks. On issues the +reviewer checks them, until the bot does. ### Acceptance Criteria @@ -78,7 +79,7 @@ be enforced automatically later. Until then, the reviewer checks them. - [ ] It names a barrier that blocks the goal, not routine work a doer would simply perform - [ ] It states a user or business inability, not a solution technicality -- [ ] The Problem prose is 300 characters or fewer +- [ ] The Problem prose is within the cap in [DEV-050](./DEV-050.md) - [ ] The Solution's first sentence states what the user or business can do once this merges - [ ] The Solution prose is 450 characters or fewer