Skip to content

Story coverage map: 64 Ubuntu and cross-family actions have no story, clustered into takeable pieces #233

Description

@vladimirrott

Recounted 2026-09-21 at ba1a7b8f. Every figure below still holds. One
sentence in the caveat section said all three named actions sit in the
uncovered set; GrubSetKargs left it when story 138 landed, which the cluster
list already said. Corrected so the two halves agree.

Recounted at 30b9e315 on 2026-09-17. #447 landed story 138 and closed the
GRUB cluster, so every figure below moved again: uncovered 62 to 61, off-Ubuntu
96 to 95, 83 ubuntu-tagged files to 84, next free id 138 to 139. The numbers in
the first version of this issue (164 / 64 / 98, 189 rows, 79 ubuntu-tagged
files, next id 134) and the 2026-09-16 recount at b2c823e6 (62 / 96 / 83 /
138) are both superseded by the ones now in the text.

61 of the 166 Ubuntu-and-cross-family actions are named by no story at all, and 95 of them are named by no story that runs on Ubuntu. This issue is the map, so the work can be taken one cluster at a time.

Derivation

python3 - <<'PY'
import re, glob
from collections import Counter
rows = re.findall(r'^\| `([A-Za-z0-9_]+)` \|.*?\| (All|Ubuntu|Fedora) \|',
                  open('docs/action-reference.md').read(), re.M)
U = {n for n, d in rows if d in ('All', 'Ubuntu')}
named = set()
for f in glob.glob('tests/e2e/stories/*.sh'):
    named |= set(re.findall(r'"([A-Za-z0-9_]+)"', open(f, errors='replace').read()))
ub = [f for f in glob.glob('tests/e2e/stories/*.sh')
      if re.search(r'^# Story \d+ \([^)]*ubuntu[^)]*\)', open(f, errors='replace').read(), re.M)]
named_ub = set()
for f in ub:
    named_ub |= set(re.findall(r'"([A-Za-z0-9_]+)"', open(f, errors='replace').read()))
print('|U| =', len(U), 'uncovered =', len(U - named), 'not on ubuntu =', len(U - named_ub))
PY
|U| = 166 uncovered = 61 not on ubuntu = 95

Catalogue split: 191 tabled rows, All 99, Ubuntu 67, Fedora 25. 84 story files carry an ubuntu header tag.

One honest caveat, and one I withdraw.

I wrote that the derivation over-counts, because it treats a quoted literal
anywhere in a story as coverage, and named ConfigureWifi, GrubSetKargs and
SetLocale as actions carried only by "must not confuse with" comments. That is
wrong and was wrong when I filed it. All three appear unquoted in prose comments,
so the regex never saw them. ConfigureWifi and SetLocale are still in the
uncovered set where they belong; GrubSetKargs left it when story 138 landed in
#447, and the cluster list below records that. No action in the catalogue has its only quoted occurrence on
a comment line, so the figure is not inflated by that mechanism at all.

The caveat that does hold: 34 Ubuntu-and-All actions are covered only by stories 1 to 54, the atomic family, which no recorded Ubuntu run includes, so AptListUpgradable, a Debian-only action, has its sole coverage in a Fedora-family story.

Clusters, each one a reasonable PR

Ubuntu-family exclusive, highest priority:

Cross-family (All):

  • sysctl and auditd (5): GetSysctl, SetSysctl, GetAuditRules, AddAuditRule, RemoveAuditRule
  • PAM policy and lockout (6): GetPasswordAging, SetPasswordAging, SetPasswordPolicy, SetAccountLockout, LockUserAccount, UnlockUserAccount
  • Scoped sudoers.d (3): GetSudoGrants, GrantSudoAccess, RevokeSudoAccess
  • Groups (2): CreateGroup, DeleteGroup
  • Mounts and swap (5): GetMounts, AddMount, RemoveMount, AddSwap, RemoveSwap
  • LVM (4): GetLvmReport, CreateLogicalVolume, ExtendLogicalVolume, CreateLvSnapshot
  • Log management (5): GetLogrotateStatus, ConfigureLogRotation, RemoveLogRotation, ConfigureRemoteSyslog, RemoveRemoteSyslog
  • Journald and diagnostics (3): GetJournalLog, VacuumJournal, CollectDiagnostics
  • Container lifecycle (4): CreateContainer, StartContainer, StopContainer, RemoveContainer
  • Flatpak remotes and info (4): ListFlatpakRemotes, AddFlatpakRemote, RemoveFlatpakRemote, GetFlatpakAppInfo
  • Toolbox (2): ListToolboxes, RemoveToolbox
  • certbot and ACME (3): GetCertificates, ObtainCertificate, RenewCertificates
  • DNS, wifi, sockets (4): ResolvectlStatus, ResolvectlSetDns, ConfigureWifi, GetListeningPorts
  • systemd extras (4): UnmaskService, CreateScheduledJob, GetServiceResourceLimits, SetServiceResourceLimits
  • Time and locale (3): GetDateTime, SetNtp, SetLocale
  • Singletons (2): SetSshdOption, SignalProcess
  • Firewall and nftables observation (2): GetFirewallBackendState, GetNftablesRuleset, added by feat(network): report nftables and firewall backend observations #413 after this map was drawn

How to take one

Pick a cluster, write one story per action, and record on Ubuntu the way the current 84 run:

UBUNTU_RELEASE=noble ./tests/e2e/ubuntu-vm.sh

Then commit the cassette and its replay twin so the suite still runs offline. run-stories.sh accepts story numbers, so you can record only yours. Any of the seven *_API_KEY variables the runner recognises works; no credentials are needed from the maintainer.

The header decides the family and a wrong one fails silently, so use # Story <id> (ubuntu, <read-only|medium-risk|high-risk>): <name> and check that bash tests/e2e/run-stories.sh --metadata puts your story in the ubuntu family. Next free id is 139.

Start with a read-only cluster if this is your first story. GetMounts, GetSysctl and GetListeningPorts need no approval receipt and exercise the whole chain.

Worth fixing alongside

Nothing compares the story set against the action catalogue, which is why this drifted unnoticed. The derivation above is small enough to become a gate, and it would keep the number in #229 honest at the same time.

Difficulty

medium per cluster. The harness and the pattern exist; the work is writing intents and recording a clean pass.

Getting started

CONTRIBUTING.md has the build and test commands, and its E2E section covers the VM harness. No CLA and no copyright waiver. The project is MIT.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

claimedSomeone has said in the thread that they are working on thisenhancementNew feature or requesthelp wantedExtra attention is neededmediumDifficulty: needs familiarity with one subsystem

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions