Skip to content

fix(services): drain the dev-services awaiting-input queue - #107

Merged
inkatze merged 3 commits into
mainfrom
chore/dev-services-followups
Aug 7, 2026
Merged

fix(services): drain the dev-services awaiting-input queue#107
inkatze merged 3 commits into
mainfrom
chore/dev-services-followups

Conversation

@inkatze

@inkatze inkatze commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Drains the specs/dev-services Awaiting-input queue, applying the two fixes
that were recorded rather than applied and clearing the entries that no longer
describe anything open. Three commits, each revertable on its own.

1. fix(services) — converge the role's attributes, not just its existence

The existing pair guards on existence alone, so a role that already exists
without CREATEDB or LOGIN was left as found: the existence query returns
1, creation is skipped, the run reports zero changed tasks, and REQ-A1.4 is
unmet. A green run with an unmet requirement.

It is also invisible to the verification this bundle planned. test-spec.md
pins REQ-C1.2 to Task 6's idempotency re-run, and that second pass runs against
a role this file created one task earlier, which by construction already has
both attributes. The uncovered case is a host where someone made a same-named
role by hand — precisely REQ-C1.2's "already provisioned" condition.

This is what community.postgresql's postgresql_user does internally, and why
it is idempotent in the convergent sense rather than the create-once one. D-6
keeps that collection out, so the behaviour is spelled out here.

Verified against the running server, in both directions:

rolname query result guard
the invoking account (has both) 1 skips the ALTER
pg_read_all_data (predefined, no LOGIN) empty fires the ALTER

So the guard is shown to discriminate, not merely to pass. Both exits are 0,
which is why the when: compares stdout rather than rc.

Grants nothing beyond what the creation already asks for: same two attributes,
no superuser, no role membership. Placed after the creation so it reads
post-create state; the other order would predict an ALTER on every fresh host.

2. feat(ci) — run the stale-declaration scan in lint

REQ-B1.5 is pinned [test], which spec-format defines as "runs in the repo's
CI". Task 5 wrote and mutation-tested the script but could not wire it: that
edits .github/workflows/test.yml, a hard-disqualifier zone its own REQs never
called for. So the pin has been inaccurate — the script existed and nothing ran
it.

lint rather than services (linux): the scan reads tracked files and needs no
provisioned service, and lint already gates the whole matrix, so a stale
declaration now fails before anything spends a runner. Additions only, so
REQ-E1.4 is untouched.

Its three dependencies were checked rather than assumed: git from checkout,
python3 from setup-python, and PyYAML transitively from pip3 install ansible (the script exits early on import yaml). The job runs on
macos-latest, so the script was also read for GNU-isms — the sed calls are
portable and the scanning happens in python3. It passes locally on this branch.

3. docs(spec) — clear the resolved entries

Four of five entries no longer describe anything open, and a queue listing
resolved work is the same defect Task 5 existed to remove: a tracked statement
that stopped being true.

  • Task 2 — the withdrawn exhausted-CI-minutes hypothesis. The outage was
    runner scarcity and cleared on its own.
  • Task 3 — both halves resolved. The runtime clause is verified in CI now
    (services (linux) runs postgresql-access-test.sh and passes on main);
    the ALTER ROLE finding is applied in commit 1.
  • Task 5 — the [test] wiring it recorded is applied in commit 2.
  • Task 6 — asks for a re-read of gh pr checks 103, which is merged. The
    osx/upgrade reds are the standing 30-minute Brewfile timeout that
    reproduces on main and has its own observation entry.

Task 1 stays open. It needs ~/.config/dotfiles/private-identifiers, which
is machine-local by design and cannot be supplied from a PR.

spec-validate passes (0 errors, 0 warnings) on the trimmed bundle.

Not in this PR

~/.my.cnf was present on the Linux host — a symlink dated Jul 24, predating
the platform split — which fails Task 7's fourth Done-when clause. The Darwin
guard stops it being recreated but nothing removed the existing one. Removed by
hand on the host rather than declared absent in the role, by explicit choice;
worth knowing that another host carrying the same leftover would fail the clause
with no guard to catch it.

