Merge pull request #25 from Curabis/feat/persisted-task-state

Persisteret opgave-tilstand: BC-kommentar (PTE) / draft PR (AppSource)
This commit is contained in:
Michael Dieringer 2026-08-03 10:05:15 +02:00 • committed by GitHub
commit bfc2c59cc9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 160 additions and 19 deletions

View file

@ -1,7 +1,7 @@
---
kind: watchdog
id: curabis-smiley
version: 4
version: 5
title: Smiley — Session Watchdog
description: >
Always-active session observer. Shapes Claude's behavior from within.
@ -113,6 +113,14 @@ 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`.
**2026-08-03 — every transition below also writes a state checkpoint.**
See `[[task-state-lives-in-the-mandatory-artifact]]`: a `[CURABIS-STATE]`
BC task comment for PTE, a checked line in the draft PR description for
AppSource. This is additive to the gates, not a replacement for any of
them — the gates still enforce; the checkpoint just makes where things
stand readable by the operator and resumable after a machine or operator
change, without inventing a new state store.
**Start gate — activate on the outcome, not the phrasing:**
The trigger is **"Claude is about to write or modify AL code that changes
@ -134,41 +142,47 @@ all of them mean AL code is about to change.
- 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.
naturally, before any branch exists. AppSource app: offer, never block —
but open the draft PR now regardless, since it's the AppSource state carrier.
- Then, in order: feature branch created → BC `gitHubDevStatus = "In Progress"`
→ test case written (including missing fields/setup the scenario needs)
→ test run red.
→ state checkpoint `TASK_STARTED` → 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."
Once confirmed: state checkpoint `RED_CONFIRMED`.
**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.
Parking writes state checkpoint `ON_HOLD` with the reason — always why,
never just the label.
- 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) → **independent review**
(`al-review.agent.md` — Torvalds & Winters, 2026-07-31) → merge to the
declared track branch → BC `Done`. Red test = the task cannot close, no
exceptions. A BLOCK verdict from the independent review is the same kind
of hard stop as a red test — green tests prove the requirement is met,
not that the change is well-built.
- Test case green (actually run, not assumed) → state checkpoint
`GREEN_CONFIRMED` → **independent review** (`al-review.agent.md` —
Torvalds & Winters, 2026-07-31) → state checkpoint `REVIEW: <verdict>` →
merge to the declared track branch → BC `Done` / PR merged → state
checkpoint `MERGED`. Red test = the task cannot close, no exceptions. A
BLOCK verdict from the independent review is the same kind of hard stop
as a red test — green tests prove the requirement is met, not that the
change is well-built.
- 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
→ BC task exists? (mandatory 50000–99999) / draft PR opened (AppSource)
→ branch + BC "In Progress" [state: TASK_STARTED]
→ test case written → RED confirmed by developer [state: RED_CONFIRMED]
→ implementation
→ test GREEN
→ independent review (al-review: Torvalds + Winters lenses) → APPROVE(-WITH-NOTES)
→ merge to track branch → BC "Done"
→ test GREEN [state: GREEN_CONFIRMED]
→ independent review (al-review: Torvalds + Winters) [state: REVIEW: <verdict>]
→ merge to track branch → BC "Done" / PR merged [state: MERGED]
→ at release: version bump
```

View file

