gitsheets v1.2.0 added content-typed records — sheets opt into format.type = 'markdown' to store records as .md files with TOML frontmatter and a designated body field. Plus lazy body loading via query({ withBody: false }).
This is the biggest one-time upgrade we'd take from the gitsheets 1.x line. Not urgent — defer to after cutover-prep ships so we're not refactoring entities mid-migration.
Why migrate
- Snapshot is actually-readable. Contributors cloning
codeforphilly-data-snapshot see real .md files in any markdown viewer — instead of parsing TOML records to find the prose.
- Authoring via PR. Staff / maintainers can edit a project overview in any markdown editor and PR it; currently they roundtrip through the API.
- Listing performance.
queryAll({ withBody: false }) on hot paths: projects-index, activity feed, FTS seeding, snapshot scrub.
- Indexes stay fast. Index builds use body-less reads natively in v1.2.
What changes
Entities with substantial body content:
Project — overview (markdown body), summary (short markdown) → migrate overview as the body field, keep summary in frontmatter
ProjectUpdate — body (markdown) → migrate body as the body field
ProjectBuzz — summary (markdown) → migrate as body
Person — bio (markdown) → migrate as body
HelpWantedRole — description (markdown) → migrate as body
Tag — description (markdown, short) → optional; cheaper to leave as TOML field
The migration is bounded; entities without long bodies (ProjectMembership, SlugHistory, Revocation, TagAssignment, HelpWantedInterestExpression) stay as TOML records.
Tasks
- Schema reshape in
packages/shared/src/schemas/ — one designated body field per content-typed entity (rename or restructure the existing overview / body / bio / description / summary fields).
- Update
.gitsheets/<sheet>.toml configs with [gitsheet.format] type = 'markdown' body = '<fieldName>'.
- In-memory loader in
apps/api/src/store/memory/loader.ts — use { withBody: false } for index-building reads; lazy-load via Sheet.loadBody(record) when serving record detail responses.
- Serializers in
apps/api/src/services/serializers/ — *Html / *Excerpt derived from the body field instead of the legacy string field.
- FTS pipeline in
apps/api/src/store/fts.ts — body included in the indexed text via lazy-load batch.
apps/api/scripts/import-laddr.ts — write the new markdown format for migrated entities.
apps/api/scripts/scrub-data.ts — the snapshot now contains real .md files; verify the scrub still strips PII correctly across the new file shape.
- The data repo's existing TOML records need migration once — write a one-shot
apps/api/scripts/migrate-to-content-typed.ts that reads existing records and rewrites as .md per the new format.
- Update
specs/behaviors/markdown-rendering.md and specs/data-model.md to reflect content-typed entities.
Why defer
cutover-prep is next and depends on every other plan; this would invalidate frozen plans (storage-foundation, read-api, write-api, laddr-import, public-snapshot-scrub).
- The benefit is real but landing is post-cutover work, not pre-cutover refactor.
Out of scope
gitsheets check pre-commit hooks belong in the data repo, not this code repo.
- The bundled Claude Code skill at
node_modules/gitsheets/skills/gitsheets/ is available once we bump the dep range; future plans touching gitsheets can load it.
gitsheets v1.2.0 added content-typed records — sheets opt into
format.type = 'markdown'to store records as.mdfiles with TOML frontmatter and a designated body field. Plus lazy body loading viaquery({ withBody: false }).This is the biggest one-time upgrade we'd take from the gitsheets 1.x line. Not urgent — defer to after
cutover-prepships so we're not refactoring entities mid-migration.Why migrate
codeforphilly-data-snapshotsee real.mdfiles in any markdown viewer — instead of parsing TOML records to find the prose.queryAll({ withBody: false })on hot paths: projects-index, activity feed, FTS seeding, snapshot scrub.What changes
Entities with substantial body content:
Project—overview(markdown body),summary(short markdown) → migrateoverviewas the body field, keepsummaryin frontmatterProjectUpdate—body(markdown) → migratebodyas the body fieldProjectBuzz—summary(markdown) → migrate as bodyPerson—bio(markdown) → migrate as bodyHelpWantedRole—description(markdown) → migrate as bodyTag—description(markdown, short) → optional; cheaper to leave as TOML fieldThe migration is bounded; entities without long bodies (
ProjectMembership,SlugHistory,Revocation,TagAssignment,HelpWantedInterestExpression) stay as TOML records.Tasks
packages/shared/src/schemas/— one designated body field per content-typed entity (rename or restructure the existingoverview/body/bio/description/summaryfields)..gitsheets/<sheet>.tomlconfigs with[gitsheet.format] type = 'markdown' body = '<fieldName>'.apps/api/src/store/memory/loader.ts— use{ withBody: false }for index-building reads; lazy-load viaSheet.loadBody(record)when serving record detail responses.apps/api/src/services/serializers/—*Html/*Excerptderived from the body field instead of the legacy string field.apps/api/src/store/fts.ts— body included in the indexed text via lazy-load batch.apps/api/scripts/import-laddr.ts— write the new markdown format for migrated entities.apps/api/scripts/scrub-data.ts— the snapshot now contains real.mdfiles; verify the scrub still strips PII correctly across the new file shape.apps/api/scripts/migrate-to-content-typed.tsthat reads existing records and rewrites as.mdper the new format.specs/behaviors/markdown-rendering.mdandspecs/data-model.mdto reflect content-typed entities.Why defer
cutover-prepis next and depends on every other plan; this would invalidate frozen plans (storage-foundation,read-api,write-api,laddr-import,public-snapshot-scrub).Out of scope
gitsheets checkpre-commit hooks belong in the data repo, not this code repo.node_modules/gitsheets/skills/gitsheets/is available once we bump the dep range; future plans touching gitsheets can load it.