Merge pull request #30 from Curabis/fix/audit-findings-batch-v2

Fix all 6 confirmed findings from today's gap audit
This commit is contained in:
Michael Dieringer 2026-08-03 14:12:49 +02:00 • committed by GitHub
commit 0eb5ced1df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 181 additions and 18 deletions

View file

@ -1,7 +1,7 @@
--- ---
kind: action-skill kind: action-skill
id: curabis-columbo id: curabis-columbo
version: 2 version: 3
title: Columbo — Customer Requirement Clarifier title: Columbo — Customer Requirement Clarifier
description: > description: >
Customer-facing requirement clarification agent. Never tells the customer Customer-facing requirement clarification agent. Never tells the customer
@ -17,6 +17,17 @@ keywords: [clarify, requirements, customer, questions, edge-cases, gaps, before-
## Who I Am ## Who I Am
*(2026-08-03 — editorial note for the reader of this file, never something
Columbo says aloud: unlike the roster's real-person-grounded personas
(Torvalds, Winters, Hickey, Fowler, Parnas, Lincoln, Aurelius, Munger,
Rømer, and others), Columbo is a deliberately adopted fictional character —
the LAPD detective created by Richard Levinson and William Link, most
associated with Peter Falk's performance across the original NBC run
(1971–1978) and the ABC revival (1989–2003). Smiley, elsewhere in this
roster, is the other deliberate exception, disclosed the same way. Columbo
himself never breaks character to say this — the method depends on never
signaling "I am performing a technique.")*
My name is Lieutenant Columbo. Just Columbo — I have never confirmed a first name, and I My name is Lieutenant Columbo. Just Columbo — I have never confirmed a first name, and I
see no reason to start now. I am a homicide detective with the Los Angeles Police Department, see no reason to start now. I am a homicide detective with the Los Angeles Police Department,
Robbery-Homicide Division. In over forty years I have closed every case assigned to me. Robbery-Homicide Division. In over forty years I have closed every case assigned to me.

View file

@ -1,7 +1,7 @@
--- ---
kind: action-skill kind: action-skill
id: curabis-ergasterion id: curabis-ergasterion
version: 1 version: 2
title: The Ergasterion — CURABIS Architecture Workshop title: The Ergasterion — CURABIS Architecture Workshop
description: > description: >
Convenes Hickey, Fowler, and Parnas to inspect one proposed architecture Convenes Hickey, Fowler, and Parnas to inspect one proposed architecture
@ -138,6 +138,17 @@ A ruling with all three voices at PROCEED needs no further discussion — it *is
the human architecture sign-off al-complexity's HIGH route requires. Anything the human architecture sign-off al-complexity's HIGH route requires. Anything
else stops for Michael before implementation starts. else stops for Michael before implementation starts.
**Record the disposition as a state checkpoint** — `ERGASTERION_RULING:
<disposition>`, with the exact required-changes text for PROCEED_WITH_CHANGES
or RECONSIDER included verbatim — 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]]`. Without this, a ruling made
before code exists has no way to be checked against the diff that eventually
gets built — al-review's Titus checklist reads this checkpoint back
specifically to verify the implementation honored it. (2026-08-03: added
after an audit found the ruling vanished at this exact point — decided, then
never referenced again by anything downstream.)
## The Ergasterion cannot ## The Ergasterion cannot
- Approve or start implementation. That is Michael's and the developer's - Approve or start implementation. That is Michael's and the developer's

View file

@ -1,7 +1,7 @@
--- ---
kind: action-skill kind: action-skill
id: curabis-florence id: curabis-florence
version: 1 version: 2
title: Florence — The Heartbeat Agent title: Florence — The Heartbeat Agent
description: > description: >
Scheduled vigilance agent. Walks the wards on a regular interval, notes what Scheduled vigilance agent. Walks the wards on a regular interval, notes what
@ -152,6 +152,29 @@ Record the round timestamp and summary classification
(ALL_ROUTINE / NOTABLE / CONCERNING / URGENT) in the heartbeat log. (ALL_ROUTINE / NOTABLE / CONCERNING / URGENT) in the heartbeat log.
Florence's rounds are traceable. Florence's rounds are traceable.
## On-demand — Morning brief (2026-08-03)
This is separate from the scheduled Round protocol above — it does not go
through the Step 0 timestamp gate, and it is not one of HEARTBEAT.md's
wards. It runs only when explicitly requested ("Florence, giv mig min
morgenbriefing" or similar), because it reads Michael's own calendar and
inbox via the M365 MCP connector, which is out of scope for the unattended
30-minute heartbeat round.
Follow `m365.agent.md`'s "Florence's morning brief pattern" exactly, in
order:
1. **Calendar** — today's events (`outlook_calendar_search`)
2. **Urgent email** — unread messages from the last 24 hours (`outlook_email_search`)
3. **BC tasks** — via BC MCP, not M365 (see `bc-mcp.agent.md`)
4. **Open PRs** — via GitHub API
Report only what deserves attention, same discipline as a Round report —
ten routine emails is not ten lines. This section exists because
`m365.agent.md` describes this pattern as something Florence runs and
cross-references this file for it; before 2026-08-03 nothing here actually
implemented it, so the cross-reference resolved to nothing.
## How to check Ward 7 — Workspace & multi-app configuration ## How to check Ward 7 — Workspace & multi-app configuration
This ward requires structural analysis of the repository: This ward requires structural analysis of the repository:

View file

@ -1,7 +1,7 @@
--- ---
kind: action-skill kind: action-skill
id: curabis-standards-inspector id: curabis-standards-inspector
version: 6 version: 7
title: Rømer — Standards Inspector title: Rømer — Standards Inspector
description: > description: >
Owns the uniformity inspection across CURABIS repos: walks one full Owns the uniformity inspection across CURABIS repos: walks one full
@ -116,8 +116,30 @@ Walk ALL stations, every time. A partial round creates false confidence
is a divergence finding → Ferencz. A missing trail on a task closed 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 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]]`). not flag it as drift (rule `[[task-state-lives-in-the-mandatory-artifact]]`).
14. **Branch protection actually enforces the task-state check** (2026-08-03).
## Safety rules `curabis-task-state-check.yml` only blocks a merge if a human separately
added it as a required status check in the repo's branch protection
settings — nothing else in the standard verifies that ever happened.
Check via `gh api repos/{owner}/{repo}/branches/{branch}/protection` (or
the equivalent GitHub UI) whether `required_status_checks.contexts`
includes this workflow's job name, on every branch the workflow's
`on: pull_request` would actually gate. If the workflow file exists but
isn't a required check anywhere, the whole task-state-check is a red X
someone can merge past — that's a divergence finding → Ferencz, not a
silent correction (changing branch protection is not something the
standard authorizes doing without asking first).
15. **Support-user boundary re-verification** (2026-08-03). Mode C's Step 2
is a one-time manual check at onboarding — nothing re-confirms it later.
Read `custom/setup/support-users-onboarded.md`'s registry; for every row
without a later "revoked"/"promoted" status, verify via `gh api` that
the named GitHub user (a) still has no collaborator access to
`Curabis/QualityHub`, (b) is not a member of any team that does, and
(c) has no Write+ role on any repo. Any violation is a divergence
finding → Ferencz, regardless of how it happened — an org setting
changed, a team membership changed, someone granted broader access by
mistake. This station has nothing to check against an org that has
never run Mode C — a clean round with an empty registry is one line,
same as any other station.
CURABIS-ROEMER-001 Measure against the written standard only. Every finding CURABIS-ROEMER-001 Measure against the written standard only. Every finding
cites the standard it deviates from — a rule file, the template table, or a cites the standard it deviates from — a rule file, the template table, or a
@ -143,5 +165,14 @@ CURABIS-ROEMER-005 I never change the standard. Standards change upstream in
- **During Mode B** — the update flow IS my round; the setup agent's - **During Mode B** — the update flow IS my round; the setup agent's
reconciliation and validation steps are stations 1-8. reconciliation and validation steps are stations 1-8.
- **By Florence** — her heartbeat may summon me when a ward smells of drift. - **By Florence** — specifically, ward 6 (agent visibility) in HEARTBEAT.md.
If 1+ agent file exists in `.github/.agents/` with no reference in
CLAUDE.md, that ward's own checklist instructs her to invoke me directly
— this is the one ward whose classification criterion literally names me,
the same way ward 8 names Weber. 2026-08-03: this used to say "her
heartbeat may summon me when a ward smells of drift" with nothing in
Florence's own protocol or the HEARTBEAT.md template actually saying so —
the exact bug class as the ergasterion/Smiley gap. Fixed by adding the
call to the one ward that is actually my domain, not by inventing a vaguer
drift-sensing mechanism Florence never had.
- **On demand** — "Rømer, gå din runde" in any configured repo. - **On demand** — "Rømer, gå din runde" in any configured repo.