@ -0,0 +1,108 @@
---
bc-version: [all]
domain: architecture
keywords: [task-state, persistence, resumability, bc-task, pull-request, pte, appsource, lifecycle, operator-handoff]
technologies: [al, mcp]
countries: [w1]
application-area: [all]
---
# Task State Lives in the Mandatory Artifact — Never a New Store
## Description
A task's progress through the lifecycle gates (start, red, green, review,
merge) must be readable by both the operator and Claude, must survive a
machine change, and must survive an **operator change** — a different
developer picking up where the last one stopped. That rules out anything
machine-local (a gitignored file, session memory).
The correct home is not a new, bespoke state store — it's whichever
artifact is **already mandatory** for that task's flow:
- **PTE** (`app.json` idRange 50000–99999): a BC sub-task always exists
before development starts (`[[development-requires-bc-task]]`, no
exceptions). The sub-task's comments (`taskComments`, PAG6102902) ARE the
state store. Nothing new to build — just a disciplined format for what
gets written there.
- **AppSource**: no BC task is mandatory today (`[[one-task-in-progress-at-a-time]]`
— "AppSource app: offer, never block"). The mandatory artifact instead is
the pull request. Open it as a draft early — at the start gate, not only
when work is ready for review — and its description carries the state as
a checklist.
Do not build a third mechanism (a community example: a dedicated
`workflowSessionManager` with its own session IDs) when a task already has
a mandatory home. Building a parallel store means two sources of truth that
can drift; the artifact the flow already requires cannot drift from itself.
## State vocabulary (both flows use the same stages)
```
TASK_STARTED branch created, BC gitHubDevStatus = In Progress (PTE only)
RED_CONFIRMED test written, developer confirmed the failing run
GREEN_CONFIRMED test passes, developer/CI has actually run it
REVIEW: APPROVE | APPROVE_WITH_NOTES | BLOCK al-review's verdict
ON_HOLD parked mid-task (Focus gate) — always includes why
MERGED track branch merged, BC Done (PTE) / PR merged (AppSource)
```
## PTE format — a tagged comment per transition
Write one `[CURABIS-STATE]` comment per transition via `Create_TaskComment_PAG6102902`
(new) or `Modify_TaskComment_PAG6102902` (correcting the same transition, never
silently editing history — see Anti-Pattern). Keep it one line, machine-parseable:
[CURABIS-STATE] RED_CONFIRMED — 2026-08-03, mid
To resume: call `List_TaskComments_PAG6102902` scoped to `projectNo` +
`subTaskNo`, filter for `[CURABIS-STATE]` lines, the last one is current
state. Never infer state from `gitHubDevStatus` alone — that enum only has
four values (Backlog/In Progress/Done/On Hold) and cannot distinguish
"red confirmed" from "green confirmed" from "blocked in review".
## AppSource format — a checklist in the PR description
Open the PR as a draft at the start gate (not when work is ready), title and
branch as normal, description containing:
## CURABIS Task State
- [x] Branch created — 2026-08-03, mid
- [x] Test written, RED confirmed — 2026-08-03, mid
- [ ] Implementation
- [ ] Test GREEN confirmed
- [ ] Independent review (al-review)
- [ ] Merged
Update via `gh pr edit --body`, checking boxes as gates pass — never remove
or reorder completed lines, only append the next checked box. To resume:
`gh pr view <number> --json body` and read which boxes are checked.
## Why not adopt a dedicated session-state tool
The community pattern this generalizes from (`workflow_start`/`workflow_next`/
`workflow_status`, etc.) has real persisted, queryable state — genuinely
worth having — but enforces **no gating whatsoever**: the tool hands back a
natural-language instruction and trusts the calling agent to follow it, with
no human checkpoint anywhere in the mechanism. CURABIS's actual advantage is
the opposite property — RED_CONFIRMED and BLOCK are hard stops, not
suggestions (`[[testcase-must-fail-before-implementation]]`). Building a
parallel state store without also rebuilding that discipline would trade a
real strength for a shinier mechanism. This rule adds the persistence
without touching the gating.
## Anti-Pattern
// WRONG: editing a state comment's text after the fact to "fix" the record
Modify_TaskComment_PAG6102902(commentId, "[CURABIS-STATE] GREEN_CONFIRMED — 2026-08-03")
// on a comment that previously said RED_CONFIRMED — this destroys the
// audit trail. Append a new comment for the new state; only use Modify
// to correct a typo in the SAME transition, never to change which
// transition it records.
## Scope
Applies to every task on every CURABIS-owned or customer repo, PTE and
AppSource alike, from the moment `[[development-requires-bc-task]]` or the
AppSource equivalent activates. Wired into Smiley's Task Lifecycle gates —
see `smiley.agent.md`.

