Skip to content
ROLLCALL

Register 0.1 a part of WELD

Fleet attendance, Wayne State University

ROLLCALL

Every app answers “present”.

The ones on PHP 7.4 answer from the back row.

WELD's fleet scanner. For every app it writes down the PHP image, the declared PHP floor, Laravel, the auth package and the PROCTOR result, then checks each one against CREED's policy.json by date. One snapshot a day gives you drift and an EOL burn-down.

composer require waynestate/rollcall

Quick start Take the roll

Today's roll sample data
  1. kiln-bookingPHP 8.5present
  2. tuba-rentalPHP 8.4present
  3. pigeon-postPHP 8.3late
  4. lunch-ledgerPHP 8.3late
  5. abacus-classicPHP 7.4back row

Answered 5 of 5

The magic trick is attendance

Take the roll

Seventeen apps, seated front to back by PHP version. Scroll, and ROLLCALL calls each name down the list. Everyone answers. The back row answers with a hand in the air.

Sample data · fictional apps · policy as of 2026-10-28

Sample roll: seventeen fictional apps with their PHP image, Laravel version, auth package, PROCTOR result and the mark ROLLCALL gives them
No.AppPHP imageLaravelAuthPROCTORMark
Front row PHP 8.5 and 8.4, active
01kiln-booking8.513sesamepasspresent
02tuba-rental8.413sesamepasspresent
03moth-catalog8.412sesamepasspresent
04quad-weather8.413nonepasspresent
05greenhouse-log8.412sesamepasspresent
06sundial8.413sesamepasspresent
07otter-tracker8.412sesamepasspresent
Middle rows PHP 8.3 and 8.2, security fixes only
08pigeon-post8.312phpcaspasslate
09lunch-ledger8.312sesamefaillate
10chess-club8.311, EOLphpcaspasslate
11lost-mittens8.312nonenonelate
12fog-index8.2 64 days left11, EOLphpcaspasslate
Back row past end of life
13abacus-classic7.48, EOLphpcasnoneback row
14punch-card-pal7.4nonenonenoneback row
15dial-up-directory8.110, EOLphpcasfailback row
16floppy-archive8.09, EOLsesamepassback row
17ghost-kiosklegacy-base no version in the tagnonenonenoneinaudible
present
7
late
5
back row
4
inaudible
1
Answered
17

Nobody is ever marked absent: a gap in one source becomes a note on that app, never a failed scan. The public report shows only totals like these; the per-app list is the internal view (--internal) and stays inside the project.

Five answers per app

What “present” means

Each answer is a version, and every version is checked against the dates in CREED's policy.json. State is never decided in code.

  1. PHP image

    The runtime the app really ships on, read from the app list's image tag.

  2. PHP floor

    The lowest PHP its composer.json allows. * counts as no floor at all.

  3. Laravel

    The installed version from composer.lock, never a guess.

  4. Auth package

    Which sign-in package is installed: SESAME, a CAS client, or none.

  5. PROCTOR

    pass, fail or none, from PROCTOR's JSON report. ROLLCALL never re-runs a rule.

Key to the marks

  • present active: fully supported
  • late security_only: fixes only, a date is coming
  • back row eol: past its security date, or older than anything the policy lists
  • inaudible unknown: newer than the policy knows, or a tag nobody can read

Drift and the burn-down

Watch the back row empty

One snapshot per scan day. Count the apps on an EOL image each day and you get a line that should only go one way.

Apps on an EOL PHP image, one scan a week Sample data
Apps on an EOL PHP image fell from 19 on August 12 to 4 on October 28 (sample data). 151050 Aug 12Sep 9Oct 7Oct 28 19 4 left

Grafana draws the same line from /metrics with the bundled dashboard, grafana/rollcall-burn-down.json.

Drift, counted per kind

  • image_eolruns on an EOL PHP image
  • image_unknownan image tag nobody can read
  • image_below_floorthe image is older than the app allows
  • floor_allows_eolthe PHP floor still lets an EOL version in
  • floor_unboundedno PHP floor declared at all
  • eol_past_gracepast the policy's grace days
  • laravel_eolLaravel past its security date
  • proctor_missingno PROCTOR report on file
  • proctor_failingPROCTOR says fail
  • override_expireda PROCTOR override ran out