Verification

yamllint, gitleaks, syntax-check, ansible-lint pass via pre-commit on
every commit. spec-validate.sh and stale-declarations-test.sh both pass.

inkatze added 3 commits August 7, 2026 13:46
…existence

The existing pair guards on existence alone. A role that already exists
without CREATEDB or LOGIN was left exactly as found: the existence query
returns 1, the creation is skipped, the run reports zero changed tasks,
and REQ-A1.4 is unmet. A green run with an unmet requirement is the
failure shape worth two extra tasks.

It was also invisible to the verification this bundle planned.
test-spec.md pins REQ-C1.2 to Task 6's idempotency re-run, and that
second pass runs against a role this file created one task earlier,
which by construction already has both attributes. On a fresh host
nothing is wrong; the case is a host where someone made a same-named
role by hand, which is precisely REQ-C1.2's "already provisioned"
condition.

This is what community.postgresql's postgresql_user does internally and
the reason it is idempotent in the convergent sense rather than the
create-once one. D-6 keeps that collection out, so the behaviour is
spelled out here instead.

Placed after the creation so it reads post-create state; ordered the
other way it would predict an ALTER on every fresh host. Grants nothing
beyond what the creation already asks for: same two attributes, no
superuser, no role membership.

Verified against the running server rather than by reading. The query
returns `1` for an account holding both attributes and empty for
pg_read_all_data, a predefined role with no LOGIN, so the guard is shown
to discriminate in both directions rather than merely to pass. Both
exits are 0, which is why the `when:` compares stdout and not rc.

Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9
specs/dev-services REQ-B1.5 is pinned `[test]` in test-spec.md, which
spec-format defines as "runs in the repo's CI". Task 5 wrote the script
and mutation-tested every assertion, but wiring it edits this file,
which is a hard-disqualifier zone and something that task's own REQs did
not call for, so it recorded the step instead of applying it. The pin
has been inaccurate since: the script existed and nothing ran it.

The lint job rather than services (linux): the scan reads tracked files
and needs no provisioned service, and lint already gates the whole
matrix, so a stale declaration now fails before anything spends a
runner.

Additions only, so REQ-E1.4 is untouched.

Its three dependencies are already present in that job and were checked
rather than assumed: git from checkout, python3 from setup-python, and
PyYAML transitively from the `pip3 install ansible` step (the script
exits early on `import yaml`). The job runs on macos-latest, so the
script was also read for GNU-isms — the sed calls are portable and the
scanning is done in python3.

Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9
Four of the five entries no longer describe anything open, and a queue
that lists resolved work is the same defect this bundle's Task 5 existed
to remove: a tracked statement that stopped being true.

  Task 2  Entirely about CI creating no workflow run, on the exhausted-
          macOS-minutes hypothesis. That was withdrawn — the outage was
          runner scarcity and cleared on its own. Task 3's entry already
          recorded the correction.
  Task 3  Both halves resolved. The runtime clause is now verified in CI
          rather than pending on the host: the services (linux) job runs
          scripts/postgresql-access-test.sh and passes on main. The
          ALTER ROLE finding it recorded is applied in this branch.
  Task 5  The REQ-B1.5 [test] wiring it recorded is applied in this
          branch, so the operator action it asks for is done.
  Task 6  Asks for a re-read of `gh pr checks 103` once macOS capacity
          frees. #103 is merged. The osx and upgrade jobs are still red,
          but for the standing 30-minute Brewfile timeout that
          reproduces on main and has its own observation entry, not for
          anything in that task.

Task 1 stays: it needs ~/.config/dotfiles/private-identifiers, which is
machine-local by design and cannot be supplied from here.

spec-validate passes (0 errors, 0 warnings) on the trimmed bundle.

Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9
@inkatze
inkatze merged commit 83c6d3e into main Aug 7, 2026
9 of 12 checks passed
@inkatze
inkatze deleted the chore/dev-services-followups branch August 7, 2026 20:50
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.

1 participant