Package: living-course
Generated from api/packages/living-course
Source: api/packages/living-course. The sections after the README are extracted from the code on every docs build.
README
Section titled “README”Watches the sources of a course built with the Course Builder (an upload, a Git repository, web
pages), detects what changed at fragment level without a model, finds the lessons and quiz questions
that cite the changed passages, and proposes cited updates the author reviews as one diff. Learner
progress is preserved by explicit rules and every decision lands in a tamper-evident audit trail.
Records: ADR 0030 (revisions and proposals), 0031 (change detection), 0032 (connectors), 0033
(progress rules), 0034 (audit trail); plan docs/plans/phase-3.md.
- Author guide:
front/docs-site/src/content/docs/creators/course-builder.mdx(sections on sync and updates) - Settings, env variables, commands:
front/docs-site/src/content/docs/admin/living-course.mdx - Internals, endpoints, events:
front/docs-site/src/content/docs/developers/living-course.mdx - Writing a connector plugin:
docs/living-course/connector-plugins.md
Connector (upload | git | url | plugin) ─▶ Revision (numbered per source, fragments with file_path) ─▶ FragmentDiff (deterministic: unchanged | changed | moved | added | removed; no model) ─▶ ImpactAnalyzer (citations ─▶ elements) ─▶ StalenessService (element_status) ─▶ AnalysisService (one grounded call per group, run kind `sync`, cost caps) ─▶ UpdateProposal + items ─▶ DecisionService (accept / reject / regenerate) ─▶ ApplyService (blueprint version kind `update`) ─▶ ProgressRules + LearnerNotice, AuditLog (hash chain, append-only trigger), Notifiervendor/bin/phpunit --testsuite living-course # fake driver, recorded live answers replayedphp artisan living-course:eval --fixtures=all --author=1 # free, fake driverphp artisan living-course:poll # due sources (scheduled every 15 minutes)php artisan living-course:backfill # first revision for existing sessionsSource text is untrusted: it only reaches the model inside a delimited block of the user turn, and
the model’s output is validated against a schema and must cite fragments of the new revision.
Outbound requests use Ulams\Core\Http\SafeHttp. LMS entities change only through the Course
Builder applier and the domain services; tests/Unit/GuardsTest.php enforces this.
API endpoints
Section titled “API endpoints”| Method | Path | Auth | Action |
|---|---|---|---|
GET |
/api/admin/living-course/sessions/{session}/sources |
yes | SourcesController@index |
GET |
/api/admin/living-course/sources/{source}/revisions |
yes | SourcesController@revisions |
POST |
/api/admin/living-course/sources/{source}/revisions |
yes | SourcesController@upload |
GET |
/api/admin/living-course/revisions/{revision} |
yes | SourcesController@revision |
GET |
/api/admin/living-course/sessions/{session}/staleness |
yes | StalenessController@show |
GET |
/api/admin/living-course/sessions/{session}/audit |
yes | AuditController@index |
GET |
/api/admin/living-course/sessions/{session}/audit/export |
yes | AuditController@export |
GET |
/api/admin/living-course/sessions/{session}/audit/verify |
yes | AuditController@verify |
GET |
/api/admin/living-course/audit/export |
yes | AuditController@exportAll |
GET |
/api/admin/living-course/audit/verify |
yes | AuditController@verifyAll |
GET |
/api/admin/living-course/sessions/{session}/proposals |
yes | ProposalsController@index |
GET |
/api/admin/living-course/proposals/{proposal} |
yes | ProposalsController@show |
POST |
/api/admin/living-course/proposals/{proposal}/analyse |
yes | ProposalsController@analyse |
POST |
/api/admin/living-course/proposals/{proposal}/items/{item}/accept |
yes | ProposalsController@accept |
POST |
/api/admin/living-course/proposals/{proposal}/items/{item}/reject |
yes | ProposalsController@reject |
POST |
/api/admin/living-course/proposals/{proposal}/items/{item}/reset |
yes | ProposalsController@reset |
POST |
/api/admin/living-course/proposals/{proposal}/items/{item}/regenerate |
yes | ProposalsController@regenerate |
POST |
/api/admin/living-course/proposals/{proposal}/reanalyse |
yes | ProposalsController@reanalyse |
PUT |
/api/admin/living-course/proposals/{proposal}/learner-note |
yes | ProposalsController@learnerNote |
GET |
/api/admin/living-course/connectors |
yes | ConnectController@connectors |
POST |
/api/admin/living-course/sessions/{session}/sources/connect |
yes | ConnectController@connect |
POST |
/api/admin/living-course/connections/{connection}/check |
yes | ConnectController@check |
POST |
/api/admin/living-course/connections/{connection}/webhook-secret |
yes | ConnectController@rotateSecret |
PUT |
/api/admin/living-course/connections/{connection} |
yes | ConnectionsController@update |
DELETE |
/api/admin/living-course/connections/{connection} |
yes | ConnectionsController@destroy |
POST |
/api/admin/living-course/proposals/{proposal}/apply |
yes | ProposalsController@apply |
POST |
/api/admin/living-course/proposals/{proposal}/accept-all |
yes | ProposalsController@acceptAll |
POST |
/api/admin/living-course/proposals/{proposal}/reject |
yes | ProposalsController@rejectAll |
GET |
/api/admin/living-course/revisions/{revision}/changes |
yes | SourcesController@changes |
GET |
/api/living-course/courses/{course}/notices |
yes | NoticesController@index |
POST |
/api/living-course/notices/{notice}/dismiss |
yes | NoticesController@dismiss |
GET |
/api/living-course/courses/{course}/freshness |
yes | NoticesController@freshness |
POST |
/api/living-course/webhooks/{webhookId} |
WebhookController@receive |
Permissions
Section titled “Permissions”| Permission | Seeded for roles | Constant |
|---|---|---|
living_course_review |
LivingCoursePermissionsEnum::LIVING_COURSE_REVIEW |
Settings
Section titled “Settings”Registered with AdministrableConfig::registerConfig (editable in the admin panel under Configuration → Settings).
None.
Events
Section titled “Events”| Event | Description | Notification templates |
|---|---|---|
CourseContentUpdated |
A learner has new notices after an update. In-app and e-mail, at most one e-mail per course per 7 days. Recipient: the learner. | |
ProposalApplied |
An update proposal was applied to the course (progress rules and notifications follow). | |
SourceCheckFailing |
A connection failed its check three times in a row. In-app and e-mail. Recipient: the session author. | |
SourceRevisionDetected |
A source revision with impact on the course was detected (in-app only). Recipient: the session author. | |
UpdateProposalApplied |
An update proposal was applied (in-app only). Recipient: the session author. | |
UpdateProposalReady |
An update proposal is ready for review or waits for the author to start the analysis. In-app and e-mail. Recipients: the session author and the course authors who may review. |
Notification templates registered here
Section titled “Notification templates registered here”None.
Artisan commands
Section titled “Artisan commands”| Command | Description | Signature |
|---|---|---|
living-course:backfill |
Record revision 1 for sources built before Living Course existed (idempotent) | living-course:backfill {--session= : Only this builder session id} |
living-course:eval |
Evaluate Living Course update proposals on golden v1/v2 fixtures (fake driver by default, –live for the real model) | living-course:eval {--fixtures=all : all, or a comma list of coffee, git, injection} {--live : call the real model for the update analysis} {--record : write cassettes (tests/cassettes) from this run} {--author= : user id that owns the eval sessions (default: the first admin)} {--max-usd=1 : total spend cap of a live run} |
living-course:poll |
Check the connected sources that are due and prune old webhook deliveries | living-course:poll |
Scheduled jobs
Section titled “Scheduled jobs”| Kind | Target | Frequency |
|---|---|---|
| command | 'living-course:poll' |
everyFifteenMinutes()->withoutOverlapping()) |
Environment variables read
Section titled “Environment variables read”LIVING_COURSE_ALLOWED_HOSTS, LIVING_COURSE_AUTO_ANALYSE_USD, LIVING_COURSE_CONNECTORS, LIVING_COURSE_INSECURE_HOSTS, LIVING_COURSE_LEARNER_NOTICE_AFTER_DAYS, LIVING_COURSE_MAX_FRAGMENTS, LIVING_COURSE_MAX_GROUPS, LIVING_COURSE_MIN_POLL_MINUTES, LIVING_COURSE_PROPOSAL_COST_USD, LIVING_COURSE_QUEUE, LIVING_COURSE_QUEUE_CONNECTION, LIVING_COURSE_SOURCE_MONTHLY_USD, LIVING_COURSE_WEBHOOK_DEBOUNCE_SECONDS, QUEUE_CONNECTION