Skip to content

feat(directie): a signals script that says what is red, without a model - #330

Merged
Apolloccrypt merged 2 commits into
mainfrom
feat/directie-signalen
Sep 2, 2026
Merged

feat(directie): a signals script that says what is red, without a model#330
Apolloccrypt merged 2 commits into
mainfrom
feat/directie-signalen

Conversation

@Apolloccrypt

@Apolloccrypt Apolloccrypt commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Een meetscript zonder model dat in een oogopslag laat zien wat rood is.
scripts/directie/signalen.py stelt een vaste lijst vragen aan GitHub (via
gh) en aan productie (via curl), en geeft per vraag een ernst, een meting
en een voorstel van een zin. JSON naar stdout, leesbare tekst met --tekst,
exitcode 1 als er iets rood is.

Wat het meet

  • Elke open pull request: check-status en leeftijd in uren.
  • Open dependabot-PRs als een signaal, met de leeftijd van de oudste.
  • Gefaalde workflow-runs van de laatste 24 uur. Rood alleen als main geraakt is.
  • De laatste uitkomst van de drie kanaries met tijdstip. Ze zijn geen losse
    workflows maar stappen in de live-job van product-heartbeat.yml, dus het
    script zoekt ze op naam in .github/workflows. Het kijkt daarbij eerst naar
    de schedule- en workflow_dispatch-runs, want alleen daar draait de
    live-job; een kale lijst van de laatste twintig runs bestaat op een drukke dag
    bijna helemaal uit pull-request-runs waarin de kanariestappen zijn
    overgeslagen. Levert dat niets op, dan volgt een breed net over alle events.
    Verhuist een kanarie naar een eigen workflow, dan blijft dat werken.
    Verdwijnt hij, dan wordt het signaal oranje in plaats van stil groen.
  • Statuscode van https://paramant.app/health en de responstijd van de homepage.
  • De zes ParaID-deny-ingangen: POST met lege JSON-body naar
    /v1/paraid/issue-document moet op alle zes de hosts 404 geven.

Een signaal dat niet gemeten kon worden is oranje, nooit groen. De drempels
staan als constanten bovenaan het bestand.

Geen extra afhankelijkheden: Python 3 standaardbibliotheek plus gh en curl.
Een volledige run duurde hier 12 tot 17 seconden over vier runs, vrijwel
helemaal wachten op GitHub. docs/directie.md legt uit wat elk signaal meet en
wanneer het rood wordt.

Getest

  • python3 -m py_compile scripts/directie/signalen.py
  • Echte runs tegen deze repo en tegen productie (laatste uitvoer hieronder).
  • Foutpad: met --repo naar een niet bestaande repo worden de GitHub-signalen
    oranje met "niet gemeten" in plaats van dat het script sterft.
  • Rood pad: met /health naar een 404-pad gaat het signaal rood en eindigt het
    script met exitcode 1. In een eerdere run hier ving het script ook een echt
    rood signaal: sign-e2e faalde toen op PR Homepage speaks to a buyer: what it does, what it costs, why you can check it #328.

Uitvoer van python3 scripts/directie/signalen.py --tekst

PARAMANT directiesignalen  2026-09-02T14:07:55Z
repo Apolloccrypt/paramant-relay
rood 0   oranje 2   groen 17

[ORANJE] open dependabot-PRs
           meting:   1 open, oudste 6.7 dagen (#313)
           voorstel: Loop de dependabot-PRs langs en merge wat groen is.

[ORANJE] gefaalde runs laatste 24 uur
           meting:   1 gefaalde run, 0 op main (sign-e2e)
           voorstel: Laat de eigenaar van de branch de gefaalde runs oppakken, main is niet geraakt.

[GROEN ] kanarie heartbeat
           meting:   success, 2.7 uur geleden (run 33624449015, product-heartbeat.yml)
           voorstel: Niets doen, de kanarie leeft.

[GROEN ] kanarie parasign-kanarie
           meting:   success, 2.7 uur geleden (run 33624449015, product-heartbeat.yml)
           voorstel: Niets doen, de kanarie leeft.

[GROEN ] kanarie transfer-kanarie
           meting:   success, 2.7 uur geleden (run 33624449015, product-heartbeat.yml)
           voorstel: Niets doen, de kanarie leeft.

[GROEN ] ParaID dicht op finance.paramant.app
           meting:   POST met lege body geeft HTTP 404 in 0.08 s (verwacht 404)
           voorstel: Niets doen, de route is dicht.

[GROEN ] ParaID dicht op health.paramant.app
           meting:   POST met lege body geeft HTTP 404 in 0.07 s (verwacht 404)
           voorstel: Niets doen, de route is dicht.

[GROEN ] ParaID dicht op iot.paramant.app
           meting:   POST met lege body geeft HTTP 404 in 0.07 s (verwacht 404)
           voorstel: Niets doen, de route is dicht.

[GROEN ] ParaID dicht op legal.paramant.app
           meting:   POST met lege body geeft HTTP 404 in 0.06 s (verwacht 404)
           voorstel: Niets doen, de route is dicht.

[GROEN ] ParaID dicht op paramant.app
           meting:   POST met lege body geeft HTTP 404 in 0.07 s (verwacht 404)
           voorstel: Niets doen, de route is dicht.

[GROEN ] ParaID dicht op relay.paramant.app
           meting:   POST met lege body geeft HTTP 404 in 0.06 s (verwacht 404)
           voorstel: Niets doen, de route is dicht.

[GROEN ] PR #325 Give ParaSign a product page at /parasign so the signing pro
           meting:   PR #325 is groen en 42 min oud
           voorstel: Beoordeel PR #325 wanneer het uitkomt.

[GROEN ] PR #326 Keep the recurring billing layer off until BILLING_MODE says
           meting:   PR #326 is groen en 38 min oud
           voorstel: Beoordeel PR #326 wanneer het uitkomt.

[GROEN ] PR #327 Pin the site's ten heaviest claims to the code that makes th
           meting:   PR #327 is groen en 37 min oud
           voorstel: Beoordeel PR #327 wanneer het uitkomt.

[GROEN ] PR #328 Homepage speaks to a buyer: what it does, what it costs, why
           meting:   PR #328 is groen en 18 min oud
           voorstel: Beoordeel PR #328 wanneer het uitkomt.

[GROEN ] PR #329 Build the crypto binding on rust:1.98-alpine by adopting the
           meting:   PR #329 is groen en 14 min oud
           voorstel: Beoordeel PR #329 wanneer het uitkomt.

[GROEN ] PR #330 feat(directie): a signals script that says what is red, with
           meting:   PR #330 is groen en 10 min oud
           voorstel: Beoordeel PR #330 wanneer het uitkomt.

[GROEN ] productie /health
           meting:   HTTP 200 in 0.07 s
           voorstel: Niets doen, productie antwoordt gezond.

[GROEN ] responstijd homepage
           meting:   HTTP 200 in 0.10 s (oranje boven 1.0 s, rood boven 2.5 s)
           voorstel: Niets doen, de homepage laadt snel.

Niets rood, exitcode 0.

Apolloccrypt and others added 2 commits September 2, 2026 15:57
scripts/directie/signalen.py asks a fixed list of questions to GitHub via gh
and to production via curl, and turns each answer into a severity, a
measurement and a one-sentence proposal. JSON on stdout, readable text with
--tekst, exit 1 when anything is red, so cron or a later round can steer on
the exit code.

It measures: every open pull request with its check status and age in hours;
open dependabot pull requests as one signal with the age of the oldest; failed
workflow runs of the last 24 hours, red only when main is hit; the last outcome
of the three canaries with a timestamp, found by name in .github/workflows
rather than hardcoded, so a canary that moves to its own workflow keeps being
measured and one that disappears turns orange instead of quietly green; the
status code of /health and the response time of the homepage; and the six
ParaID deny entries, where POST with an empty body to
/v1/paraid/issue-document must answer 404 on every host.

A signal that could not be measured is orange, never green. Thresholds sit as
named constants at the top of the file so the argument about when something is
red happens in one place.

Python 3 standard library plus gh and curl, no other dependencies.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…runs

Three points from review on the signals script.

The canary window was too narrow. gh run list --workflow product-heartbeat.yml
--limit 20 put the last schedule run at position 15 of 20 on a busy day,
because the list is full of pull_request runs in which the canary steps are
skipped. One more busy hour and a living canary would have been reported
orange. It now asks for the schedule and workflow_dispatch runs first, which is
where the live job runs at all, and only falls back to a wide net over all
events when that yields nothing. Side effect: fewer job API calls, so a full
run got faster rather than slower.

docs/directie.md names the wortel field in the JSON section, and the run
duration is now the measured 12 to 17 seconds over four runs instead of a round
number, with what makes it grow.

signaal_homepage had a dead branch: status >= 400 or status is None can never
see None, because a failed measurement returns earlier on the fout field. The
None check now comes first, where it can do its work.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Apolloccrypt
Apolloccrypt merged commit 0078892 into main Sep 2, 2026
11 checks passed
Apolloccrypt added a commit that referenced this pull request Sep 2, 2026
Mick's two content requirements for /parasign, plus the rebase onto main.

The free plan is called Community, because that is what it is: a give-back,
not a trial and not a funnel. The card says so in the founder's own terms
(Mick Beer, privacy and security researcher at Paramantis Solutions B.V.,
the wording about.html already carries) and bridges to /pricing, where the
same plan is listed as the tier named Free. PR #328 introduces the same
Community wording on the homepage; whichever lands first, the bridge keeps
both pages honest.

The paid tiers are presented as what they are: business plans that pay for
the free one. Names and amounts are lifted from /pricing (Pro 49, Business
299, Enterprise on request, with the incl-btw checkout amounts), and
relay/test/pricing-page.test.js already ties every one of them to
relay/lib/billing-catalog.js.

The technique moved to section 04, under the heading that says it is
evidence and not a pitch. ML-DSA-65, FIPS 204 and SHA3-256 no longer appear
in the title, the description, the H1 area or the opening paragraph; first
occurrence in the rendered page is now at character 4633 of 1280px body
text, well past the plans. The hero says what the reader gets, the proof
section says how to check it.

Three new gates in relay/test/pricing-page.test.js, deliberately in that
file rather than in ui-truthfulness.test.mjs, which #328 is rewriting:
- saying Community obliges the page to name the /pricing tier it maps to,
  and obliges /pricing to still carry a tier named Free
- every tier name printed on /parasign must be a tier /pricing sells
- the founder line may claim only what /about claims, and naming him
  obliges the page to name the company registration

Rebased onto main (#324 navigation, #326 billing stance, #330 signals),
no conflicts. frontend/apply-nav.py stamped the seven-item nav shell, the
Company/Legal footer and the design-system versions onto the page; a second
run produces no diff. bron-seo/apply_seo_head.py re-stamped the JSON-LD for
the new title and description. bron-seo/build_sitemap.py said the sitemap
was out of date and regenerated it: one line, the lastmod of /vault, which
#324 touched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Apolloccrypt added a commit that referenced this pull request Sep 2, 2026
Mick's two content requirements for /parasign, plus the rebase onto main.

The free plan is called Community, because that is what it is: a give-back,
not a trial and not a funnel. The card says so in the founder's own terms
(Mick Beer, privacy and security researcher at Paramantis Solutions B.V.,
the wording about.html already carries) and bridges to /pricing, where the
same plan is listed as the tier named Free. PR #328 introduces the same
Community wording on the homepage; whichever lands first, the bridge keeps
both pages honest.

The paid tiers are presented as what they are: business plans that pay for
the free one. Names and amounts are lifted from /pricing (Pro 49, Business
299, Enterprise on request, with the incl-btw checkout amounts), and
relay/test/pricing-page.test.js already ties every one of them to
relay/lib/billing-catalog.js.

The technique moved to section 04, under the heading that says it is
evidence and not a pitch. ML-DSA-65, FIPS 204 and SHA3-256 no longer appear
in the title, the description, the H1 area or the opening paragraph; first
occurrence in the rendered page is now at character 4633 of 1280px body
text, well past the plans. The hero says what the reader gets, the proof
section says how to check it.

Three new gates in relay/test/pricing-page.test.js, deliberately in that
file rather than in ui-truthfulness.test.mjs, which #328 is rewriting:
- saying Community obliges the page to name the /pricing tier it maps to,
  and obliges /pricing to still carry a tier named Free
- every tier name printed on /parasign must be a tier /pricing sells
- the founder line may claim only what /about claims, and naming him
  obliges the page to name the company registration

Rebased onto main (#324 navigation, #326 billing stance, #330 signals),
no conflicts. frontend/apply-nav.py stamped the seven-item nav shell, the
Company/Legal footer and the design-system versions onto the page; a second
run produces no diff. bron-seo/apply_seo_head.py re-stamped the JSON-LD for
the new title and description. bron-seo/build_sitemap.py said the sitemap
was out of date and regenerated it: one line, the lastmod of /vault, which
#324 touched.
@Apolloccrypt
Apolloccrypt deleted the feat/directie-signalen branch September 5, 2026 18:56
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