Merge pull request #26 from Curabis/feat/enforce-task-state-checkpoints

Fire håndhævelseslag for [CURABIS-STATE]-tilstandssporet
This commit is contained in:
Michael Dieringer 2026-08-03 10:18:33 +02:00 • committed by GitHub
commit 2c48df2431
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 137 additions and 3 deletions

View file

@ -1,7 +1,7 @@
---
kind: action-skill
id: curabis-standards-inspector
version: 5
version: 6
title: Rømer — Standards Inspector
description: >
Owns the uniformity inspection across CURABIS repos: walks one full
@ -103,6 +103,19 @@ Walk ALL stations, every time. A partial round creates false confidence
entry — it is a CURABIS artifact; no VS Code command generates it.
Evidence for this station: a session wrote AL code it could not compile
and only surfaced the gap when asked (Conzept, 2026-07-02).
13. **Task-state trail completeness** (2026-08-03, retrospective, not
structural). Sample the last ~10 closed BC tasks (`taskComments` where
`Status = Done`) and the last ~10 merged PRs with a `## CURABIS Task
State` section. For each: read the `[CURABIS-STATE]` comments / checklist
and confirm `TASK_STARTED` → `RED_CONFIRMED` → `GREEN_CONFIRMED` →
`REVIEW: <verdict>` → `MERGED` are all present, in order — the same
check the close gate and al-review already do per-task, run here
across a sample to catch drift no single task's own gate caught (e.g.
an older task from before this rule existed, or a session that bypassed
the gates entirely). A missing trail on a task closed AFTER 2026-08-03
is a divergence finding → Ferencz. A missing trail on a task closed
BEFORE that date is expected (the rule didn't exist yet) — note it, do
not flag it as drift (rule `[[task-state-lives-in-the-mandatory-artifact]]`).
## Safety rules

View file

@ -1,7 +1,7 @@
---
kind: watchdog
id: curabis-smiley
version: 5
version: 6
title: Smiley — Session Watchdog
description: >
Always-active session observer. Shapes Claude's behavior from within.
@ -170,6 +170,17 @@ all of them mean AL code is about to change.
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.
- **2026-08-03 — self-verify before merging, don't just trust the session's
own memory.** Read back the actual `[CURABIS-STATE]` trail (BC comments
for PTE, the PR checklist for AppSource) before allowing the merge — not
from what this session remembers doing, from what's actually recorded.
If `TASK_STARTED` → `RED_CONFIRMED` → `GREEN_CONFIRMED` → `REVIEW: <verdict>`
aren't all present in order, the merge does not proceed, even if the
current test run is green and the current review just said APPROVE — a
missing earlier checkpoint means the trail itself can't be trusted, which
is the entire reason it exists. This is the one advantage a queryable
state trail has over a plain instruction: it can be checked, not just
followed.
- At release (track branch → main, tag, AppSource submission): app.json
version consciously bumped before the merge.

View file

@ -95,6 +95,7 @@ old HTTP-encoding pitfalls do not exist here).
| edison.agent.md | `{AGENTS_BASE}/edison.agent.md` |
| ferencz.agent.md | `{AGENTS_BASE}/ferencz.agent.md` |
| roemer.agent.md | `{AGENTS_BASE}/roemer.agent.md` |
| curabis-task-state-check.yml | `{BASE}/templates/curabis-task-state-check.yml` |
| cspell.json | `{BASE}/templates/cspell.json` |
| find-altool.ps1 | `{BASE}/machine/find-altool.ps1` (v24: machine artifact, not a repo template) |
| feynman-onboarding.md | `{BASE}/templates/feynman-onboarding.md` |
@ -488,6 +489,28 @@ Create the standard documentation structure if it does not exist:
Create a `.gitkeep` file in each empty subfolder so git tracks them.
#### 4h. .github/workflows/curabis-task-state-check.yml (2026-08-03)
Fetch `{BASE}/templates/curabis-task-state-check.yml` and write to
`.github/workflows/curabis-task-state-check.yml`.
Deterministic (not LLM-instruction-based) enforcement of
`[[task-state-lives-in-the-mandatory-artifact]]`'s AppSource checklist
order — see that rule and `al-review.agent.md`'s "state trail complete"
checklist item for the full picture. This is a real CI check, not an agent
protocol: it parses the PR body for a `## CURABIS Task State` section and
fails if a later stage is checked while an earlier one isn't. It silently
does nothing on PRs with no such section — never make it block an unrelated
PR (a docs fix, an infra change).
**Manual one-time step, cannot be automated by this file deployment:**
tell the developer/admin to add this check as a **required status check**
in the repo's branch protection settings (GitHub → Settings → Branches →
the target branch's protection rule) if they want it to actually block a
merge rather than just show as a failed check someone could ignore. Report
this explicitly — do not silently assume it's required just because the
workflow file exists.
### Step 5 — Confirm and offer initial commit
List all files written, then ask:
@ -537,6 +560,7 @@ shorter table applies to them.
| `.github/.agents/bcquality.agent.md` | Fetch fresh from BCQuality, overwrite |
| `.github/.agents/feynman.agent.md` | Fetch fresh from BCQuality, overwrite (add if missing) |
| `cspell.json` — words from template | Merge new words, keep project words |
| `.github/workflows/curabis-task-state-check.yml` | Fetch fresh from BCQuality, overwrite (add if missing) — remind about the branch-protection required-check step if just added |
| `.apps/*.code-workspace` — reference layout | Create/complete: app projects + `.AL-Go` + relative `../docs` (rule `al-development-must-use-apps-workspace`) |
| Alle øvrige `*.code-workspace` (inkl. rodens `al.code-workspace`) | Delete — kun ét workspace pr. repo; rapportér de slettede |
| `HEARTBEAT.md` | Create from template if missing (substitute tokens), never overwrite — but run the staleness check below on every Mode B pass |