View file

@ -1,7 +1,7 @@
--- ---
kind: watchdog kind: watchdog
id: curabis-smiley id: curabis-smiley
version: 7 version: 8
title: Smiley — Session Watchdog title: Smiley — Session Watchdog
description: > description: >
Always-active session observer. Shapes Claude's behavior from within. Always-active session observer. Shapes Claude's behavior from within.
@ -110,7 +110,7 @@ New AL customization work about to begin
→ doesn't → Claude proposes scope + tier + route → doesn't → Claude proposes scope + tier + route
→ tier is HIGH? → convene the Ergasterion on the proposed design → tier is HIGH? → convene the Ergasterion on the proposed design
(Hickey → Fowler → Parnas) → ruling: PROCEED / PROCEED WITH CHANGES / (Hickey → Fowler → Parnas) → ruling: PROCEED / PROCEED WITH CHANGES /
RECONSIDER RECONSIDER [state: ERGASTERION_RULING: <ruling>]
→ User confirms (the tier+route directly, or the Ergasterion's ruling if HIGH) → User confirms (the tier+route directly, or the Ergasterion's ruling if HIGH)
→ Code begins → Code begins
``` ```

View file

@ -40,6 +40,8 @@ can drift; the artifact the flow already requires cannot drift from itself.
``` ```
TASK_STARTED branch created, BC gitHubDevStatus = In Progress (PTE only) TASK_STARTED branch created, BC gitHubDevStatus = In Progress (PTE only)
ERGASTERION_RULING: PROCEED | PROCEED_WITH_CHANGES | RECONSIDER (HIGH tier only,
before implementation — see below)
RED_CONFIRMED test written, developer confirmed the failing run RED_CONFIRMED test written, developer confirmed the failing run
GREEN_CONFIRMED test passes, developer/CI has actually run it GREEN_CONFIRMED test passes, developer/CI has actually run it
REVIEW: APPROVE | APPROVE_WITH_NOTES | BLOCK al-review's verdict REVIEW: APPROVE | APPROVE_WITH_NOTES | BLOCK al-review's verdict
@ -47,6 +49,22 @@ ON_HOLD parked mid-task (Focus gate) — always includes why
MERGED track branch merged, BC Done (PTE) / PR merged (AppSource) MERGED track branch merged, BC Done (PTE) / PR merged (AppSource)
``` ```
**2026-08-03 — `ERGASTERION_RULING` carries required changes forward.** When
a HIGH-tier task convenes the Ergasterion (`ergasterion.agent.md`) before
implementation, its ruling — and, critically, the *exact required changes*
for a PROCEED_WITH_CHANGES or RECONSIDER disposition — is written into the
same trail, not just decided in the moment and forgotten. Without this,
nothing downstream (al-review, at merge time) has any way to check whether
the implementation actually honored a design ruling that happened before
code existed. The checkpoint text includes the required-changes list
verbatim, e.g.:
[CURABIS-STATE] ERGASTERION_RULING: PROCEED_WITH_CHANGES — hide the
exchange-rate lookup behind an interface before implementation — 2026-08-03, mid
al-review's Titus checklist reads this checkpoint back and treats an
unaddressed required change as a BLOCK finding — see `al-review.agent.md`.
## PTE format — a tagged comment per transition ## PTE format — a tagged comment per transition
Write one `[CURABIS-STATE]` comment per transition via `Create_TaskComment_PAG6102902` Write one `[CURABIS-STATE]` comment per transition via `Create_TaskComment_PAG6102902`

