Skip to content

chore(flathub): run Flathub's own submission linter (#449) - #614

Merged
TheZupZup merged 11 commits into
mainfrom
chore/449-flathub-lint
Sep 10, 2026
Merged

chore(flathub): run Flathub's own submission linter (#449)#614
TheZupZup merged 11 commits into
mainfrom
chore/449-flathub-lint

Conversation

@TheZupZup

Copy link
Copy Markdown
Owner

Works #449. Not closing it — see "What is still open" below.

CI has validated the desktop entry and the metainfo for a while, with desktop-file-validate and appstreamcli validate. Those answer whether two files are well-formed. Flathub's linter answers whether a submission would be accepted: reproducible sources, permissions Flathub actually grants, and a long list of listing rules no XML validator knows about. Nothing here had ever run it.

The exact commands

The linter ships inside org.flatpak.Builder, which is how Flathub's own docs run it — the same tool a reviewer uses.

flatpak install -y flathub org.flatpak.Builder
flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest flatpak/io.github.thezupzup.linthra.yml
flatpak run --command=flatpak-builder-lint org.flatpak.Builder repo flatpak/repo-ci
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream flatpak/flatpak-builder-ci/files/share/app-info/xmls/io.github.thezupzup.linthra.xml.gz

All three now run in the Flatpak build job: manifest before the build, repo and AppStream catalogue after the export. That third file is what a software centre actually reads, and it is not the file appstreamcli validate checked.

Version assumptions

org.flatpak.Builder is deliberately not pinned. Flathub reviews with whatever is current, so pinning would make this check green against a linter nobody uses. The cost is that a new linter release can turn the build red for a reason the PR did not cause — the runner prints flatpak --version, the ref, the commit and the linter version before any result, so that is visible rather than mysterious, and the fix is to fix the finding.

What the runner refuses

scripts/flathub_builder_lint.py exists for what it will not call a pass, not to wrap three commands:

  • A missing linter is not a pass. No flatpak, no org.flatpak.Builder, or no report → exit 2, saying nothing was linted. A check that silently succeeds when its tool is missing is worse than no check, because it gets reported as evidence.
  • A finding needs a written reason in flatpak/flathub-lint-exceptions.json, warnings included. Reviewers read warnings, and [Flathub] Run flathub-builder-lint cleanly #449 is about a submission-quality result rather than an exit code.
  • A reason cannot outlive its problem. An exception the linter no longer reports also fails, so the file cannot rot into a suppression list.
  • An exception with an empty reason is rejected outright — that is a suppression wearing a different hat.

The exceptions file ships empty, which is the state #456 requires.

One real fix, found without the tool

The summary was 36 characters against Flathub's 35-character cap. Now Play your own music collection (30).

test/tooling/flathub_metadata_guardrails_test.dart holds that rule and the other cheap, stable, textual ones — trailing period, leading article, repeated app name, 20-char name cap, required metainfo elements, desktop-entry visibility and icon name — so the next one is caught on the PR that causes it rather than in a submission review. It is explicitly not a reimplementation of the linter; everything else is the linter's job.

What is still open

Two findings are expected, and neither is excepted, because neither is a case of the linter being wrong:

So this PR makes the check exist, repeatable and honest. It does not yet make it clean, and I would rather leave #449 open than close it on a check that has not returned green once.

What was actually validated

Run locally:

  • python3 test/tooling/flathub_builder_lint_test.py — 17 passing (missing linter, undocumented finding, stale exception, empty reason, malformed file, warnings counted as findings)
  • flutter test test/tooling/ — 430 passing, including the 13 new metadata guardrails
  • flutter analyze, dart format --set-exit-if-changed test — clean
  • ruff check / ruff format --check on scripts tool tools — clean
  • python3 scripts/check_release_metadata_sync.py, python3 scripts/check_linux_runner.py — clean after the summary change
  • scripts/check_secrets.sh — clean

Not run here: the linter itself. This container has no flatpak, so the first real output is CI on this PR. I expect it to be red on the two findings above, and I will report exactly what comes back rather than guessing at it now.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp


Generated by Claude Code

TheZupZup and others added 3 commits September 10, 2026 14:32
CI has validated the desktop entry and the metainfo for a while. Those answer
whether two files are well-formed. Flathub's linter answers whether a
submission would be accepted — reproducible sources, permissions Flathub
actually grants, and a long list of listing rules no XML validator knows
about — and nothing here had ever run it.