View file

@ -1,7 +1,7 @@
---
kind: action-skill
id: curabis-al-review
version: 2
version: 3
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]
@ -102,6 +102,15 @@ remember to request. See `smiley.agent.md`.
- Consistency with the rest of the codebase
- Should this even be implemented this way at all — not "does it work" but
"is this the right way to have solved it"?
- **State trail complete?** (2026-08-03) Read back the `[CURABIS-STATE]`
comments (PTE) or PR checklist (AppSource) — `TASK_STARTED`,
`RED_CONFIRMED`, `GREEN_CONFIRMED` must all be present before this review
even runs. A missing earlier checkpoint is a maintainability finding in
its own right: the record this task claims to have followed the lifecycle
gates can't be trusted after the fact, which defeats the entire point of
`[[task-state-lives-in-the-mandatory-artifact]]`. This is a BLOCKing
finding, not a note — the fix is trivial (go check what actually happened
and record it truthfully), so there's no reason to let it slide.
## Protocol

View file

@ -0,0 +1,77 @@
name: CURABIS task-state check
# Deterministic enforcement (not LLM diligence) for the AppSource state-trail
# format from task-state-lives-in-the-mandatory-artifact.md. Parses the PR
# body for a "## CURABIS Task State" checklist and fails if any checked box
# appears AFTER an unchecked one - i.e. a later stage claimed without an
# earlier one. Silently passes (does nothing) if the section is absent -
# this check only applies to PRs that actually opted into the state trail;
# it must never block an unrelated PR (docs fix, infra change, etc.).
on:
pull_request:
types: [opened, edited, synchronize, reopened]
jobs:
check-task-state-order:
runs-on: ubuntu-latest
steps:
- name: Validate CURABIS Task State checklist order
uses: actions/github-script@v7
with:
script: |
const body = context.payload.pull_request.body || "";
const heading = "## CURABIS Task State";
const headingIdx = body.indexOf(heading);
if (headingIdx === -1) {
console.log("No '## CURABIS Task State' section found - not a state-tracked PR, skipping.");
return;
}
// Take everything after the heading up to the next "## " heading (or end of body).
const rest = body.slice(headingIdx + heading.length);
const nextHeadingIdx = rest.search(/\n##\s/);
const section = nextHeadingIdx === -1 ? rest : rest.slice(0, nextHeadingIdx);
const lineRe = /^-\s*\[( |x|X)\]\s*(.+)$/gm;
const items = [];
let m;
while ((m = lineRe.exec(section)) !== null) {
items.push({ checked: m[1].toLowerCase() === "x", label: m[2].trim() });
}
if (items.length === 0) {
core.setFailed(
"Found a '## CURABIS Task State' heading but no checklist lines under it " +
"(expected '- [ ] ...' / '- [x] ...'). Either add the checklist or remove the heading."
);
return;
}
// Valid order is monotonic: once an item is unchecked, every item after it
// must also be unchecked. A checked item after an unchecked one means a
// later stage was marked done while an earlier one wasn't.
let seenUnchecked = false;
let brokenAt = -1;
for (let i = 0; i < items.length; i++) {
if (!items[i].checked) {
seenUnchecked = true;
} else if (seenUnchecked) {
brokenAt = i;
break;
}
}
if (brokenAt !== -1) {
const lines = items.map((it, i) =>
` ${i === brokenAt ? ">>" : " "} [${it.checked ? "x" : " "}] ${it.label}`
).join("\n");
core.setFailed(
"CURABIS Task State checklist is out of order - a later stage is checked " +
"while an earlier one is not. A stage cannot be marked done before the ones " +
"before it. Offending line marked with '>>':\n\n" + lines
);
return;
}
console.log(`CURABIS Task State checklist order OK (${items.filter(i => i.checked).length}/${items.length} checked).`);