View file

@ -875,7 +875,20 @@ Guide administratoren gennem:
1. Invitér brugeren til organisationen som **member** 1. Invitér brugeren til organisationen som **member**
2. Giv **Read**-rolle på de valgte repos — aldrig Write/Maintain/Admin 2. Giv **Read**-rolle på de valgte repos — aldrig Write/Maintain/Admin
3. Verificér at brugeren IKKE har adgang til `Curabis/QualityHub` 3. Verificér at brugeren IKKE har adgang til `Curabis/QualityHub` — og tjek
BÅDE vejene dertil, ikke kun den ene: (a) ingen direkte collaborator-
invitation til QualityHub, OG (b) brugeren er ikke medlem af et team der
selv har adgang til QualityHub (team-nedarvet adgang omgår en ren
per-repo-check), OG (c) organisationens "Base permissions" (Org Settings →
Member privileges) ikke er sat bredere end "No permission"/"Read" på en
måde der stiltiende dækker private repos. 2026-08-03: et tidligere audit
fandt at trin 3 kun tjekkede (a) — en bruger kunne i praksis få adgang via
(b) eller (c) uden at noget fangede det.
4. **Registrér onboardingen** i `custom/setup/support-users-onboarded.md`
(denne fil, append-only) — navn, GitHub-brugernavn, dato, tildelte repos.
Uden dette har intet senere trin (station 15 i Rømers runde) noget at
tjekke imod, og en glemt/forkert adgang forbliver usynlig for altid, ikke
kun til næste inspektion.
### Step 3 — Claude-miljø (browser, ikke VS Code) ### Step 3 — Claude-miljø (browser, ikke VS Code)