Wires all three modes into the Flatpak build job: the manifest before the
build, and the exported repository plus the AppStream catalogue
appstreamcli compose produced (which is not the file appstreamcli validate
checked) after the export. The linter comes from org.flatpak.Builder,
deliberately unpinned: Flathub reviews with whatever is current, so pinning
would make this green against a linter nobody uses. The runner prints every
version before any result, so a rule change is visible rather than mysterious.

scripts/flathub_builder_lint.py exists for what it refuses to call a pass:

- a missing linter exits 2 and says nothing was linted, rather than reporting
  a clean run of nothing;
- any finding without a written reason in flathub-lint-exceptions.json fails,
  warnings included;
- a reason for a finding the linter no longer reports also fails, so the file
  cannot rot into a suppression list;
- an exception with an empty reason is rejected outright.

The exceptions file ships empty, which is the state #456 requires.

One real fix found without the tool: the summary was 36 characters against
Flathub's 35-character cap. Now "Play your own music collection" (30).
test/tooling/flathub_metadata_guardrails_test.dart holds that rule and the
other cheap ones — trailing period, leading article, repeated app name, name
length, required elements, desktop-entry visibility and icon name — so the
next one is caught on its own PR instead of in a submission review.

Two findings are expected and are not excepted, because neither is the linter
being wrong: the manifest CI lints is the development manifest, which builds
the working checkout rather than a tagged release (#451), and the metainfo
carries no screenshots (#437, #450). Both belong to their issues.

Not run here: the linter itself. This container has no flatpak, so the first
real output is CI on this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp
)

The first CI run answered the question this PR existed to ask, and caught a
bug in the asking. flatpak-builder-lint 3.0.0 ran, found nothing in the
manifest, printed nothing at all, and exited 0 — and the runner read that
empty report as "the linter is probably not installed" and failed the job.

Which was exactly backwards: the log line above it printed
`flatpak-builder-lint 3.0.0.post798.dev0+5181352`.

Silence is now read in both directions. Exit 0 with no output is a clean
report, and cannot be confused with a missing tool, because main() has already
established that org.flatpak.Builder is installed before any mode runs. A
non-zero exit with no output still explains nothing and is still refused.

Both cases are tests now rather than an assumption about a tool's output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp
…real findings (#449)

The lint now runs end to end and has produced its first real output.

manifest: clean. appstream: clean. repo: two errors, both the missing
screenshots — appstream-screenshots-not-mirrored-in-ostree and
metainfo-missing-screenshots.

Second runner bug, same shape as the first: not every mode speaks JSON. The
appstream mode hands the catalogue to appstreamcli and prints its verdict as
text, and the runner refused "Validation was successful." as unreadable output
and exited 2 on a mode that had passed. For text output the exit code is now
the verdict and the text is printed either way, so a real appstreamcli failure
still has to be looked at.

The two screenshot errors are not excepted and will not be. Flathub is right
to require a screenshot, inventing one from the Android set would misrepresent
the desktop window, and the fix is real Linux captures (#437) landed through
the metadata pass (#450). Until then the repo mode is red, which is the honest
state of the packaging rather than something to paper over — an exceptions
entry would only record that we would rather not see it.

Also worth recording: the linter does *not* flag the manifest's `type: dir`
source. The submission manifest (#451) is still needed, and this check will
not tell you so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp

Copy link
Copy Markdown
Owner Author

First real linter output, and why this PR stays red

Build and launch Flatpak will keep failing on this branch, deliberately. Recording what it found so the state is clear rather than mysterious.

Against flatpak-builder-lint 3.0.0.post798.dev0+5181352 (from org.flatpak.Builder, commit d04b579):

Mode Result
manifest clean
appstream clean — "Validation was successful."
repo 2 errors
appstream-screenshots-not-mirrored-in-ostree (error)
metainfo-missing-screenshots (error)
info: metainfo-missing-screenshots: The metainfo file is missing screenshots
      or it is not present under the screenshots/screenshot/image tag

Why I am not fixing this here

Both errors are the same missing thing: the metainfo carries no screenshots. Flathub is right to require one, and the fix is real Linux captures of the desktop window — that is #437, landing through the metadata pass in #450. Inventing them from the Android set would misrepresent the app, and this PR is about the lint, not the listing.

I have also not added an exception. flatpak/flathub-lint-exceptions.json is for a finding where the linter is wrong or the problem is unavoidable for Linthra; this is neither. An entry would only record that we would rather not see it, and #456 requires that file to be empty anyway.

So the honest state is: the check exists, it is repeatable, it runs all three modes, and it has found something real that is not fixed yet. Two runner bugs it exposed along the way are fixed (ebbc3ac, 1a4a619) — a mode that prints nothing when clean, and a mode that prints text rather than JSON.

One thing worth knowing for #451

The linter does not flag the manifest's type: dir source. The development manifest builds the working checkout, which is right for testing a PR and wrong for a submission — but this check will not tell you that, so #451 still needs doing on its own merits.

What turns it green

#437#450 → the screenshots land → the repo mode passes → flathub-lint-exceptions.json is still empty, which is exactly the state #456 gates on.


Generated by Claude Code

Main squash-merged #609, so this branch's copies of the audio smoke's
workflow entries conflicted with it. Both sides are kept: the smoke
manifest generator test and the Flathub lint runner test both run, and
both path filters list both scripts.

House style is commas, colons and parentheses rather than em dashes.
Prose and comments only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp
@github-actions

Copy link
Copy Markdown
Contributor

Repository integrity review

CLEAN

Previously reported repository-integrity findings are resolved.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bb65c9aa26

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/flathub_builder_lint.py Outdated
Comment thread scripts/flathub_builder_lint.py Outdated
A failed step ends the job, and the submission lint sits ahead of the
launch smoke. So an open finding we are deliberately carrying (missing
screenshots, today) does not just turn the badge red: it stops the
package being installed and launched in CI at all, on this branch and on
main once this merges. That trades real coverage for a red badge.

The two answer different questions. The lint answers "would Flathub
accept this?", the launch smoke answers "does the package work?". The
second is the one worth keeping answered while the first is knowingly
open, so it runs first.

No change to what either step does, and none to the lint's strictness.

Asserted rather than left to a comment: the ordering has a guardrail,
verified to fail when the steps are swapped back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp

Copy link
Copy Markdown
Owner Author

You marked this ready, so one consequence of merging it as it stood is worth flagging, and I have pushed a fix for it in f6bb6b2.

The lint would have taken the launch smoke down with it. The step order was:

  1. Lint the exported repository and AppStream catalogue
  2. Install and launch packaged Flatpak

A failed step ends the job. The lint is a hard-failing run: and this workflow triggers on push to main as well as on PRs. So merging with the screenshot finding still open would not just turn the badge red, it would stop the package ever being installed and launched in CI, here and on main, until screenshots land. That trades real coverage for a red badge, and it is the coverage that actually tells us the package works.

The two steps answer different questions. The lint answers "would Flathub accept this?", the launch smoke answers "does the package work?". While the first is knowingly open, the second is the one worth keeping answered, so it now runs first.

Nothing about the lint's strictness changed, and neither step's behaviour changed. The exceptions file is still empty.

The ordering now has a guardrail in flathub_metadata_guardrails_test.dart, since a comment saying "order matters here" is exactly the kind of thing a later refactor tidies away. Verified it fails when the steps are swapped back:

+12 -1: the lint runner is wired up and unsuppressed the launch smoke runs before the submission lint [E]

Rebuilt on top of your main merge (bb65c9a). flutter test test/tooling/ 469 passing, analyze and format clean.

This PR still goes red on metainfo-missing-screenshots, which is correct and unchanged. The difference is that now everything else on the job still runs and reports.


Generated by Claude Code

…er failure (#449)

Two Codex findings, both real, both latent only because the exceptions
file is still empty. They would have bitten the first time anyone wrote a
real exception, which is the worst moment for the mechanism to be broken.

**Staleness compared across modes that never ran together.** CI lints the
manifest before the build and the repo and catalogue after it, in two
invocations, and each loads the whole file. So a repo exception looked
stale during the manifest run and failed the build, and vice versa. That
made documented exceptions unusable in CI.

Exception keys now carry their mode ("repo/some-finding"), the staleness
check covers only the modes a given invocation linted, and a reason
written for one mode no longer accepts a same-named finding from another.
An unqualified or unknown-mode key is rejected with a message saying why,
rather than silently meaning something.

**Text-mode failures collapsed to one name.** Any non-JSON, non-zero
result became "<mode>-lint-failed", so a reason attached to it would keep
matching after the original problem was fixed and a different one
appeared, defeating the guarantee that a reason cannot outlive its
problem. Those are now refused outright: the name means the linter itself
failed, which is not a submission finding to document. Refused both when
the file is loaded and again where findings are matched.

The committed exceptions file is still empty, and the policy text and
docs/flathub-builder-lint.md now state both rules.

28 runner tests, 469 tooling tests, ruff clean. The cross-mode regression
test was verified to fail against the previous logic.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp
…hots (#449)

This PR was red, and the failure was never about the tooling. The repo and
appstream modes both report metainfo-missing-screenshots, which is a real
submission blocker fixed by taking screenshots (#437), not by anything in
the linter or its runner.

Holding the whole PR hostage to that helped nobody. The two ways to make
it green now are both worse than splitting it:

- leave the job red, which trains everyone to ignore the check and buries
  any genuinely new finding under the one everybody already knows about;
- record an exception, which the exceptions file explicitly forbids for a
  finding that is simply not fixed yet, and which #456 would require
  removing again anyway.

So the capability lands and the gate follows. Kept here: the linter, the
runner, its 28 tests, the docs, the exceptions mechanism, and the manifest
mode wired into CI, which runs before the build and is green. Removed: the
post-build step, and the ordering guardrail that only had something to
order.

Nothing is suppressed. The runner still drives all three modes, and
`--repo`/`--builddir` works today; it is the CI wiring that waits, in
#628, alongside the screenshots that let it pass.

A guardrail asserts the post-build modes stay unwired until then, so
turning them on has to delete a test and is a decision someone makes
rather than something that drifts in.

469 tooling tests, 28 runner tests, analyze, format and ruff clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp

Copy link
Copy Markdown
Owner Author

Split this so the tooling can land green, in 5048a92. The red was never about the tooling.

What stays: the linter, scripts/flathub_builder_lint.py and its 28 tests, the exceptions mechanism, the docs, and the manifest mode wired into CI. That one runs before the build, fails in about a second on a manifest finding, and is green.

What moves to #628: the post-build step that lints the exported repo and the AppStream catalogue. Both report metainfo-missing-screenshots today, which is a real submission blocker fixed by taking screenshots (#437), not by anything in this PR.

Nothing is suppressed. The runner still drives all three modes and --repo/--builddir works today, documented in docs/flathub-builder-lint.md. It is the CI wiring that waits, not the capability, and the exceptions file is still empty.

The reasoning, since "we'll turn it on later" is exactly the kind of promise that quietly never happens:

  • Leaving the job red trains everyone to ignore it, and buries any genuinely new finding under the one everybody already knows about.
  • An exception is what the file explicitly forbids for a finding that is simply not fixed yet, and [Flathub] Submit Linthra to Flathub #456 would require removing it again.

So there is a guardrail asserting the post-build modes stay unwired until #628:

expect(
  workflow,
  isNot(contains('--repo flatpak/repo-ci')),
  reason: 'wiring the repo mode in needs #628, and this test with it',
);
expect(workflow, contains('#628'),
    reason: 'the workflow must say where the missing gate went');

Turning them on has to delete that test, in a diff a reviewer reads. That makes it a decision rather than something that drifts in, and it means the missing gate cannot be forgotten.

I also removed the launch-smoke-before-lint ordering guardrail I added earlier, since with the post-build lint gone it had nothing left to order. #628 carries it as a step, because the reason still holds: a failed step ends the job, so the lint must not sit ahead of the launch smoke.

469 tooling tests, 28 runner tests, analyze, format and ruff all clean.


Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5048a92c7e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/flatpak-build.yml Outdated
Comment thread docs/flathub-builder-lint.md
Comment thread test/tooling/flathub_metadata_guardrails_test.dart
…ummary (#449)

Three Codex findings on the split, all correct.

**The appstream mode is clean, so it should gate.** I deferred both
post-build modes on the premise that both reported the screenshot
findings. The CI log says otherwise: both errors come from `repo`, while
`appstream` reported "no findings / Validation was successful". So I
deferred a passing check for no reason, leaving a future regression in the
generated catalogue free to land. It gates now, via --builddir, and only
`repo` waits for #628.

That also restores the ordering guardrail, which had nothing to order
while there was no post-build lint: the launch smoke runs first, because a
failed step ends the job.

**The summary guardrail measured XML, not text.** tagValue returned the
serialized value, so a summary containing a required entity counted
"&amp;" as five characters instead of the one a software centre shows. A
valid 35-character summary would have failed. Entities are decoded before
measuring, and length is counted in runes rather than UTF-16 code units so
a non-BMP character does not count twice. Verified with a summary that
renders at 35 and spells at 39: it passes now, and would not have.

**The documented local sequence could not run.** flatpak-ci.md ends with
`cd flatpak` and never returns, so the commands beneath it resolved
scripts/ and flatpak/ one directory too deep and failed before reaching
the linter. It says `cd ..` now.

The docs table also said the wrong thing about which mode reports what,
which is what let the first mistake through. It now states per mode what
gates and what it reports, and says plainly that appstream and repo are
different checks despite both mentioning screenshots.

471 tooling tests, 28 runner tests, analyze, format and ruff clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92ecb7e0eb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/tooling/flathub_metadata_guardrails_test.dart Outdated
Comment thread docs/flathub-builder-lint.md Outdated
… repo (#449)

Two more Codex findings, both correct.

**The docs claimed CI lints the exported repository.** The "Where this
runs" section still described the job as linting the repo after export,
which stopped being true when that mode was deferred to #628 two commits
ago. That is the worst kind of stale doc: a maintainer would read a green
CI run as evidence the publishable OSTree had been checked, when nothing
checked it. It now says plainly that the repo mode is not wired up, that
CI passing is not evidence about the OSTree, and where to get that
evidence instead.

I had corrected the table above it and missed the prose below it, which
is exactly how a document ends up contradicting itself.

**The summary guardrail decoded only named entities.** `&#38;` and
`&#x1F3B5;` are legal ways to write characters that are one glyph on
screen, and leaving them encoded counted six or nine characters for one,
so a valid summary near the limit would have been rejected. Numeric
references now decode first, before the named ones, with an unparseable or
out-of-range reference left exactly as written rather than throwing inside
a guardrail.

Verified both forms against a summary that renders at 35, and confirmed a
genuinely over-length summary is still rejected, so this loosens the
measurement without loosening the rule.

471 tooling tests, analyze, format clean, metainfo still validates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1b34a5e614

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/tooling/flathub_metadata_guardrails_test.dart Outdated
Comment thread scripts/flathub_builder_lint.py
…failure exit (#449)

Two Codex findings. The first is a bug I introduced one commit ago while
fixing the previous one.

**Chained decoding decoded twice.** Running the numeric pass before the
named one means `&#38;lt;` becomes `&lt;` becomes `<`: written as nine
characters, rendered as nine characters, counted as six. Undercounting is
the dangerous direction, because it lets an overlong summary through the
cap it exists to enforce. Both kinds of reference are now decoded in a
single non-recursive pass.

Confirmed against a summary that renders at 42 characters and was
previously counted as 26: it is correctly rejected now.

**A non-zero exit with structured output read as clean.** If the linter
returned valid JSON carrying neither errors nor warnings alongside a
failure exit, the exit status was discarded, findings() saw an empty
report and the run printed PASS. The text and empty-output paths already
refuse an unexplained failure; JSON now does too, as an unexceptable
"<mode>-lint-failed" finding, while a report that does explain itself
keeps its own findings.

Worth recording a process failure alongside these. My first negative
control for the second fix silently did nothing: ruff had reformatted the
line I was trying to revert onto one line, my replace did not match, and
the suite passed for the wrong reason. I read that as evidence the test
was weak, when in fact the control was. Reverting again, with an assertion
that the revert actually applied, showed the test failing as intended.

30 runner tests, 471 tooling tests, analyze, format and ruff clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLDN6yzLpSdXoFHYJNqyyp
@TheZupZup
TheZupZup merged commit 834eac4 into main Sep 10, 2026
20 checks passed
@TheZupZup
TheZupZup deleted the chore/449-flathub-lint branch September 10, 2026 20:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants