Repository source: docs/plans/activity_source_filename_commit_plan_v1.md
Activity Source Filename And Commit Plan
Feasibility
Yes. Activity rows already come from canonical repository records, so each item can be given a deterministic source filename and, when the canonical repository is a git checkout, the commit SHA that last introduced or changed that source file.
The implementation should store this metadata in the read model during full rebuilds and incremental updates. The activity page should not run git commands per request.
Current State
/activity/renderstemplates/pages/activity.phpwith items fromApplication::fetchActivity().Activity rows are stored in the SQLite
activitytable.Full read-model rebuild inserts activity in
ReadModelBuilder::indexActivity().Incremental post writes insert activity in
IncrementalReadModelUpdater::insertActivity().Incremental thread-label writes rebuild label activity in
IncrementalReadModelUpdater::refreshThreadLabelActivity().Post records have deterministic paths through
CanonicalPathResolver::post($postId).Thread-label activity currently loses the source
ThreadLabelRecord::recordIdbefore insertion, so it cannot yet deriverecords/thread-labels/<record-id>.txtat render time.
Proposed Data Contract
Add nullable columns to activity:
source_path TEXT NULL: repository-relative canonical filename, for examplerecords/posts/root-001.txt.source_commit_sha TEXT NULL: full git commit SHA for the source file, orno-git/git-erroronly if the repository cannot provide a value.
For first implementation:
thread and reply items use
records/posts/<post-id>.txt;identity/bootstrap/approval items are still post activity rows, so they use the same post path;
thread label items use
records/thread-labels/<record-id>.txtafter preserving the label record id in the activity event model.
Implementation Plan
Stage 1: Read-model schema and source path plumbing
Bump
ReadModelMetadata::SCHEMA_VERSION.Add
source_pathandsource_commit_shato theactivitytable inReadModelBuilder.Extend
ReadModelBuilder::indexPosts()to keep each post'ssource_pathfrom the scanned relative path.Extend thread-label activity event arrays in
ReadModelBuilder::indexThreadLabels()to includesource_pathusingCanonicalPathResolver::threadLabel($record->recordId).Extend matching PHPDoc array shapes so the source metadata is explicit.
Status: Implemented in the Stage 1 commit. Schema version bumped to 10; full rebuild activity rows now carry canonical source paths and nullable source commit fields.
Stage 2: Commit SHA resolution
Add a small helper for read-model indexing, likely in
ReadModelBuilderfirst:input: repository-relative path;
output:
git log -1 --format=%H -- <path>result;fallback:
no-gitwhen.gitis absent,git-errorwhen git fails, ornullif the path has no history.
Use the helper while inserting full-rebuild activity rows.
Keep this out of
Application::fetchActivity()and templates.Consider caching path-to-SHA results during a rebuild so duplicate path lookups do not repeat git commands.
Status: Implemented in the Stage 2 commit.
ReadModelBuildernow caches source-path git lookups and writessource_commit_shaduring full rebuilds.
Stage 3: Incremental update support
In
IncrementalReadModelUpdater::insertActivity(), set:source_pathtoCanonicalPathResolver::post($record->postId);source_commit_shato the$commitShapassed to the current write update.
In
computeThreadLabelState(), include the thread-labelrecord_idorsource_pathin each activity event.In
refreshThreadLabelActivity(), setsource_pathtoCanonicalPathResolver::threadLabel($recordId)andsource_commit_shato the$commitShafromapplyThreadLabelWrite().Update the method signatures/PHPDocs as needed so the commit SHA can be passed into the refresh method.
Status: Implemented in the Stage 3 commit. Incremental post, approval, bootstrap, and thread-label activity inserts now populate source metadata.
Stage 4: Activity rendering
Select
activity.source_pathandactivity.source_commit_shainApplication::fetchActivity().Include them in the mapped item array.
Render a compact metadata line in
templates/pages/activity.php, for example:Source: records/posts/root-001.txt @ abc1234
Display a shortened hash in the UI, but keep the full hash available in a
titleattribute or equivalent text if existing style allows.Omit the line when both values are empty/null.
Decide whether RSS descriptions should include the source line. My recommendation is to include it only in HTML for the first slice, then add RSS if needed.
Status: Implemented in the Stage 4 commit. HTML activity cards now render
Source:with a canonical filename, shortened commit hash, and full hash intitlewhen available.
Stage 5: Tests and verification
Update
LocalAppSmokeTestactivity assertions to expect source filename text for a post item and a thread-label item.Add or extend a test with a real git-backed temp repository so at least one activity row has a real commit SHA.
Add no-git coverage using the existing fixture path expectations, since local smoke tests currently expect
no-gitfor app version.Run:
php -l src/ForumRewrite/ReadModel/ReadModelMetadata.phpphp -l src/ForumRewrite/ReadModel/ReadModelBuilder.phpphp -l src/ForumRewrite/ReadModel/IncrementalReadModelUpdater.phpphp -l src/ForumRewrite/Application.phpphp -l templates/pages/activity.phpphp tests/run.php
Status: Implemented in the Stage 5 commit. Smoke coverage now checks post and thread-label filenames, no-git unavailable display, schema version 10, and a real git-backed source commit hash. Verification passed with the planned syntax checks and
php tests/run.php.
Risks And Decisions
Full rebuild git lookups may be slow on large repositories if done one path at a time. Cache results at minimum; batch lookup can be considered later if profiling shows a problem.
source_commit_shaneeds a clear meaning. This plan uses the latest commit touching the source file for rebuilds, and the write commit SHA for incremental writes.Production hotfix note: full rebuilds now use the repository head for rebuilt source rows instead of running one
git logper source file. This keeps file-at-commit links valid for current canonical files and avoids holding the global execution lock across many per-file git scans during deploy-time schema rebuilds. Incremental writes still use the exact write commit SHA.Thread-label activity needs extra source metadata before insertion. Without preserving
recordId, label items can only point to the thread, not to the canonical label record.In no-git fixture environments, the UI should avoid presenting
no-gitas a real commit hash. A label likecommit unavailableis preferable if the value isno-git,git-error, or null.
Approval Gate
Pause here until this plan is approved. After approval, implement in slices with schema/read-model changes first, then rendering and tests.