Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
Agents
particle-academy/change-council
claude-code
cursor
change-ledger
detector
state-machine
audit-log
fingerprints
petitions
php-tokenizer

Two halves in one repo:

Install
php artisan boost:add-skill particle-academy/change-council

Save this content to: AGENTS.md

# change-council code map

Two halves in one repo:

- `council/`: the detector. Plain Node ESM, **zero dependencies** (built-ins
  only), plus one PHP script run as a child process. CI fetches it by pinned
  SHA and content hash, so never add an import from outside `council/`.
- `src/` (`ChangeCouncil\`): the Laravel 13 ledger. Runtime imports are
  illuminate components only (symfony/process and the HTTP client arrive
  through them). inertia-laravel is a `suggest`. Nothing in `src/` uses
  Foundation helpers (`config()`, `app()`); read config through the container.

## The detector

- `check.mjs` is the CLI (report-only: always exits 0 unless the usage is
  wrong or `--strict` is passed). `lib/detect.mjs` runs every extractor in
  `lib/extractors/`, applies waivers, sorts and counts. An extractor returns
  findings built by `lib/finding.mjs`; it reports what it did through
  `ctx.coverage()` and never swallows an error (`ctx.error()` sets `ok:false`).
- Everything is read from git objects (`lib/git.mjs`), never the working tree,
  except `--from-dts/--to-dts` directories. Fingerprints are
  `sha256(class|subject|before|after)`; changing a subject format changes every
  fingerprint and un-covers approved Changes, so treat subjects as wire format.
- Never spawn a bare program name. `resolveExecutable()` in `lib/git.mjs` walks
  PATH (absolute entries only) so the repo under inspection or the start
  directory cannot supply `git` or `php`. Its cases are
  `council/test/fixtures/executable-lookup-cases.json`, the same file as in
  fancy-git-js and fancy-git-php.
- `php/surface.php` tokenizes (never executes) PHP files given on stdin. It
  compares only CHANGED files under the composer autoload paths.
- `lib/record.mjs` must stay byte-compatible with `src/Support/CanonicalJson.php`.
  The shared fixture `tests/fixtures/decision-record.json` is verified by both
  suites; regenerate it with `php tests/fixtures/make-decision-fixture.php`.

## The ledger

- `Ledger\Ledger` is the ONLY writer of `council_changes.state`. Every
  transition is one transaction plus audit events through `Audit\AuditLog`.
  States and the transition diagram are in `Ledger\States`.
- Whitelisting is computed in `propose()` from `Ledger\Whitelist`, never read
  from input. For `github_issue` the initiator is the issue author's login,
  checked against the GitHub author list; a whitelisted author opens round 1
  like a whitelisted agent. Anything non-whitelisted goes to `awaiting_owner`.
- Owner methods (`approveInitiation`, `rejectInitiation`, `override`,
  `revoke`, `setSilencePolicy`, `setChangeSilencePolicy`) are called ONLY from
  `Http\Api` behind the `owner` ability. Never from `src/Console`: an agent can
  run any command with any flag. `CommandsTest` scans for it.
- `Petitions\Ingest` is the only writer of votes. Order: replay check, flags,
  strict parse (`ReplyParser`), nonce lookup, sender match, change/round/digest
  match, open-or-catch-up, then store. The tally reads only `counted` votes and
  only `verdict` and impact `severity`.
- `Petitions\DeliveryResult` reads a send result at three refusal depths;
  only an explicit `ok: true` is `sent`.
- The ledger never calls Genie: `Transport\ClerkQueueTransport` leaves
  petitions queued. Tests bind `tests/Support/FakeTransport`.
- `Http\Api` is framework-free; `Laravel\CouncilController` adds only the body
  limit, JSON decoding and the user. Every route asks `Http\Authorizer`
  (default `DenyAll`); only a literal `true` from a callback allows.
  `Http\OwnersAuthorizer` (`Council::authorizeOwners()`) is the opt-in
  owner-only hook over `council.owners`; an empty list allows nobody. It is
  never bound by default.
- `Models\AuditEvent` throws on update/delete; the migration adds SQLite
  triggers. `AuditLog::verify()` reads raw rows, not models.
- `Feed\Feed` never emits reply free text (it masks `note`/`reason`).
- `Notify\OwnerEventNotifier` (default `NullNotifier`) is told about owner
  events. `Ledger::notifyAfterCommit()` queues it with `afterCommit()` at each
  transition point:
  - `propose()` when it lands in `awaiting_owner` (the only way into that
    state), as `awaiting_owner`;
  - `approveInitiation`, `rejectInitiation`, `override` and `revoke`;
  - `close()`, once per closed round, plus `escalated`.

An `OwnerEvent` holds refs, states, codes and counts, never free text. The
  `awaiting_owner` initiator passes through `OwnerEvent::identity()`. A
  throwing notifier is swallowed and audited as `notify.failed`.
  `Notify\GenieInboxNotifier` reads `GENIE_INBOX_URL`/`_TOKEN` with `getenv()`
  at send time, never config. It audits event, ref and status only, never
  throws and never retries. Opt in with `Council::notifyUsing()`,
  `Council::notifyGenie()` or `council.notify.genie`.

## The pages

`resources/js/Pages/Council/{Index,Show}.tsx` plus `parts/*.ts` (no JSX, so a
host's `**/*.tsx` page glob skips them). Imports are limited to Fancy packages,
React and `@inertiajs/react`; reply text renders as `Text` or a read-only
`CodeView`, never HTML. `tests/Unit/PagesTest.php` enforces these, the slow
visibility-gated poll, and a `data-action`/`data-field` handle on every control
(put it FIRST in the tag: the check stops at the first `>`).
Hosts publish COPIES of these files; `Laravel\PublishedPages` and
`council:pages-check` compare a host's copy with the shipped one, so any
change here is a "re-publish the pages" line in the CHANGELOG.

## Tests

- `node --test "council/test/*.test.mjs"`: fixture git repos built per test,
  a must-fire pair per class and a must-not-fire pair per waiver.
- `vendor/bin/pest`: a hand-built kernel (`tests/Support/TestApp.php`; no
  testbench), in-memory SQLite, the array cache, and `FakeTransport`. The clock
  is frozen at 2026-10-27 12:00 per test. HTTP tests dispatch through the real
  router; bind `request` before setting the user resolver.

change-council code map

Two halves in one repo:

  • council/: the detector. Plain Node ESM, zero dependencies (built-ins only), plus one PHP script run as a child process. CI fetches it by pinned SHA and content hash, so never add an import from outside council/.
  • src/ (ChangeCouncil\): the Laravel 13 ledger. Runtime imports are illuminate components only (symfony/process and the HTTP client arrive through them). inertia-laravel is a suggest. Nothing in src/ uses Foundation helpers (config(), app()); read config through the container.

The detector

  • check.mjs is the CLI (report-only: always exits 0 unless the usage is wrong or --strict is passed). lib/detect.mjs runs every extractor in lib/extractors/, applies waivers, sorts and counts. An extractor returns findings built by lib/finding.mjs; it reports what it did through ctx.coverage() and never swallows an error (ctx.error() sets ok:false).
  • Everything is read from git objects (lib/git.mjs), never the working tree, except --from-dts/--to-dts directories. Fingerprints are sha256(class|subject|before|after); changing a subject format changes every fingerprint and un-covers approved Changes, so treat subjects as wire format.
  • Never spawn a bare program name. resolveExecutable() in lib/git.mjs walks PATH (absolute entries only) so the repo under inspection or the start directory cannot supply git or php. Its cases are council/test/fixtures/executable-lookup-cases.json, the same file as in fancy-git-js and fancy-git-php.
  • php/surface.php tokenizes (never executes) PHP files given on stdin. It compares only CHANGED files under the composer autoload paths.
  • lib/record.mjs must stay byte-compatible with src/Support/CanonicalJson.php. The shared fixture tests/fixtures/decision-record.json is verified by both suites; regenerate it with php tests/fixtures/make-decision-fixture.php.

The ledger

  • Ledger\Ledger is the ONLY writer of council_changes.state. Every transition is one transaction plus audit events through Audit\AuditLog. States and the transition diagram are in Ledger\States.
  • Whitelisting is computed in propose() from Ledger\Whitelist, never read from input. For github_issue the initiator is the issue author's login, checked against the GitHub author list; a whitelisted author opens round 1 like a whitelisted agent. Anything non-whitelisted goes to awaiting_owner.
  • Owner methods (approveInitiation, rejectInitiation, override, revoke, setSilencePolicy, setChangeSilencePolicy) are called ONLY from Http\Api behind the owner ability. Never from src/Console: an agent can run any command with any flag. CommandsTest scans for it.
  • Petitions\Ingest is the only writer of votes. Order: replay check, flags, strict parse (ReplyParser), nonce lookup, sender match, change/round/digest match, open-or-catch-up, then store. The tally reads only counted votes and only verdict and impact severity.
  • Petitions\DeliveryResult reads a send result at three refusal depths; only an explicit ok: true is sent.
  • The ledger never calls Genie: Transport\ClerkQueueTransport leaves petitions queued. Tests bind tests/Support/FakeTransport.
  • Http\Api is framework-free; Laravel\CouncilController adds only the body limit, JSON decoding and the user. Every route asks Http\Authorizer (default DenyAll); only a literal true from a callback allows. Http\OwnersAuthorizer (Council::authorizeOwners()) is the opt-in owner-only hook over council.owners; an empty list allows nobody. It is never bound by default.
  • Models\AuditEvent throws on update/delete; the migration adds SQLite triggers. AuditLog::verify() reads raw rows, not models.
  • Feed\Feed never emits reply free text (it masks note/reason).
  • Notify\OwnerEventNotifier (default NullNotifier) is told about owner events. Ledger::notifyAfterCommit() queues it with afterCommit() at each transition point:
    • propose() when it lands in awaiting_owner (the only way into that state), as awaiting_owner;
    • approveInitiation, rejectInitiation, override and revoke;
    • close(), once per closed round, plus escalated.

An OwnerEvent holds refs, states, codes and counts, never free text. The awaiting_owner initiator passes through OwnerEvent::identity(). A throwing notifier is swallowed and audited as notify.failed. Notify\GenieInboxNotifier reads GENIE_INBOX_URL/_TOKEN with getenv() at send time, never config. It audits event, ref and status only, never throws and never retries. Opt in with Council::notifyUsing(), Council::notifyGenie() or council.notify.genie.

The pages

resources/js/Pages/Council/{Index,Show}.tsx plus parts/*.ts (no JSX, so a host's **/*.tsx page glob skips them). Imports are limited to Fancy packages, React and @inertiajs/react; reply text renders as Text or a read-only CodeView, never HTML. tests/Unit/PagesTest.php enforces these, the slow visibility-gated poll, and a data-action/data-field handle on every control (put it FIRST in the tag: the check stops at the first >). Hosts publish COPIES of these files; Laravel\PublishedPages and council:pages-check compare a host's copy with the shipped one, so any change here is a "re-publish the pages" line in the CHANGELOG.

Tests

  • node --test "council/test/*.test.mjs": fixture git repos built per test, a must-fire pair per class and a must-not-fire pair per waiver.
  • vendor/bin/pest: a hand-built kernel (tests/Support/TestApp.php; no testbench), in-memory SQLite, the array cache, and FakeTransport. The clock is frozen at 2026-10-27 12:00 per test. HTTP tests dispatch through the real router; bind request before setting the user resolver.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core