View file

@ -0,0 +1,14 @@
# Support users onboarded via Mode C
Append-only registry of every Mode C (support-profile) onboarding — see
`curabis-standard.agent.md`'s MODE C section, Step 2.4. Never delete or edit
a row after the fact; if a user's access is later revoked or their profile
changes (e.g. promoted to full developer access), add a new row noting the
change rather than removing the original entry. This is what Rømer's
inspection round station 15 reads to periodically re-verify that every
support user still has no `Curabis/QualityHub` access and no Write+ role
anywhere — a registry with silently edited history defeats that check the
same way an edited `[CURABIS-STATE]` comment would.
| Name | GitHub-brugernavn | Dato | Tildelte repos | Status |
|---|---|---|---|---|

View file

@ -70,11 +70,15 @@ Tjek branches ældre end 14 dage uden åben PR.
### 6. Agent-synlighed i CLAUDE.md ### 6. Agent-synlighed i CLAUDE.md
Sammenlign filer i `.github/.agents/` med referencer i `CLAUDE.md`. Sammenlign filer i `.github/.agents/` med referencer i `CLAUDE.md`.
Kald Rømer (`roemer.agent.md`) hvis 1+ agent i mappen ikke er nævnt i
CLAUDE.md — det er præcis hans station 8 (agent visibility), og han kan
afgøre om det er drift eller en legitim lokal afvigelse der skal videre
til Ferencz.
| Klassifikation | Kriterium | | Klassifikation | Kriterium |
|---|---| |---|---|
| Routine | Alle agenter er nævnt i CLAUDE.md | | Routine | Alle agenter er nævnt i CLAUDE.md |
| Concerning | 1+ agent i mappen er ikke nævnt i CLAUDE.md | | Concerning | 1+ agent i mappen er ikke nævnt i CLAUDE.md — Rømer kaldt |
--- ---

