Weekly Recap: August 21-28
The feature side of AL Runner’s week — real Cronus data via --test-data, breakpoint debugging back via --dap, per-test coverage for mutation testing — is already its own post
. This recap covers everything else that shipped in the same window: a CI incident and its fix in AL Runner, two real-world bugs in the Linux fast lane, a first update in two years for a browser extension, and a contribution to a project I don’t maintain.
AL Runner: a CI-skip bug that ate its own required check
The rest of this week’s AL Runner work went into CI and release tooling, and one bug in it is worth telling in detail. A PR that fixed the changelog generator (#2115) described GitHub’s [skip ci] directive in its own PR body, as prose explaining what the new workflow does with it. This repo squash-merges pull requests, and GitHub’s squash commit message is just the PR title followed by the PR body — so that prose line landed in the commit message on main, GitHub matched it as a real skip-ci directive, and it silently skipped the one required check plus the very workflow the PR had just added. The fix (#2119) adds a script that checks every PR title and body against every spelling GitHub honors before merge, with a documented way to write the directive out in a PR that genuinely needs to describe it without triggering it.
The changelog generator itself needed real fixes underneath that incident. It only recognized unscoped commit prefixes like fix:, but this repo writes almost all of its commits scoped (fix(startup):, feat(dap):), so those commits fell through and either got dumped into the changelog raw or classified wrong — a couple of scoped chore: commits had already leaked into a published release. The same PR added a workflow that keeps the changelog’s “Unreleased” section continuously up to date from the commit history instead of leaving it empty between releases, plus a follow-up fix so that workflow doesn’t race the release process and re-add commits a release just shipped.
A few smaller things round out the week. Dependency-need detection during provisioning moved from a hand-maintained list of app names to an actual dependency-graph walk, so the next Microsoft app with the same transitive-dependency shape gets caught automatically instead of needing its own fix. The release workflow stopped hardcoding “main” as its push target, a bug that would only surface after the full test matrix had already run. And several startup log lines were corrected to report what was actually searched or downloaded rather than a count taken before the real work happened.
Matching test coverage landed in the companion BusinessCentral.AL.Language.Tests
repo too, pinning the TestPage handler behavior AL Runner’s fixes depend on: modal pages with no source table, subpage parts on those hosts, page-global Code/Date controls, and GoToRecord on a precompiled page.
The Linux fast lane: two bugs that only showed up on real pipelines
Two bugs this week trace back to real pipelines breaking, not to something found in a test lab. The first: every shell loop in MsDyn365Bc.On.Linux (the reusable workflow behind AL-Go’s “Linux fast lane”) that split a list of app directories used spaces as the delimiter, which breaks the moment one of those directory names has a space in it — a completely ordinary thing to name a folder. The directory name got split into multiple bogus fragments, so the build looked for a compiled app under the wrong filename and failed with a “missing” error that pointed nowhere useful. Fixed by switching those lists to newline-separated instead of space-separated, since a directory name can’t contain a newline (#49). AL-Go’s fast lane builds this same kind of list dynamically when it hands directories off, so it needed a matching fix and a pin bump before any of this reached a real pipeline (#19, #20).
The second bug: a project with zero test apps configured — a normal setup if you’re only using the fast lane to compile, not to test — made the test step fail outright. The workflow treated “zero tests ran” as always meaning something broke, when it just as often means there was nothing to test in the first place. Fixed so a compile-only project can use the fast lane’s container without getting flagged as a failure for having no tests to run (#51).
Separately, Microsoft moved the actual AL compiler binary out of the Linux-specific compiler package sometime between two beta builds — that package now ships only the analyzer DLLs, and the real compiler lives in the OS-agnostic base package instead. That broke the BC 29 preview leg before BC even got a chance to boot, and it has nothing to do with anything in this project’s own code. Fixed with a fallback to the base package (#46), which AL-Go picked up with its own pin bump (#16). Two smaller fixes rode along: the NavUserPassword authentication check, which used to run unconditionally on every AL-Go pipeline whether or not a repo cared about testing authentication, is now opt-in (#48), and a flaky version of that same check — caused by BC’s own user cache lagging behind direct SQL changes in the test setup — now retries instead of failing intermittently. Worth calling out separately: philipp-mlr sent in PR #45, fixing two bugs behind a misleading SUPER-user error on ISV extension installs — a real outside contribution, not something I wrote. All of this reached AL-Go’s main branch by way of the usual pin bumps, and from there the automated deploy mirrored it downstream into AL-Go-PTE and AL-Go-AppSource without anyone touching those two repos directly.
OpenPageInspection: a first update in two years
OpenPageInspection
, the browser extension that gives you page/table IDs and quick BC shortcuts, hadn’t been touched since February 2024. This week it got rewritten from the ground up. It was a hand-written Chrome-only Manifest V3 extension; it’s now a WXT project that builds for Chromium browsers and Firefox from the same source, with each shortcut as its own module behind a shared interface so adding one is a single new file. Page Inspection now works by dispatching BC’s own Ctrl+Alt+F1 keydown — the same code path pressing the keys triggers — instead of posting an internal designer message that only ever worked once the designer had already loaded on that tab, and never worked on-premises at all since it depended on a CDN URL on-prem doesn’t serve. Shortcuts that open a BC page now ask the running client to open it in place through BC’s own navigation API, instead of reloading the tab and losing the session. There’s also a new optional button in BC’s own top bar for the same shortcuts, off by default so a normal install doesn’t need any extra permissions, plus unit tests and CI for publishing to the Firefox and Edge add-on stores.
A contribution to someone else’s project
I also contributed Azure CLI authentication to navapi
, a Business Central API client maintained by Jeremy Vyska — not my project, just a contribution. Until now every profile needed a client ID and client secret from an app registration. I added a second option: a profile can pull its token from az account get-access-token instead, so anyone who already runs az login can use navapi without creating or storing a secret at all. The tricky part turned out to be identity, not the token itself — az authenticates as whichever account is currently active, not whichever tenant you point it at, so a user signed into more than one identity would get an error that looks like “wrong tenant” but actually means “wrong identity.” I added identity pinning to fix that, and since nobody remembers which Azure accounts they have connected by name, the picker lists them instead of asking the user to type one from memory.
The maintainer’s review caught real problems and led to a second round of commits: a pinned identity needed to keep working for delegated admin and guest access, where az holds no account in the target tenant at all; the Linux keyring check was treating a non-persistent, in-memory keyring as if it were a real OS keychain, which would have silently dropped secrets; the az executable path needed quoting to run safely through a shell; and the VS Code extension had its own copy of the secret and identity logic that had to be brought in line with the CLI. I also refactored ProfileConfig.auth into a discriminated union so the two auth types can’t be mixed into an invalid state, and added a small feature to search endpoints by name or entity type along the way.