rollcall drift also compares the policy with a saved endoflife.date page. A difference is a flag for a person; the policy stays the source of truth.

From a checkout, with the bundled fixtures

Quick start

No network, no token. PHP 8.3 or newer. Install dependencies once with composer install, then call the roll.

bash

export ROLLCALL_POLICY_FILE=tests/fixtures/policy.json
export ROLLCALL_REPOS_DIR=tests/fixtures/repos
export ROLLCALL_IMAGES_FILE=tests/fixtures/images.json
export ROLLCALL_PROCTOR_DIR=tests/fixtures/proctor
export ROLLCALL_STORE_DIR=var/snapshots
php bin/rollcall scan
php bin/rollcall report

What comes back real output, ROLLCALL 0.1, bundled fixtures (four demo apps)

Present: 4 apps. Snapshot 2026-10-28 saved to var/snapshots.

ROLLCALL 0.1.0 | scan 2026-10-28 | as of 2026-10-28 | public
Apps present: 4 (scan problems: 0)

PHP image
VERSION  APPS  STATE          SECURITY UNTIL  DAYS TO EOL
8.1      1     eol            2025-12-31      -301
8.3      1     security_only  2027-12-31      429
8.4      1     active         2028-12-31      795
unknown  1     unknown        -               -

EOL burn-down (state on each scan day)
DATE        APPS  EOL  SUPPORTED  UNKNOWN
2026-10-28  4     1    2          1

exit 0, however the fleet looks. There is no exit 1: ROLLCALL takes attendance, it does not hand out detention.

rollcall scan
Calls the roll once and stores <date>.json. Scan twice in a day and that day's snapshot is replaced.
rollcall report
--format=text|json|prometheus. --internal adds the per-app list; keep that inside the project.
rollcall drift
--feed=<file>, a saved endoflife.date page. ROLLCALL never fetches it itself.
In Laravel
The package registers itself. Publish the config with php artisan vendor:publish --tag=rollcall-config, then schedule php artisan rollcall:scan.

Classroom rules

For noticing who is missing, not for shaming them

  1. It enforces nothing.

    No issues opened, no comments, no deploys. It exits 0 whatever it finds.

  2. Totals, not names.

    The public report is counts and progress only: no app names, no owners, no ranking.

  3. Read-only everywhere.

    GET and HEAD only, and a test fails if a write verb shows up in src/. The one thing it writes is its own snapshot folder.

  4. Metrics stay off until you turn them on.

    Then /metrics wants a bearer token or an allowed address. With neither set, nobody gets in.

Sources in, one register out

Where the answers come from

Three sources and one policy go in; one snapshot a day comes out. Each source has a fixture adapter, so nothing here needs a live host to try.

  • Repositoriescomposer.json and .lock, from GitLab or a folder
  • App listthe PHP image each app runs
  • PROCTORone JSON report per app
  • CREEDpolicy.json, the dates
ROLLCALLscan, snapshot, compare
  • Terminaltext and json reports
  • /metricsPrometheus text, off by default
  • Grafanathe bundled burn-down dashboard
  • Laravel pagea WayneUI dashboard of totals

ROLLCALL's place in WELD

The class list

WELD is Wayne State's application stack. Every part answers present here too.

  1. WayneUIthe interface; the dashboard wears its classes
  2. CREEDwrites the dates ROLLCALL reads
  3. PROCTORchecks one app; ROLLCALL collects the results
  4. PREFLIGHTCI templates, where PROCTOR reports are born
  5. SESAMEthe auth package ROLLCALL hopes to count
  6. HELMETbaseline runtime, with its own /metrics
  7. Pinstripethe Pint and PHPStan rules this repo wears
  8. Sourdoughstarters that begin in the front row
  9. WELDthe whole stack, joined in one app
  10. ROLLCALLyou are here: the fleet census and EOL burn-down
  11. BOOSTERmoves the back row forward
  12. SQUIREcarries the release to Citadel
  13. DRAWBRIDGEthe Citadel sign-in gateway
  14. ADVISORask what applies to your app