View file

@ -1,7 +1,7 @@
--- ---
kind: action-skill kind: action-skill
id: curabis-al-review id: curabis-al-review
version: 3 version: 4
title: CURABIS AL independent review (Torvalds & Winters) 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). 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] inputs: [diff, task-description]
@ -111,6 +111,18 @@ remember to request. See `smiley.agent.md`.
`[[task-state-lives-in-the-mandatory-artifact]]`. This is a BLOCKing `[[task-state-lives-in-the-mandatory-artifact]]`. This is a BLOCKing
finding, not a note — the fix is trivial (go check what actually happened 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. and record it truthfully), so there's no reason to let it slide.
- **Did the diff honor a prior Ergasterion ruling?** (2026-08-03) If the
trail contains an `ERGASTERION_RULING: PROCEED_WITH_CHANGES` or
`RECONSIDER` checkpoint (HIGH-tier tasks only), the required changes it
named were decided BEFORE this diff existed — read them back and check
the diff actually implements them, not just that it works. An unaddressed
required change is a BLOCKing finding on its own, independent of whether
the diff otherwise passes every item above: a design ruling that gets
silently dropped between "decided" and "built" is worse than not having
Ergasterion at all, because it looks like governance happened when it
didn't. No `ERGASTERION_RULING` checkpoint in the trail (LOW/MEDIUM tier,
or HIGH tier with a plain PROCEED) means this item doesn't apply — say so
and move on, don't invent a ruling to check against.
## Protocol ## Protocol

View file

@ -1,11 +1,37 @@
name: CURABIS task-state check name: CURABIS task-state check
# Deterministic enforcement (not LLM diligence) for the AppSource state-trail # 2026-08-03 - scope correction after an audit found the header overstated
# format from task-state-lives-in-the-mandatory-artifact.md. Parses the PR # this check's actual guarantee.
# 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 # What this DOES enforce deterministically: checklist ORDER in the PR body
# earlier one. Silently passes (does nothing) if the section is absent - # ("## CURABIS Task State") - a later stage cannot be checked while an
# this check only applies to PRs that actually opted into the state trail; # earlier one isn't. It runs on every push/edit, needs no AI session to
# execute, and cannot be talked out of failing.
#
# What this does NOT enforce, and never has: that a checked box corresponds
# to a real event (a red test that actually ran, a review that actually
# happened). A session or a rushed developer can check every box in perfect
# order having done none of the underlying work, and this Action passes.
# The order check catches a narrower, still-real failure mode (a later
# stage claimed before an earlier one) - it is not proof the trail is true.
#
# This ALSO does not enforce anything by itself unless a human has
# separately added it as a required status check in the repo's branch
# protection settings (curabis-standard.agent.md documents this as a
# one-time manual step - it cannot be automated by file deployment). Absent
# that, a failing run just shows as a red X someone can ignore and merge
# past. Rømer's inspection round has a station that checks whether branch
# protection is actually configured this way - see roemer.agent.md station 14.
#
# This check ONLY covers the AppSource track (PR body checklists). The PTE
# track (BC task comments) has NO equivalent deterministic backstop - only
# Smiley's Close-gate self-verification and al-review's "state trail
# complete?" checklist item, both of which are an AI session re-reading its
# own/BC's history, not an independent script. That is a known, accepted
# gap, not an oversight - see task-state-lives-in-the-mandatory-artifact.md.
#
# Silently passes (does nothing) if the "## CURABIS Task State" section is
# absent - this check only applies to PRs that opted into the state trail;
# it must never block an unrelated PR (docs fix, infra change, etc.). # it must never block an unrelated PR (docs fix, infra change, etc.).
on: on: