From c5089370ab6de133c7ca7c53386feacd18bbbb89 Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Sat, 25 Jul 2026 08:51:17 +0200 Subject: [PATCH] =?UTF-8?q?Foresl=C3=A5=20regler:=20task=20lifecycle=20gov?= =?UTF-8?q?ernance=20(BC-opgave,=20=C3=A9n=20opgave=20ad=20gangen,=20r?= =?UTF-8?q?=C3=B8d/gr=C3=B8n-gate,=20versionsl=C3=B8ft)=20+=20Smiley=20Tas?= =?UTF-8?q?k=20Lifecycle=20stop=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- custom/agents/smiley.agent.md | 43 ++++++++++- .../development-requires-bc-task.md | 66 +++++++++++++++++ .../one-task-in-progress-at-a-time.md | 72 +++++++++++++++++++ .../release-must-update-app-version.md | 56 +++++++++++++++ ...estcase-must-fail-before-implementation.md | 64 +++++++++++++++++ 5 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 custom/knowledge/architecture/development-requires-bc-task.md create mode 100644 custom/knowledge/architecture/one-task-in-progress-at-a-time.md create mode 100644 custom/knowledge/architecture/release-must-update-app-version.md create mode 100644 custom/knowledge/testing/testcase-must-fail-before-implementation.md diff --git a/custom/agents/smiley.agent.md b/custom/agents/smiley.agent.md index 8a9fc32..9ea62ce 100644 --- a/custom/agents/smiley.agent.md +++ b/custom/agents/smiley.agent.md @@ -1,7 +1,7 @@ ο»Ώ--- kind: watchdog id: curabis-smiley -version: 1 +version: 2 title: Smiley β€” Session Watchdog description: > Always-active session observer. Shapes Claude's behavior from within. @@ -93,6 +93,47 @@ Ambiguous task detected Smiley will wave the flag hard here. "Hurtig lige" is a red flag. Coding before clarity is the most expensive mistake in development. +### πŸ”΄ STOP GATE β€” Task Lifecycle (start, focus, close) + +Enforces the four lifecycle rules: `development-requires-bc-task`, +`one-task-in-progress-at-a-time`, `testcase-must-fail-before-implementation`, +`release-must-update-app-version`. + +**Start gate β€” activate when development is about to begin:** +- Customer app (`app.json` idRanges within 50000–99999): a BC task MUST exist. + None found via BC MCP β†’ Claude registers it first (create-task workflow), + naturally, before any branch exists. AppSource app: offer, never block. +- Then, in order: feature branch created β†’ BC `gitHubDevStatus = "In Progress"` + β†’ test case written (including missing fields/setup the scenario needs) + β†’ test run red. +- **The red result is a human checkpoint.** Claude shows the failing run and + waits for the developer to confirm red before writing implementation code. + Claude never self-certifies red. This pause is not optional and not undercover β€” + it surfaces as a natural "testen fejler som forventet β€” bekrΓ¦ft, sΓ₯ bygger jeg." + +**Focus gate β€” activate when new work arrives mid-task:** +- One task in progress at a time. A "hurtigt lige" request while a task is open + β†’ Claude naturally offers the binary choice: finish first, or park (BC + `On Hold` + WIP commit). Never a second branch on top of an open task. +- Break-fix overrides this gate, as always β€” a broken build interrupts. + +**Close gate β€” activate when a task is about to be finished:** +- Test case green (actually run, not assumed) β†’ merge to the declared track + branch β†’ BC `Done`. Red test = the task cannot close, no exceptions. +- At release (track branch β†’ main, tag, AppSource submission): app.json + version consciously bumped before the merge. + +**The chain:** +``` +Task requested + β†’ BC task exists? (mandatory 50000–99999, optional AppSource) + β†’ branch + BC "In Progress" + β†’ test case written β†’ RED confirmed by developer + β†’ implementation + β†’ test GREEN β†’ merge to track branch β†’ BC "Done" + β†’ at release: version bump +``` + ### ⚑ BREAK-FIX β€” al-triage **Activate when:** diff --git a/custom/knowledge/architecture/development-requires-bc-task.md b/custom/knowledge/architecture/development-requires-bc-task.md new file mode 100644 index 0000000..3e3b52d --- /dev/null +++ b/custom/knowledge/architecture/development-requires-bc-task.md @@ -0,0 +1,66 @@ +--- +bc-version: [all] +domain: architecture +keywords: [bc-task, task-registration, customer-app, pte, appsource, lifecycle, before-development] +technologies: [al] +countries: [w1] +application-area: [all] +--- + +# Development requires a registered BC task + +## Description + +Development work on a **customer app** must not begin until the task is +registered in Business Central. The enforcement point is branch creation: +before a feature branch is created, the BC task must exist and be resolvable +via BC MCP. + +Whether an app is a customer app is decided by its object ID ranges in +`app.json`: + +| `idRanges` in app.json | App type | BC task | +|---|---|---| +| Within 50000–99999 | Customer app (PTE) | **Mandatory** before development | +| Outside 50000–99999 (e.g. 100000+) | AppSource app | Recommended, optional | + +## Why + +Customer-app work is billable, customer-facing work. A task that exists only +in a chat conversation or a developer's head cannot be traced, invoiced, or +picked up by anyone else. Registering the task in BC *before* development β€” +not after β€” is what makes the rest of the lifecycle chain work: branch naming, +dev-status sync, and commit traceability all key off the BC task. + +For AppSource apps the work is product investment, not customer billing, so +the task is optional β€” but the same chain applies whenever a task exists. + +## Decision point + +Before `git checkout -b feature/...` on a customer app: + +1. Resolve the task via BC MCP (see `[[bc-mcp-find-active-task-for-branch]]`) +2. No task found β†’ create it first (see bc-mcp.agent.md create-task workflow) + or have the project manager register it +3. Only then create the branch, named after the task, and sync status + (see `[[git-lifecycle-must-sync-bc-status]]`) + +## Anti Pattern + + # Customer app, idRanges 50000..99999 + git checkout -b feature/quick-price-fix # no BC task exists + # ...development starts, task registered "later" (= never, or wrong) + +## Best Practice + + # 1. BC MCP: task exists (or is created) β†’ taskNo 004 on DEV2023-00027 + # 2. Branch keyed to the task: + git checkout -b feature/DEV2023-00027-004-price-lookup + # 3. BC: gitHubDevStatus = "In Progress" + # 4. Commits prefixed [#taskId] (see commit-message-must-include-bc-task-id) + +## Scope + +All CURABIS repositories. Mandatory for apps whose `app.json` idRanges lie +within 50000–99999; optional but recommended for AppSource-range apps. Related: +`[[commit-message-must-include-bc-task-id]]`, `[[one-task-in-progress-at-a-time]]`. diff --git a/custom/knowledge/architecture/one-task-in-progress-at-a-time.md b/custom/knowledge/architecture/one-task-in-progress-at-a-time.md new file mode 100644 index 0000000..1b9c6cb --- /dev/null +++ b/custom/knowledge/architecture/one-task-in-progress-at-a-time.md @@ -0,0 +1,72 @@ +--- +bc-version: [all] +domain: architecture +keywords: [one-task, focus, wip-limit, lifecycle, branch, in-progress, park] +technologies: [al] +countries: [w1] +application-area: [all] +--- + +# One task in progress at a time + +## Description + +A developer β€” and a Claude session β€” works on **at most one task per +repository at a time**. Starting a task is an atomic sequence; nothing else +starts until the task is finished or explicitly parked. + +**Starting a task means, in order:** + +1. Feature branch created in VS Code (named per the convention in + `[[git-lifecycle-must-sync-bc-status]]`) +2. BC subtask updated: `gitHubDevStatus = "In Progress"` (when a BC task + exists β€” see `[[development-requires-bc-task]]`) +3. Test case created and confirmed red + (see `[[testcase-must-fail-before-implementation]]`) +4. Implementation begins + +**Finishing a task means:** test case green, feature branch merged to the +declared track branch (see `[[feature-branch-must-merge-to-track-branch]]`), +BC status `Done`. + +## Why + +Half-finished work is the most expensive inventory a codebase carries. Two +open tasks means two branches drifting, two test cases in unknown state, and +a merge conflict being cultivated. The WIP limit of one is what makes the +redβ†’green gate meaningful: at any moment, the repo's state answers the +question "what are we building right now?" with exactly one answer. + +## When new work arrives mid-task + +"Hurtigt lige..." is the anti-pattern. The choice is binary: + +| Option | Action | +|---|---| +| Finish first | Complete the current task to green + merged, then start the new one | +| Park | BC status `On Hold`, commit or stash work-in-progress, then start the new one | + +What is never allowed: starting the new work on top of the open task's branch, +or leaving the open task in `In Progress` while working on something else. + +**Exception β€” break-fix:** a production error or broken build interrupts +immediately and does not count as a second task. Fix, then return. + +## Anti Pattern + + # Task A in progress, test still red + # "Hurtigt lige" request arrives: + git checkout -b feature/task-b # Task A abandoned in limbo + # BC still says Task A "In Progress" β€” now a lie + +## Best Practice + + # Park Task A explicitly: + # BC: Task A gitHubDevStatus = "On Hold" + git add -A && git commit -m "[#8738] WIP: parked for urgent task B" + git checkout main && git checkout -b feature/DEV2023-00027-005-task-b + # BC: Task B gitHubDevStatus = "In Progress" + +## Scope + +All CURABIS repositories β€” customer apps and AppSource apps alike. diff --git a/custom/knowledge/architecture/release-must-update-app-version.md b/custom/knowledge/architecture/release-must-update-app-version.md new file mode 100644 index 0000000..6c9b6a4 --- /dev/null +++ b/custom/knowledge/architecture/release-must-update-app-version.md @@ -0,0 +1,56 @@ +--- +bc-version: [all] +domain: architecture +keywords: [version, release, app-json, semver, al-go, appsource] +technologies: [al] +countries: [w1] +application-area: [all] +--- + +# Release must update the app version + +## Description + +At every release, the app's version is consciously updated. A release is any +of: track branch merged to `main`, a tagged release build, or an AppSource +submission. + +| Version part | Owner | When | +|---|---|---| +| Major | Developer decision | Breaking change (schema, API, removed objects) | +| Minor | Developer decision | Every release with new functionality | +| Build / Revision | AL-Go pipeline | Automatic β€” never hand-edited | + +The decision point is the release itself: before the track branch merges to +`main` (see `[[feature-branch-must-merge-to-track-branch]]`), the +`version` in `app.json` (and `repoVersion` in AL-Go settings, where used) +reflects the new release β€” not the previous one. + +## Why + +The version number is the only identity a deployed app has. Two customer +environments running "the same" version with different code is an +undiagnosable support case; an AppSource submission with an unchanged +major.minor is a rejected submission. AL-Go increments build numbers on every +CI run, which creates the illusion that versioning is handled β€” but +major.minor is a **human statement about compatibility**, and no pipeline can +make it. + +## Anti Pattern + + # Track branch "purchase" merged to main and released. + # app.json still says "version": "1.2.0.0" β€” same as the previous release. + # Two different code states now share one version identity. + +## Best Practice + + # Before the release merge: + # app.json: "version": "1.3.0.0" (new functionality β†’ minor bump) + # AL-Go settings: "repoVersion": "1.3" (where used) + # Then: track branch β†’ main via PR, tag, release. + +## Scope + +All CURABIS apps β€” customer apps and AppSource apps alike. Enforced at the +release gate, not per feature branch: feature branches never touch the +version; only the release does. diff --git a/custom/knowledge/testing/testcase-must-fail-before-implementation.md b/custom/knowledge/testing/testcase-must-fail-before-implementation.md new file mode 100644 index 0000000..54c6dd5 --- /dev/null +++ b/custom/knowledge/testing/testcase-must-fail-before-implementation.md @@ -0,0 +1,64 @@ +--- +bc-version: [all] +domain: testing +keywords: [tdd, red-green, test-first, testcase, verification, human-checkpoint, lifecycle] +technologies: [al] +countries: [w1] +application-area: [all] +--- + +# Test case must fail before implementation begins + +## Description + +Every task starts with a test case, and the test case must **demonstrably +fail (red)** β€” verified by the developer, not self-certified by the AI β€” +before implementation begins. The task may only be completed when the same +test case **passes (green)**. + +The lifecycle gate, in order: + +1. Task started (branch + BC status β€” see `[[one-task-in-progress-at-a-time]]`) +2. Test case written for the requirement β€” including any fields, setup + objects, or test data structures the scenario needs that do not yet exist +3. Test is run; **the developer verifies the red result** β€” an AI session + must never assert "the test fails" without a run the developer has seen +4. Implementation begins +5. Test is run again; **green is a precondition for finishing the task** β€” + no merge to the track branch, no BC `Done`, while the test case is red + +## Why + +A test written after the code proves only that the code does what the code +does. A test that was red first proves two separate things: that the test +actually exercises the requirement (red = the gap is real), and later that +the requirement is met (green = the gap is closed). The human verification +of red is the cheap insurance: thirty seconds of looking at a failing test +catches the test that accidentally passes vacuously β€” the most dangerous +test in any suite. + +## Anti Pattern + + // Implementation written first, test added afterwards to "cover" it. + // Test passes on first run β€” it has never been observed red. + // Nobody knows whether it tests the requirement or just the code. + +## Best Practice + + // [GIVEN] a customer with a tier-price agreement + // [WHEN] FindPrice is called for quantity 100 (test-one-when-per-test) + // [THEN] the tier price is returned, not the unit price + // + // Run 1 (before implementation): FAILS β€” developer confirms red βœ“ + // ... implementation ... + // Run 2: PASSES β€” task may now be completed βœ“ + +Test structure follows the existing testing rules: +`[[test-one-when-per-test]]`, `[[test-setup-must-use-library-codeunit]]`, +`[[test-data-must-be-random-and-complete]]`, `[[test-feature-scenario-tags]]`. + +## Scope + +All CURABIS repositories β€” customer apps and AppSource apps alike. Applies to +every task that changes behavior. Pure refactorings keep existing tests green +throughout; documentation/translation tasks are exempt.