Pre-1.0. Not intended for public use yet. The API is subject to undocumented change, and these pages may already be wrong about it.

Skip to content

Diagnosing Your Feed ​

Introduction ​

The doctor checks your definitions, schema, and recorded activities and reports how to fix gaps. By default, publishing without a headline definition throws UnauthoredActivity in local and testing environments. When storyfeed.grammar.strict is disabled, the activity can publish with a null headline; the doctor can find these gaps in already-recorded activities.

Running the Doctor ​

shell
php artisan storyfeed:doctor

For an order-placement activity recorded with strict grammar disabled and no headline definition, the report shows:

txt
No headline resolves for `order.place` — headlines will be null.
No icon resolves for `order.place`.
Note: verb `place` has no AS2.0 mapping — will serialize as base `Activity`.
2 finding(s) — see above.
Run with --stubs to print the registrations these imply.

The count excludes notes. If no errors or warnings are found, the command prints Storyfeed looks healthy.

Most checks query recorded activities, so use a database with traffic, such as staging or a production copy. With no activities, only configuration and schema checks can report findings.

Running Selected Checks ​

--list prints the check names, and --only runs the ones you name:

shell
php artisan storyfeed:doctor --list
php artisan storyfeed:doctor --only=grammar --only=verbs

Every check is listed in Doctor Checks.

Reading a Finding ​

Each finding includes a code, severity, and message. The text report colours messages by severity. Use --json to return the full report:

shell
php artisan storyfeed:doctor --json
json
{
    "healthy": false,
    "count": 2,
    "severity": "error",
    "findings": [
        {
            "code": "grammar.missing",
            "severity": "error",
            "message": "No headline resolves for `order.place` — headlines will be null.",
            "subject": {
                "type": "order",
                "verb": "place"
            },
            "fix": {
                "registry": "grammar",
                "key": "order.place",
                "tokens": [":actor", ":object", ":target", ":context", ":origin", ":result", ":instrument"],
                "snippet": "Story::for(Order::class)->verb('place')->headline(':actor placed :object');",
                "definition": "Story::for(Order::class)->verb('place')->headline(':actor placed :object');"
            }
        }
    ]
}

The other findings use the same structure. Findings without a generated fix have "fix": null. The code's first segment identifies the check; subject identifies what it checked. definition contains the line printed by --stubs.

SeverityMeaning
errorthe feed displays incorrect content, or publication will throw
warningsomething is missing or inconsistent, but the feed still displays correctly
infoadditional information that may not require a change

Fixing Common Findings ​

FindingMeansFix
grammar.missinga recorded type and verb has no headlinewrite it in routes/feed.php, or print it with --stubs
grammar.icon_missinga recorded type and verb has no iconadd ->icon()
aggregates.missingactivities group, and the group has no headlineadd a group headline, or print it with --stubs
verbs.undeclareda recorded verb is not in your vocabulary, usually a typofix the call site, or register the verb
feeds.unclassifiedno restricted named feed includes or excludes a verbadd the verb to a feed's only() or except()
surface.unaliaseda Feedable model has no morph alias, so publishing about it throwsgive it an alias, or return its parent's from getMorphClass() (Surface)
entities.unfeedableactivities name a model that does not implement Feedableimplement Feedable, then run storyfeed:trickle
backlog.uncachedentities have uncached labels and linksschedule storyfeed:trickle
tables.missinga package table does not existrun the migrations

See Doctor Checks for all findings.

Generating Missing Definitions ​

Use --stubs to print suggested definitions for routes/feed.php:

shell
php artisan storyfeed:doctor --stubs
routes/feed.php
php
use App\Models\Order;
use Storyfeed\Facades\Story;

Story::for(Order::class)->verb('place')->headline(':actor placed :object');
// order.place: an icon from your app's own set; doctor cannot choose one.
// Story::for(Order::class)->verb('place')->icon('…');

Review each stub before adding it. Incomplete stubs, such as icons, are commented out with an explanation. The finding remains until you supply the missing definition. See Doctor Checks for the definitions --stubs generates.

To write Story classes instead, run make:story --from-doctor.

Running the Doctor in CI ​

By default, findings leave the exit status at 0. Use --fail-on to fail the command at a chosen severity:

shell
php artisan storyfeed:doctor --fail-on=warning # Fails on a warning or an error.
php artisan storyfeed:doctor --fail-on=error   # Fails on an error only.

Coverage assertions check headlines in your test suite before traffic exists. The doctor checks recorded activities.

Released under the MIT License.