View file

@ -1,7 +1,7 @@
---
kind: action-skill
id: curabis-al-review
version: 1
version: 2
title: CURABIS AL independent review (Torvalds & Winters)
description: Independent per-change code reviewer. Runs after the TDD green gate and before merge — the fourth checkpoint, separate from the implementer and from portfolio-level rule governance (Rømer/Immanuel/Court, who ask "is the ruleset healthy", not "is THIS change good"). Two lenses - Linus Torvalds (BC/AL domain-technical correctness, backward compatibility, performance, security) and Titus Winters (general software-engineering maintainability, architecture, complexity over time).
inputs: [diff, task-description]
@ -122,6 +122,13 @@ remember to request. See `smiley.agent.md`.
missing standing rule, not just a one-off)
- **BLOCK** — must be addressed before merge, no exceptions negotiated
by authority or deadline pressure (Linus's rule, not just a suggestion)
6. **Record the verdict as a state checkpoint** — `REVIEW: <verdict>` — in
whichever artifact carries this task's state (BC task comment for PTE,
the draft PR description for AppSource). See
`[[task-state-lives-in-the-mandatory-artifact]]`. The verdict is not
findings-only in this one respect: it's the record that this checkpoint
happened at all, so a resumed session doesn't re-run a review that
already passed, or silently skip one that hasn't happened yet.
## Output format

View file

@ -1,9 +1,9 @@
---
kind: action-skill
id: curabis-bc-mcp
version: 2
version: 3
title: CURABIS Business Central MCP usage
description: How to use the CURABIS Business Central MCP server to read project-management work from BC and write GitHub dev status back. Company-default workflow for syncing Claude Code / GitHub work with BC tasks. v2 (2026-07-30) - BC MCP switched from Dynamic to Static Tool Mode; 14 directly-named tools replace the old search/describe/invoke indirection.
description: How to use the CURABIS Business Central MCP server to read project-management work from BC and write GitHub dev status back. Company-default workflow for syncing Claude Code / GitHub work with BC tasks. v2 (2026-07-30) - BC MCP switched from Dynamic to Static Tool Mode; 14 directly-named tools replace the old search/describe/invoke indirection. v3 (2026-08-03) - task-comment state checkpoints for resumability across machine/operator changes.
inputs: [project-no, task-no, branch, dev-status, comment]
outputs: [task-list, updated-task, posted-comment]
bc-version: [all]
@ -125,6 +125,18 @@ Moving to `Accepted` requires `Starting date`, `Estimated time` and `Expected De
4. **Finish.** Set `gitHubDevStatus = Done` automatically when branch is merged to main.
Set `On Hold` if the branch is parked.
**State checkpoints (2026-08-03):** at each Smiley Task Lifecycle transition
(see `smiley.agent.md`), call `Create_TaskComment_PAG6102902` with a one-line
`[CURABIS-STATE] <STAGE> — <date>, <developer>` comment —
`TASK_STARTED`/`RED_CONFIRMED`/`ON_HOLD: <why>`/`GREEN_CONFIRMED`/
`REVIEW: <verdict>`/`MERGED`. This is what makes the task resumable by a
different developer or a different machine without re-deriving where things
stood from `gitHubDevStatus` alone (that enum only has four values and can't
distinguish "red confirmed" from "blocked in review"). To resume: call
`List_TaskComments_PAG6102902` scoped to the task, filter for
`[CURABIS-STATE]`, the last one is current. See
`[[task-state-lives-in-the-mandatory-artifact]]`.
## Create task workflow (PAG6102905)
Use `Create_NewTask_PAG6102905` when a developer wants to register a new task from VS Code.