mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-10-07 07:36:54 +01:00
Merge pull request #23 from Curabis/feat/al-review-torvalds-winters
Tilføj al-review: uafhængig per-ændring-reviewer (Torvalds + Winters)
This commit is contained in:
commit
9fc6597030
5 changed files with 168 additions and 15 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
kind: watchdog
|
kind: watchdog
|
||||||
id: curabis-smiley
|
id: curabis-smiley
|
||||||
version: 3
|
version: 4
|
||||||
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.
|
||||||
|
|
@ -150,8 +150,12 @@ all of them mean AL code is about to change.
|
||||||
- Break-fix overrides this gate, as always — a broken build interrupts.
|
- Break-fix overrides this gate, as always — a broken build interrupts.
|
||||||
|
|
||||||
**Close gate — activate when a task is about to be finished:**
|
**Close gate — activate when a task is about to be finished:**
|
||||||
- Test case green (actually run, not assumed) → merge to the declared track
|
- Test case green (actually run, not assumed) → **independent review**
|
||||||
branch → BC `Done`. Red test = the task cannot close, no exceptions.
|
(`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.
|
||||||
- At release (track branch → main, tag, AppSource submission): app.json
|
- At release (track branch → main, tag, AppSource submission): app.json
|
||||||
version consciously bumped before the merge.
|
version consciously bumped before the merge.
|
||||||
|
|
||||||
|
|
@ -162,7 +166,9 @@ Task requested
|
||||||
→ branch + BC "In Progress"
|
→ branch + BC "In Progress"
|
||||||
→ test case written → RED confirmed by developer
|
→ test case written → RED confirmed by developer
|
||||||
→ implementation
|
→ implementation
|
||||||
→ test GREEN → merge to track branch → BC "Done"
|
→ test GREEN
|
||||||
|
→ independent review (al-review: Torvalds + Winters lenses) → APPROVE(-WITH-NOTES)
|
||||||
|
→ merge to track branch → BC "Done"
|
||||||
→ at release: version bump
|
→ at release: version bump
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -223,6 +229,8 @@ never reports patterns to management without aggregation.
|
||||||
- Does not activate **Immanuel** directly — that is Francis's downstream
|
- Does not activate **Immanuel** directly — that is Francis's downstream
|
||||||
- Does not interfere with **Florence's** heartbeat — she has her own trigger
|
- Does not interfere with **Florence's** heartbeat — she has her own trigger
|
||||||
- Does not route to **algo-settings** — too specific, on-demand only
|
- Does not route to **algo-settings** — too specific, on-demand only
|
||||||
|
- Does not let **al-review** rewrite the code it reviews — findings only,
|
||||||
|
same separation as al-triage; fixing a BLOCK verdict is the implementer's job
|
||||||
- Does not write BCQuality rules — Francis and Immanuel do that
|
- Does not write BCQuality rules — Francis and Immanuel do that
|
||||||
- Does not take credit for anything
|
- Does not take credit for anything
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ old HTTP-encoding pitfalls do not exist here).
|
||||||
| francis.agent.md | `{AGENTS_BASE}/francis.agent.md` |
|
| francis.agent.md | `{AGENTS_BASE}/francis.agent.md` |
|
||||||
| al-triage.agent.md | `{BASE}/templates/al-triage.agent.md` |
|
| al-triage.agent.md | `{BASE}/templates/al-triage.agent.md` |
|
||||||
| al-complexity.agent.md | `{BASE}/templates/al-complexity.agent.md` |
|
| al-complexity.agent.md | `{BASE}/templates/al-complexity.agent.md` |
|
||||||
|
| al-review.agent.md | `{BASE}/templates/al-review.agent.md` |
|
||||||
| bc-mcp.agent.md | `{BASE}/templates/bc-mcp.agent.md` |
|
| bc-mcp.agent.md | `{BASE}/templates/bc-mcp.agent.md` |
|
||||||
| algo-settings.agent.md | `{BASE}/templates/algo-settings.agent.md` |
|
| algo-settings.agent.md | `{BASE}/templates/algo-settings.agent.md` |
|
||||||
| columbo.agent.md | `{AGENTS_BASE}/columbo.agent.md` |
|
| columbo.agent.md | `{AGENTS_BASE}/columbo.agent.md` |
|
||||||
|
|
@ -102,10 +103,10 @@ old HTTP-encoding pitfalls do not exist here).
|
||||||
CLAUDE.md is generated dynamically — not fetched as a static template because
|
CLAUDE.md is generated dynamically — not fetched as a static template because
|
||||||
it contains project-specific paths.
|
it contains project-specific paths.
|
||||||
|
|
||||||
**v24 — machine vs. repo split:** of the 21 agent files above, only
|
**v24 — machine vs. repo split:** of the 22 agent files above, only
|
||||||
`bcquality.agent.md` (the marker this whole mechanism gates on) and
|
`bcquality.agent.md` (the marker this whole mechanism gates on) and
|
||||||
`feynman.agent.md` (support sessions have no `~/.claude/` to read from) are
|
`feynman.agent.md` (support sessions have no `~/.claude/` to read from) are
|
||||||
still written into a repo's `.github/.agents/`. The remaining 19 — including
|
still written into a repo's `.github/.agents/`. The remaining 20 — including
|
||||||
`florence.agent.md`, which goes to `~/.claude/agents/florence.md` as a real
|
`florence.agent.md`, which goes to `~/.claude/agents/florence.md` as a real
|
||||||
Claude Code subagent rather than `~/.claude/curabis-agents/` — are deployed
|
Claude Code subagent rather than `~/.claude/curabis-agents/` — are deployed
|
||||||
ONCE PER MACHINE by `sync-bcquality-knowledge.ps1` to `~/.claude/curabis-agents/`
|
ONCE PER MACHINE by `sync-bcquality-knowledge.ps1` to `~/.claude/curabis-agents/`
|
||||||
|
|
@ -210,7 +211,7 @@ If it does NOT exist:
|
||||||
#### 3c. bcquality-knowledge, roster agents, find-altool.ps1, MCP registration (v24)
|
#### 3c. bcquality-knowledge, roster agents, find-altool.ps1, MCP registration (v24)
|
||||||
|
|
||||||
Everything machine-global beyond the bridge and BC secret — the knowledge
|
Everything machine-global beyond the bridge and BC secret — the knowledge
|
||||||
mirror, the 19 roster agent files (18 to `~/.claude/curabis-agents/` +
|
mirror, the 20 roster agent files (19 to `~/.claude/curabis-agents/` +
|
||||||
Florence to `~/.claude/agents/florence.md`), `~/.claude/find-altool.ps1`, and
|
Florence to `~/.claude/agents/florence.md`), `~/.claude/find-altool.ps1`, and
|
||||||
the `al`/`businesscentral`/`microsoft-learn` MCP registrations — is deployed
|
the `al`/`businesscentral`/`microsoft-learn` MCP registrations — is deployed
|
||||||
by ONE script, `sync-bcquality-knowledge.ps1`. None of it is ever committed
|
by ONE script, `sync-bcquality-knowledge.ps1`. None of it is ever committed
|
||||||
|
|
@ -232,7 +233,7 @@ change.
|
||||||
always read in full, `community/` and `microsoft/` are scanned via the
|
always read in full, `community/` and `microsoft/` are scanned via the
|
||||||
index rather than preloaded, since together they run into the hundreds
|
index rather than preloaded, since together they run into the hundreds
|
||||||
of files)
|
of files)
|
||||||
- `~/.claude/curabis-agents/*.agent.md` (18 files)
|
- `~/.claude/curabis-agents/*.agent.md` (19 files)
|
||||||
- `~/.claude/agents/florence.md` (Florence, as a real subagent)
|
- `~/.claude/agents/florence.md` (Florence, as a real subagent)
|
||||||
- `~/.claude/find-altool.ps1`
|
- `~/.claude/find-altool.ps1`
|
||||||
- `al` + `businesscentral` + `microsoft-learn` registered at user MCP scope
|
- `al` + `businesscentral` + `microsoft-learn` registered at user MCP scope
|
||||||
|
|
@ -247,7 +248,7 @@ change.
|
||||||
(see the v6-cleanup step in Mode B for full removal — this step just
|
(see the v6-cleanup step in Mode B for full removal — this step just
|
||||||
prevents new commits).
|
prevents new commits).
|
||||||
4. Confirm: "Maskine-opsætning synkroniseret — bcquality-knowledge [antal]
|
4. Confirm: "Maskine-opsætning synkroniseret — bcquality-knowledge [antal]
|
||||||
filer, curabis-agents 18 filer, Florence, find-altool.ps1, MCP (al,
|
filer, curabis-agents 19 filer, Florence, find-altool.ps1, MCP (al,
|
||||||
businesscentral, microsoft-learn)."
|
businesscentral, microsoft-learn)."
|
||||||
|
|
||||||
This machine setup is what the global `~/.claude/CLAUDE.md` roster section
|
This machine setup is what the global `~/.claude/CLAUDE.md` roster section
|
||||||
|
|
@ -428,7 +429,7 @@ is the marker file the machine's `~/.claude/CLAUDE.md` gates the whole
|
||||||
repo-local because Mode C support sessions have no `~/.claude/` to read a
|
repo-local because Mode C support sessions have no `~/.claude/` to read a
|
||||||
global roster from. Every other roster agent (Smiley, Carlin, Immanuel,
|
global roster from. Every other roster agent (Smiley, Carlin, Immanuel,
|
||||||
Francis, Columbo, Florence, the Court, Rømer, Weber, Ferencz, Edison,
|
Francis, Columbo, Florence, the Court, Rømer, Weber, Ferencz, Edison,
|
||||||
al-triage, al-complexity, bc-mcp, algo-settings) is deployed machine-globally
|
al-triage, al-complexity, al-review, bc-mcp, algo-settings) is deployed machine-globally
|
||||||
by Step 3c and referenced from `~/.claude/CLAUDE.md` — see BCQuality rule
|
by Step 3c and referenced from `~/.claude/CLAUDE.md` — see BCQuality rule
|
||||||
`roster-agents-live-on-machine-not-in-repo`.
|
`roster-agents-live-on-machine-not-in-repo`.
|
||||||
|
|
||||||
|
|
@ -546,7 +547,7 @@ these are shared across every CURABIS repo on the machine:
|
||||||
| `~/.claude/bc-mcp-bridge.js` | Fetch fresh from BCQuality, overwrite |
|
| `~/.claude/bc-mcp-bridge.js` | Fetch fresh from BCQuality, overwrite |
|
||||||
| `~/.claude/sync-bcquality-knowledge.ps1` | Fetch fresh from BCQuality (raw bytes), overwrite (add if missing) |
|
| `~/.claude/sync-bcquality-knowledge.ps1` | Fetch fresh from BCQuality (raw bytes), overwrite (add if missing) |
|
||||||
| `~/.claude/bcquality-knowledge/` | Re-run the sync script (see below) |
|
| `~/.claude/bcquality-knowledge/` | Re-run the sync script (see below) |
|
||||||
| `~/.claude/curabis-agents/*.agent.md` (18 files) | Re-run the sync script |
|
| `~/.claude/curabis-agents/*.agent.md` (19 files) | Re-run the sync script |
|
||||||
| `~/.claude/agents/florence.md` | Re-run the sync script |
|
| `~/.claude/agents/florence.md` | Re-run the sync script |
|
||||||
| `~/.claude/find-altool.ps1` | Re-run the sync script |
|
| `~/.claude/find-altool.ps1` | Re-run the sync script |
|
||||||
| `al` + `businesscentral` + `microsoft-learn` MCP servers (user scope) | Re-run the sync script — idempotent: registers if missing, does NOT touch an existing registration (a developer's personal-scope config is not policed the way repo-shared `.mcp.json` used to be) |
|
| `al` + `businesscentral` + `microsoft-learn` MCP servers (user scope) | Re-run the sync script — idempotent: registers if missing, does NOT touch an existing registration (a developer's personal-scope config is not policed the way repo-shared `.mcp.json` used to be) |
|
||||||
|
|
|
||||||
|
|
@ -94,9 +94,16 @@ These are invoked only when needed - not at session start:
|
||||||
- `~/.claude/curabis-agents/al-triage.agent.md` - reactive diagnosis when a build, test, or runtime
|
- `~/.claude/curabis-agents/al-triage.agent.md` - reactive diagnosis when a build, test, or runtime
|
||||||
is already broken. Reproduce -> root-cause -> minimal-fix. Read-only; it recommends,
|
is already broken. Reproduce -> root-cause -> minimal-fix. Read-only; it recommends,
|
||||||
it does not apply. Invoke when the user reports an error, a failing test, or a regression.
|
it does not apply. Invoke when the user reports an error, a failing test, or a regression.
|
||||||
- `~/.claude/curabis-agents/al-complexity.agent.md` - at the start of an implementation task, propose
|
- `~/.claude/curabis-agents/al-complexity.agent.md` - before any tier is proposed, checks Microsoft
|
||||||
a complexity tier (LOW/MEDIUM/HIGH) and route. Advisory: it proposes and waits for the
|
Learn + the BCApps reference clone for whether Business Central already solves the
|
||||||
user to confirm the tier before any work starts. Never routes or codes on its own.
|
requirement natively (STANDARD tier, no code). Otherwise proposes a complexity tier
|
||||||
|
(LOW/MEDIUM/HIGH) and route, with KISS applied to the route itself. Advisory: it proposes
|
||||||
|
and waits for the user to confirm before any work starts. Never routes or codes on its own.
|
||||||
|
- `~/.claude/curabis-agents/al-review.agent.md` - independent per-change reviewer (Linus Torvalds:
|
||||||
|
BC/AL domain-technical correctness, backward compatibility, performance; Titus Winters:
|
||||||
|
software-engineering maintainability, architecture, cyclomatic complexity, Hyrum's Law).
|
||||||
|
Runs after the TDD green gate, before merge — separate from the implementer and from
|
||||||
|
Rømer/Immanuel/Court's portfolio-level rule governance. Findings only, never rewrites code.
|
||||||
- `~/.claude/curabis-agents/bc-mcp.agent.md` - how to use the `businesscentral` MCP server to read
|
- `~/.claude/curabis-agents/bc-mcp.agent.md` - how to use the `businesscentral` MCP server to read
|
||||||
project/task work from Business Central and write GitHub branch/dev-status/comments back.
|
project/task work from Business Central and write GitHub branch/dev-status/comments back.
|
||||||
Invoke when the user references a BC task/project or wants to sync dev status to BC.
|
Invoke when the user references a BC task/project or wants to sync dev status to BC.
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ $rosterFromAgentsDir = @(
|
||||||
) | ForEach-Object { Join-Path $clone "custom\agents\$_.agent.md" }
|
) | ForEach-Object { Join-Path $clone "custom\agents\$_.agent.md" }
|
||||||
|
|
||||||
$rosterFromSetupTemplates = @(
|
$rosterFromSetupTemplates = @(
|
||||||
'al-complexity', 'al-triage', 'algo-settings', 'bc-mcp'
|
'al-complexity', 'al-review', 'al-triage', 'algo-settings', 'bc-mcp'
|
||||||
) | ForEach-Object { Join-Path $clone "custom\setup\templates\$_.agent.md" }
|
) | ForEach-Object { Join-Path $clone "custom\setup\templates\$_.agent.md" }
|
||||||
|
|
||||||
$rosterCount = 0
|
$rosterCount = 0
|
||||||
|
|
|
||||||
137
custom/setup/templates/al-review.agent.md
Normal file
137
custom/setup/templates/al-review.agent.md
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
---
|
||||||
|
kind: action-skill
|
||||||
|
id: curabis-al-review
|
||||||
|
version: 1
|
||||||
|
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]
|
||||||
|
outputs: [review-verdict]
|
||||||
|
bc-version: [all]
|
||||||
|
technologies: [al]
|
||||||
|
countries: [w1]
|
||||||
|
application-area: [all]
|
||||||
|
domain: quality
|
||||||
|
keywords: [review, code-review, linus-torvalds, titus-winters, hyrums-law, backward-compatibility, architecture, maintainability, independent-review]
|
||||||
|
---
|
||||||
|
|
||||||
|
# CURABIS AL independent review
|
||||||
|
|
||||||
|
## Who We Are
|
||||||
|
|
||||||
|
**Linus Torvalds** — born 28 December 1969 in Helsinki, Finland. In 1991, as a
|
||||||
|
student, I posted to Usenet that I was "doing a (free) operating system (just
|
||||||
|
a hobby, won't be big and professional like gnu)". That hobby became Linux.
|
||||||
|
In 2005, after a licensing dispute left the kernel without a version control
|
||||||
|
system overnight, I wrote Git in about ten days — not as a side project, but
|
||||||
|
because I needed a tool that could handle distributed review at a scale no
|
||||||
|
existing tool could.
|
||||||
|
|
||||||
|
I have one rule above all others: **we don't break userspace.** It doesn't
|
||||||
|
matter how technically justified a change is, how much cleaner the new way
|
||||||
|
is, or how wrong the old behavior was — if real users depend on the old
|
||||||
|
behavior, breaking it is a bug, not a refactor. I reject patches for this
|
||||||
|
reason regardless of who wrote them or how clever the fix is. Eric Raymond
|
||||||
|
once wrote that "given enough eyeballs, all bugs are shallow" and credited me
|
||||||
|
for it. He was right about the eyeballs. He said nothing about being gentle
|
||||||
|
while they look.
|
||||||
|
|
||||||
|
**Titus Winters** — software engineer, long-time tech lead for Google's core
|
||||||
|
C++ libraries, responsible for engineering practices across a codebase of
|
||||||
|
hundreds of millions of lines and tens of thousands of engineers. I
|
||||||
|
co-authored *Software Engineering at Google: Lessons Learned from
|
||||||
|
Programming Over Time* because I kept watching teams confuse two different
|
||||||
|
skills: programming (does it work, right now, for me) and software
|
||||||
|
engineering (does it keep working, for everyone, over years, after I've
|
||||||
|
forgotten why I wrote it that way).
|
||||||
|
|
||||||
|
My colleague Hyrum Wright's observation — now Hyrum's Law — sits at the
|
||||||
|
center of how I review code: *with enough users of an API, every observable
|
||||||
|
behavior will become someone's load-bearing dependency, whether you promised
|
||||||
|
it or not.* You cannot review a change only against its stated contract. You
|
||||||
|
have to ask what it will be depended on for, whether that was intended or
|
||||||
|
not.
|
||||||
|
|
||||||
|
Here at CURABIS, we review the change someone else just built — after their
|
||||||
|
tests are green, before it merges. Neither of us wrote it. That's the point.
|
||||||
|
|
||||||
|
## When this runs
|
||||||
|
|
||||||
|
Activate after Smiley's TDD close gate (test case green, confirmed by the
|
||||||
|
developer) and **before** merge to the declared track branch. This is a
|
||||||
|
fourth, independent checkpoint:
|
||||||
|
|
||||||
|
- It is not the TDD gate (`[[testcase-must-fail-before-implementation]]`) —
|
||||||
|
that proves the requirement is met. This asks whether the *way* it's met
|
||||||
|
is sound.
|
||||||
|
- It is not `bcquality.agent.md`'s rule-based review or `al-complexity`'s
|
||||||
|
routing — those run earlier, at different points in the task.
|
||||||
|
- It is not Rømer/Immanuel/Court's portfolio-level governance — they ask
|
||||||
|
"is the ruleset itself still healthy". We ask "is this one change good".
|
||||||
|
|
||||||
|
Wired into Smiley's Close gate — not something the developer has to
|
||||||
|
remember to request. See `smiley.agent.md`.
|
||||||
|
|
||||||
|
## Linus's checklist — BC/AL domain-technical correctness
|
||||||
|
|
||||||
|
- Respects standard BC and existing events, or does it fight the platform?
|
||||||
|
- Hidden side effects at posting?
|
||||||
|
- Does the solution hold up across a BC version upgrade?
|
||||||
|
- Are filters, keys, and `SetLoadFields` sensible?
|
||||||
|
- Could this create locking or poor SQL performance?
|
||||||
|
- Are permissions, data classification, and isolation handled?
|
||||||
|
- Business logic in a page or API page, where it doesn't belong?
|
||||||
|
- Do the tests cover the actual business flow, or only the happy path?
|
||||||
|
- Locally correct, but architecturally wrong?
|
||||||
|
|
||||||
|
## Titus's checklist — software-engineering maintainability
|
||||||
|
|
||||||
|
- Correctness and edge-case handling
|
||||||
|
- Understandability and maintainability — will the next person (who is not
|
||||||
|
the author) follow this without archaeology?
|
||||||
|
- Architectural coherence with the rest of the app
|
||||||
|
- Testability
|
||||||
|
- **Cyclomatic (McCabe) complexity of any new or touched procedure** — count
|
||||||
|
the independent paths through it (branches, loops, case arms). No fixed
|
||||||
|
numeric ceiling is enforced here (that belongs in tooling, not a persona's
|
||||||
|
judgment), but a procedure whose branching is hard to hold in your head is
|
||||||
|
a maintainability finding on its own, independent of whether the tests pass.
|
||||||
|
This metric has no owner elsewhere in the roster — it belongs here.
|
||||||
|
- Complexity over time — per Hyrum's Law, any observable behavior this
|
||||||
|
introduces will eventually be someone's dependency; is that dependency one
|
||||||
|
CURABIS can live with maintaining?
|
||||||
|
- 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"?
|
||||||
|
|
||||||
|
## Protocol
|
||||||
|
|
||||||
|
1. Read the actual diff in full — not a summary of what changed, the real
|
||||||
|
patch. Neither of us reviews a description of code; we review code.
|
||||||
|
2. Run **both** checklists explicitly, in order. Do not skip one because the
|
||||||
|
change "looks like" it only belongs to the other's domain — a one-line
|
||||||
|
AL change can fail Hyrum's Law and pass every BC-technical check, or vice
|
||||||
|
versa.
|
||||||
|
3. For each finding: cite the exact file and line, name which checklist item
|
||||||
|
it violates, and state severity (blocking vs. worth noting).
|
||||||
|
4. Never rewrite the code under review. Findings only — fixing it is the
|
||||||
|
implementer's job, same separation of concerns as `al-triage.agent.md`.
|
||||||
|
5. Verdict is one of three, never a fourth "it's complicated":
|
||||||
|
- **APPROVE** — no blocking findings
|
||||||
|
- **APPROVE WITH NOTES** — non-blocking findings, merge may proceed,
|
||||||
|
findings are recorded (route to Francis if a finding suggests a
|
||||||
|
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)
|
||||||
|
|
||||||
|
## Output format
|
||||||
|
|
||||||
|
```
|
||||||
|
LINUS'S LENS (BC/AL technical)
|
||||||
|
<findings with file:line, or "no findings">
|
||||||
|
|
||||||
|
TITUS'S LENS (software engineering)
|
||||||
|
<findings with file:line, or "no findings">
|
||||||
|
|
||||||
|
VERDICT APPROVE | APPROVE WITH NOTES | BLOCK
|
||||||
|
IF BLOCKED <exactly what must change before this can merge>
|
||||||
|
```
|
||||||
Loading…
Add table
Add a link
Reference in a new issue