From 0c77feb0dce54fc473e0e4ea8330bb285f152695 Mon Sep 17 00:00:00 2001 From: Barry S Stahl Date: Sun, 23 Aug 2026 14:26:37 -0700 Subject: [PATCH] Fix all markdownlint violations across repo docs - Replace dash bullet style with asterisk across all .md files (MD004) - Add blank lines after headings in CONTEXT.md (MD022) - Add blank lines before and after lists in CONTEXT.md (MD032) - Remove double blank line in docs/ADRs.md (MD012) - All 275 issues resolved; markdownlint now reports 0 issues Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .vscode/settings.json | 6 ++ CONTEXT.md | 149 ++++++++++++++++++-------- README.md | 54 +++++----- docs/ADRs.md | 51 +++++---- docs/Integration-Strategy.md | 106 +++++++++--------- docs/TalkSchema.md | 202 +++++++++++++++++------------------ 6 files changed, 315 insertions(+), 253 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d352eba --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "chat.tools.terminal.autoApprove": { + "git checkout": true, + "npx markdownlint-cli2": true + } +} \ No newline at end of file diff --git a/CONTEXT.md b/CONTEXT.md index c417e8e..c6cf58d 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -3,96 +3,153 @@ Glossary-only domain language for TalkFolio. This file records canonical terms and invariants, not implementation details. ## Term: Talk + Definition: A speakable concept, independent of any specific slide deck, conference submission, or delivery event. Owns: title, proposal copy, target audience, tags, category, PresentationFamily membership, concept lifecycle, talk-level flags, and references to built decks or companion material. Distinguish from: LiquidVictor SlideDeck, TalkCircuit Submission, SlideFed PresentationSession. Invariants: -- A Talk may exist before any deck exists. -- A Talk may reference zero or more LiquidVictor `SlideDeck.Id` values. -- A Talk may have multiple alternate titles or marketing variants. -- `Id` values are GUIDs. -- Talk-level flags are stored in a flexible `Flags` key-value map. + +* A Talk may exist before any deck exists. + +* A Talk may reference zero or more LiquidVictor `SlideDeck.Id` values. + +* A Talk may have multiple alternate titles or marketing variants. + +* `Id` values are GUIDs. + +* Talk-level flags are stored in a flexible `Flags` key-value map. ## Term: Category + Definition: A single top-level topic grouping used as the starting point for browsing and CFP selection. Values: Agile, Algorithms, Language Models, Leadership & Community, Software Engineering. Invariants: -- Exactly one Category per Talk. -- Category is intentionally coarse. -- Category is maintained as a controlled list that can expand over time. -- Cross-cutting topic nuance belongs in Tags, not nested category trees. + +* Exactly one Category per Talk. + +* Category is intentionally coarse. + +* Category is maintained as a controlled list that can expand over time. + +* Cross-cutting topic nuance belongs in Tags, not nested category trees. ## Term: Tags + Definition: A many-to-many set of topical labels used for discovery, CFP fit, and cross-cutting classification. Invariants: -- A Talk may have any number of Tags. -- Tags should capture overlap that a single Category cannot. -- Tags are free-form strings constrained to alphanumerics and `-` with no whitespace. -- Conference-specific tag mapping is not owned here; TalkCircuit maps TalkFolio Tags to a conference's allowed vocabulary. + +* A Talk may have any number of Tags. + +* Tags should capture overlap that a single Category cannot. + +* Tags are free-form strings constrained to alphanumerics and `-` with no whitespace. + +* Conference-specific tag mapping is not owned here; TalkCircuit maps TalkFolio Tags to a conference's allowed vocabulary. ## Term: TargetAudience + Definition: The intended audience for the Talk, expressed as a set of human-readable values from the TalkFolio vocabulary. Invariants: -- A Talk may have zero or many TargetAudience values. -- TargetAudience values are strings drawn from a controlled list that can expand over time. -- This is intentionally simpler than a deeply structured audience model unless the repo later decides to add richer segmentation. + +* A Talk may have zero or many TargetAudience values. + +* TargetAudience values are strings drawn from a controlled list that can expand over time. + +* This is intentionally simpler than a deeply structured audience model unless the repo later decides to add richer segmentation. ## Term: Flags + Definition: A flexible map of talk-level metadata flags. Invariants: -- Each flag is a key-value pair. -- The map is intended for extension without changing the core talk schema. -- Examples include `Locked`, `ForKids`, and `HandsOn`. + +* Each flag is a key-value pair. + +* The map is intended for extension without changing the core talk schema. + +* Examples include `Locked`, `ForKids`, and `HandsOn`. ## Term: PresentationFamily + Definition: A grouping of Talks or variants that are fundamentally the same presentation idea with different branding, format, or emphasis. Invariants: -- PresentationFamily is not a taxonomy node. -- Talks in the same PresentationFamily should not be co-submitted to the same conference. -- TalkCircuit enforces the no-duplicate-family rule at submission time. -- The Talk owns the family relationship via a nested `PresentationFamily` object (`Id` + `Variant`); the family entity does not list its members. -- `Variant` identifies the talk's role in the family (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`). -- A family is not required to have a canonical talk; when one exists, it is expressed as a `Variant` value, not a structural field on the family. + +* PresentationFamily is not a taxonomy node. + +* Talks in the same PresentationFamily should not be co-submitted to the same conference. + +* TalkCircuit enforces the no-duplicate-family rule at submission time. + +* The Talk owns the family relationship via a nested `PresentationFamily` object (`Id` + `Variant`); the family entity does not list its members. + +* `Variant` identifies the talk's role in the family (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`). + +* A family is not required to have a canonical talk; when one exists, it is expressed as a `Variant` value, not a structural field on the family. ## Term: LifecycleStatus + Definition: The concept-level state of a Talk. Canonical states: Ideation, Active, Retired. Invariants: -- Ideation means the talk idea exists but may not have proposal copy or a deck yet. -- Active means the talk is available for submission or delivery. -- Retired means the talk concept should no longer be offered. -- Deck construction status is not represented here; that belongs to LiquidVictor. + +* Ideation means the talk idea exists but may not have proposal copy or a deck yet. + +* Active means the talk is available for submission or delivery. + +* Retired means the talk concept should no longer be offered. + +* Deck construction status is not represented here; that belongs to LiquidVictor. ## Term: Proposal Copy + Definition: Text used to pitch a Talk to conferences or selection committees. Examples: abstract, short version, elevator pitch, memo to selection committee, key takeaways, target audience. Invariants: -- Proposal copy belongs to TalkFolio, even when it is later submitted through TalkCircuit. -- Conference-specific submitted versions may be captured by TalkCircuit as submission snapshots. -- ProposalCopyItems.Copy is intentionally unstructured prose; all other fields should be structured unless they are explicitly narrative/context fields. + +* Proposal copy belongs to TalkFolio, even when it is later submitted through TalkCircuit. + +* Conference-specific submitted versions may be captured by TalkCircuit as submission snapshots. + +* ProposalCopyItems.Copy is intentionally unstructured prose; all other fields should be structured unless they are explicitly narrative/context fields. ## Term: SlideDeckIds + Definition: References from a Talk to one or more built LiquidVictor decks. Invariants: -- Values are LiquidVictor `SlideDeck.Id` GUIDs. -- TalkFolio holds these references; LiquidVictor does not reference TalkFolio. -- A Talk in Ideation may have no SlideDeckIds. + +* Values are LiquidVictor `SlideDeck.Id` GUIDs. + +* TalkFolio holds these references; LiquidVictor does not reference TalkFolio. + +* A Talk in Ideation may have no SlideDeckIds. ## Term: PublicPresentationReference + Definition: Optional reference to a public or federated presentation resource exposed by SlideFed or another publication surface. Invariants: -- This is a pointer for catalog/display purposes. -- SlideFed owns the federated resource and its ActivityPub semantics. + +* This is a pointer for catalog/display purposes. + +* SlideFed owns the federated resource and its ActivityPub semantics. ## Term: RelatedContent + Definition: Companion material associated with a Talk, such as blog posts, videos, articles, essays, or notebooks, referenced for discovery, navigation, and finding material tied to a talk. Invariants: -- Related content is associated with the Talk concept, not with a specific LiquidVictor SlideDeck. -- One Talk may have zero or many RelatedContent entries. -- More than one RelatedContent item of the same type is allowed. -- Each item has a `Type`, a `Title`, an optional `Url`, and `Notes`. -- A RelatedContent item has no separate `Id`; when present, `Url` is the canonical identifier. -- `Notes` is the primary field for a brief explanation of the relationship to the talk, stored as a `|-` literal block. -- Related content may live in another domain such as CognitiveInheritance, outside the TalkFolio repo; TalkFolio stores only the lightweight reference and relationship. -- RelatedContent is a lightweight relationship model, not a content-management system or publication workflow; the content lifecycle remains with the domain that owns the content. -- `Summary`, `Status`, and `PublishedAt` are intentionally not part of this concept because those belong to the domain that owns the content lifecycle. + +* Related content is associated with the Talk concept, not with a specific LiquidVictor SlideDeck. + +* One Talk may have zero or many RelatedContent entries. + +* More than one RelatedContent item of the same type is allowed. + +* Each item has a `Type`, a `Title`, an optional `Url`, and `Notes`. + +* A RelatedContent item has no separate `Id`; when present, `Url` is the canonical identifier. + +* `Notes` is the primary field for a brief explanation of the relationship to the talk, stored as a `|-` literal block. + +* Related content may live in another domain such as CognitiveInheritance, outside the TalkFolio repo; TalkFolio stores only the lightweight reference and relationship. + +* RelatedContent is a lightweight relationship model, not a content-management system or publication workflow; the content lifecycle remains with the domain that owns the content. + +* `Summary`, `Status`, and `PublishedAt` are intentionally not part of this concept because those belong to the domain that owns the content lifecycle. diff --git a/README.md b/README.md index 339d00e..bf27449 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,15 @@ All contributors and users are expected to follow the [Strict Accountability Pol TalkFolio owns: -- talk concepts and their canonical identities -- abstracts, elevator pitches, short versions, and selection-committee language -- target audience descriptions -- alternate titles and marketing variants -- Category and Tags used for discovery and CFP fit -- PresentationFamily grouping -- concept-level lifecycle (`Ideation`, `Active`, `Retired`) -- references to built LiquidVictor decks that fulfill a talk concept -- optional references to published SlideFed resources that represent public/federated versions of a talk +* talk concepts and their canonical identities +* abstracts, elevator pitches, short versions, and selection-committee language +* target audience descriptions +* alternate titles and marketing variants +* Category and Tags used for discovery and CFP fit +* PresentationFamily grouping +* concept-level lifecycle (`Ideation`, `Active`, `Retired`) +* references to built LiquidVictor decks that fulfill a talk concept +* optional references to published SlideFed resources that represent public/federated versions of a talk TalkFolio does not own slide construction, Fediverse publication mechanics, or conference-submission state. @@ -36,18 +36,18 @@ TalkFolio does not own slide construction, Fediverse publication mechanics, or c Initial TalkFolio data should be migrated from: -- `C:\s\r\CognitiveInheritance\Pages\Talk-Catalog.md` -- `C:\s\r\bss-notes\Community\Presentations\**` -- `C:\s\r\bss-notes\Community\Presentations\README.md` +* `C:\s\r\CognitiveInheritance\Pages\Talk-Catalog.md` +* `C:\s\r\bss-notes\Community\Presentations\**` +* `C:\s\r\bss-notes\Community\Presentations\README.md` The per-talk notes are especially valuable for abstracts, elevator pitches, audience notes, outlines, alternate titles, and rough ideation material. ## Additional Docs -- [TalkFolio Context](CONTEXT.md) -- [TalkFolio Integration Strategy](docs/Integration-Strategy.md) -- [TalkFolio Schema Direction](docs/TalkSchema.md) -- [Architecture Decision Records](docs/ADRs.md) +* [TalkFolio Context](CONTEXT.md) +* [TalkFolio Integration Strategy](docs/Integration-Strategy.md) +* [TalkFolio Schema Direction](docs/TalkSchema.md) +* [Architecture Decision Records](docs/ADRs.md) ## Feature Candidates @@ -73,20 +73,20 @@ The per-talk notes are especially valuable for abstracts, elevator pitches, audi The recommended MVP should include: -- file-based Talk and PresentationFamily records that match the documented schema -- validation tooling for schema and cross-record relationships -- migration tooling to pull structured data from the existing notes sources -- basic catalog commands or reports for listing and filtering talks +* file-based Talk and PresentationFamily records that match the documented schema +* validation tooling for schema and cross-record relationships +* migration tooling to pull structured data from the existing notes sources +* basic catalog commands or reports for listing and filtering talks The MVP should explicitly defer: -- controlled vocabulary source files for Category and TargetAudience -- TalkCircuit-friendly export/read model for proposal submission workflows -- rich editing UI -- authoring scaffolds unless they fall out cheaply from the file format work -- automated external sync -- submission-state workflows -- publication/content-management workflows outside TalkFolio's boundary +* controlled vocabulary source files for Category and TargetAudience +* TalkCircuit-friendly export/read model for proposal submission workflows +* rich editing UI +* authoring scaffolds unless they fall out cheaply from the file format work +* automated external sync +* submission-state workflows +* publication/content-management workflows outside TalkFolio's boundary ## Status diff --git a/docs/ADRs.md b/docs/ADRs.md index 0f4d3a2..36191cd 100644 --- a/docs/ADRs.md +++ b/docs/ADRs.md @@ -8,8 +8,8 @@ This document consolidates the design decisions reached for TalkFolio. Each entr **Decision:** Proposal copy lives inline on the Talk record as `ProposalCopyItems`, a list of typed items, each with: -- `Type`: the copy classification (for example `Abstract`, `ElevatorPitch`, `ShortVersion`, `CommitteeNotes`, `AudienceNotes`, `AlternateTitleCandidates`) -- `Copy`: the proposal text stored as a YAML `|-` literal block +* `Type`: the copy classification (for example `Abstract`, `ElevatorPitch`, `ShortVersion`, `CommitteeNotes`, `AudienceNotes`, `AlternateTitleCandidates`) +* `Copy`: the proposal text stored as a YAML `|-` literal block **Rationale:** A typed array keeps proposal text extensible — new copy types can be introduced without changing the Talk schema — while keeping the copy inline on the record for a straightforward model. @@ -21,17 +21,17 @@ This document consolidates the design decisions reached for TalkFolio. Each entr **Decision:** The Talk schema includes a `RelatedContent` list of typed companion items, each with: -- `Type` (for example `BlogPost`, `Video`, `Article`, `Essay`, `Notebook`) -- `Title` -- `Url` (optional) -- `Notes` +* `Type` (for example `BlogPost`, `Video`, `Article`, `Essay`, `Notebook`) +* `Title` +* `Url` (optional) +* `Notes` **Rules:** -- RelatedContent is associated with the Talk concept, not with a specific LiquidVictor SlideDeck. -- Multiple items of the same `Type` are allowed. -- A RelatedContent item has no separate `Id`; when present, `Url` is the canonical identifier. -- `Summary`, `Status`, and `PublishedAt` are intentionally excluded. +* RelatedContent is associated with the Talk concept, not with a specific LiquidVictor SlideDeck. +* Multiple items of the same `Type` are allowed. +* A RelatedContent item has no separate `Id`; when present, `Url` is the canonical identifier. +* `Summary`, `Status`, and `PublishedAt` are intentionally excluded. **Rationale:** TalkFolio needs a generic way to reference companion material for discovery, navigation, and finding content tied to a talk, without becoming a content-management system. The content lifecycle remains in the domain that owns the content (for example, CognitiveInheritance for blog posts), which may live outside the TalkFolio repo. @@ -43,9 +43,9 @@ This document consolidates the design decisions reached for TalkFolio. Each entr **Decision:** PresentationFamily remains a separate entity, but the relationship is owned by the Talk: -- Each Talk carries a nested `PresentationFamily` object with `Id` and `Variant` (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`). A talk with no family omits the object. -- The PresentationFamily entity is just `Id`, `Name`, and `Notes`; it does not list members. Membership is discovered by querying Talks by `PresentationFamily.Id`. -- `CanonicalTalkId` is removed. A family is not required to have a canonical talk; when one exists, "canonical" is a `Variant` value on the Talk, not a structural field on the family. +* Each Talk carries a nested `PresentationFamily` object with `Id` and `Variant` (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`). A talk with no family omits the object. +* The PresentationFamily entity is just `Id`, `Name`, and `Notes`; it does not list members. Membership is discovered by querying Talks by `PresentationFamily.Id`. +* `CanonicalTalkId` is removed. A family is not required to have a canonical talk; when one exists, "canonical" is a `Variant` value on the Talk, not a structural field on the family. **Rationale:** Single-direction ownership matches the existing Talk → SlideDeckIds reference pattern and avoids duplicated references (Talk → family and family → talks) drifting out of sync. Variant identity belongs to the talk, and canonical status is a classification, not structure. Encapsulating `Id` and `Variant` in one object keeps family membership cohesive rather than flat fields on the Talk root. @@ -117,10 +117,10 @@ This document consolidates the design decisions reached for TalkFolio. Each entr **Decision:** TalkFolio keeps the model structured wherever reasonable. The only intentionally unstructured Talk fields are the narrative/context fields used for authored prose and commentary: -- `ProposalCopyItems[].Copy` -- `IdeationNotes` -- `PresentationFamily.Notes` -- `RelatedContent[].Notes` +* `ProposalCopyItems[].Copy` +* `IdeationNotes` +* `PresentationFamily.Notes` +* `RelatedContent[].Notes` **Rationale:** Structured fields improve consistency, filtering, and downstream tooling. The remaining prose fields exist specifically to preserve authored language, explanatory context, and editorial notes that do not fit cleanly into a rigid structure. @@ -134,10 +134,10 @@ This document consolidates the design decisions reached for TalkFolio. Each entr **Rules:** -- The initial persistence adapter may be file-based and YAML-backed. -- Application and domain logic depend on repository contracts, not on file-system details. -- The canonical identity of a Talk or PresentationFamily remains its `Id`, not its file name or path. -- Swapping the file-based adapter for a database-backed adapter should not require redesigning the domain model. +* The initial persistence adapter may be file-based and YAML-backed. +* Application and domain logic depend on repository contracts, not on file-system details. +* The canonical identity of a Talk or PresentationFamily remains its `Id`, not its file name or path. +* Swapping the file-based adapter for a database-backed adapter should not require redesigning the domain model. **Rationale:** TalkFolio wants a file-based MVP, but it should not couple the rest of the product to that storage choice. A repository boundary keeps the model portable and makes future storage changes, such as moving to a database, far easier. @@ -151,14 +151,13 @@ This document consolidates the design decisions reached for TalkFolio. Each entr **Rules:** -- Production-like or maintained talk catalogs should not be assumed to live inside this repo. -- The implementation must accept a configurable data root rather than hard-coding a repository-local path. -- This repo may include dedicated test repositories or fixture datasets for automated tests, local development, and validation scenarios. -- The test datasets exist to support product validation, not to define the long-term location of maintained catalog data. +* Production-like or maintained talk catalogs should not be assumed to live inside this repo. +* The implementation must accept a configurable data root rather than hard-coding a repository-local path. +* This repo may include dedicated test repositories or fixture datasets for automated tests, local development, and validation scenarios. +* The test datasets exist to support product validation, not to define the long-term location of maintained catalog data. **Rationale:** The product code and the talk catalog have different lifecycles. Keeping the maintained catalog generally external preserves independent versioning and reduces coupling between implementation work and content maintenance. - ## ADR-013: Configuration uses standard .NET precedence with in-memory overrides at the top **Status:** Decided diff --git a/docs/Integration-Strategy.md b/docs/Integration-Strategy.md index b83c682..09585d5 100644 --- a/docs/Integration-Strategy.md +++ b/docs/Integration-Strategy.md @@ -34,9 +34,9 @@ SlideDeckIds: Rules: -- LiquidVictor remains the source of truth for deck structure and build-time presentation metadata. -- TalkFolio never writes fields back into LiquidVictor YAML. -- A Talk may have zero decks, one deck, or multiple format-specific decks. +* LiquidVictor remains the source of truth for deck structure and build-time presentation metadata. +* TalkFolio never writes fields back into LiquidVictor YAML. +* A Talk may have zero decks, one deck, or multiple format-specific decks. ## SlideFed @@ -44,9 +44,9 @@ TalkFolio may store public URLs or federated identifiers produced by SlideFed fo Rules: -- SlideFed owns ActivityPub/ActivityStreams resources and session interaction. -- TalkFolio treats SlideFed identifiers as external publication references. -- TalkFolio does not model session lifecycle, follows, annotations, or federation delivery. +* SlideFed owns ActivityPub/ActivityStreams resources and session interaction. +* TalkFolio treats SlideFed identifiers as external publication references. +* TalkFolio does not model session lifecycle, follows, annotations, or federation delivery. ## TalkCircuit @@ -54,18 +54,18 @@ TalkCircuit consumes TalkFolio data when preparing submissions. TalkCircuit needs from TalkFolio: -- Talk identity -- current LifecycleStatus -- Category and Tags -- PresentationFamily membership -- proposal copy -- references to built decks when available +* Talk identity +* current LifecycleStatus +* Category and Tags +* PresentationFamily membership +* proposal copy +* references to built decks when available Rules: -- TalkCircuit owns submission and booking state. -- TalkCircuit may snapshot proposal copy at submission time, because submitted wording can diverge from the current catalog text. -- TalkCircuit enforces the rule that two Talks from the same PresentationFamily are not submitted to the same conference, finding a talk's family members by querying Talks that share its `PresentationFamily.Id`. +* TalkCircuit owns submission and booking state. +* TalkCircuit may snapshot proposal copy at submission time, because submitted wording can diverge from the current catalog text. +* TalkCircuit enforces the rule that two Talks from the same PresentationFamily are not submitted to the same conference, finding a talk's family members by querying Talks that share its `PresentationFamily.Id`. ## Related Content @@ -73,17 +73,17 @@ TalkFolio stores lightweight references to companion material (blog posts, video Rules: -- RelatedContent is associated with the Talk concept, not with a specific LiquidVictor deck. -- Some associated material lives outside the TalkFolio repo (for example, blog posts in CognitiveInheritance) and is still linked from the Talk by type, title, URL, and notes. -- The owning domain retains the content lifecycle; TalkFolio never models publication state, summaries, or dates for related content. +* RelatedContent is associated with the Talk concept, not with a specific LiquidVictor deck. +* Some associated material lives outside the TalkFolio repo (for example, blog posts in CognitiveInheritance) and is still linked from the Talk by type, title, URL, and notes. +* The owning domain retains the content lifecycle; TalkFolio never models publication state, summaries, or dates for related content. ## Migration Sources Initial import candidates: -- `C:\s\r\CognitiveInheritance\Pages\Talk-Catalog.md` -- `C:\s\r\bss-notes\Community\Presentations\README.md` -- `C:\s\r\bss-notes\Community\Presentations\**\*.md` +* `C:\s\r\CognitiveInheritance\Pages\Talk-Catalog.md` +* `C:\s\r\bss-notes\Community\Presentations\README.md` +* `C:\s\r\bss-notes\Community\Presentations\**\*.md` Expected migration mapping: @@ -100,16 +100,16 @@ Expected migration mapping: ## Decisions Made -- Should proposal copy be stored inline in Talk records or as separate markdown files? See [ADR-001](ADRs.md#adr-001-proposal-copy-is-stored-inline-as-a-typed-array). -- Should the product couple itself directly to a file-based store? See [ADR-011](ADRs.md#adr-011-storage-access-occurs-through-repository-abstractions). -- Should the maintained file-backed catalog live in this repo? See [ADR-012](ADRs.md#adr-012-file-backed-data-roots-are-configurable-and-generally-external-to-this-repo). -- Should Talk identities be GUIDs, slugs, or both? See [ADR-005](ADRs.md#adr-005-talk-ids-use-guids). -- Should Tags be controlled by a repo-local vocabulary file or free-form strings? See [ADR-006](ADRs.md#adr-006-tags-are-free-form-string-tokens-constrained-to-alphanumerics-and-dash). -- Should Category remain fixed, or be a controlled list that can expand? See [ADR-007](ADRs.md#adr-007-category-uses-a-controlled-extensible-list). -- Should TargetAudience be structured or a list of strings? See [ADR-008](ADRs.md#adr-008-targetaudience-uses-a-controlled-extensible-list-of-strings). -- How should extra talk metadata flags be modeled? See [ADR-009](ADRs.md#adr-009-extra-talk-metadata-flags-use-a-flexible-key-value-map). -- Which fields should remain unstructured? See [ADR-010](ADRs.md#adr-010-only-narrative-context-fields-remain-unstructured). -- How much of the existing `bss-notes` prose should remain freeform versus structured? See [ADR-010](ADRs.md#adr-010-only-narrative-context-fields-remain-unstructured). +* Should proposal copy be stored inline in Talk records or as separate markdown files? See [ADR-001](ADRs.md#adr-001-proposal-copy-is-stored-inline-as-a-typed-array). +* Should the product couple itself directly to a file-based store? See [ADR-011](ADRs.md#adr-011-storage-access-occurs-through-repository-abstractions). +* Should the maintained file-backed catalog live in this repo? See [ADR-012](ADRs.md#adr-012-file-backed-data-roots-are-configurable-and-generally-external-to-this-repo). +* Should Talk identities be GUIDs, slugs, or both? See [ADR-005](ADRs.md#adr-005-talk-ids-use-guids). +* Should Tags be controlled by a repo-local vocabulary file or free-form strings? See [ADR-006](ADRs.md#adr-006-tags-are-free-form-string-tokens-constrained-to-alphanumerics-and-dash). +* Should Category remain fixed, or be a controlled list that can expand? See [ADR-007](ADRs.md#adr-007-category-uses-a-controlled-extensible-list). +* Should TargetAudience be structured or a list of strings? See [ADR-008](ADRs.md#adr-008-targetaudience-uses-a-controlled-extensible-list-of-strings). +* How should extra talk metadata flags be modeled? See [ADR-009](ADRs.md#adr-009-extra-talk-metadata-flags-use-a-flexible-key-value-map). +* Which fields should remain unstructured? See [ADR-010](ADRs.md#adr-010-only-narrative-context-fields-remain-unstructured). +* How much of the existing `bss-notes` prose should remain freeform versus structured? See [ADR-010](ADRs.md#adr-010-only-narrative-context-fields-remain-unstructured). ## Open Questions @@ -137,43 +137,43 @@ Implement a file-based TalkFolio MVP that can hold the structured speaking catal #### Phase 1: Repository structure and sample records -- Choose the on-disk directory layout for Talk and PresentationFamily records. -- Define the file-naming convention for file-backed records. -- Define how the configurable data-root path is supplied. -- Keep maintained catalog data generally outside this repo, while adding dedicated test repositories or fixture datasets here for validation. -- Add sample records that exercise the full schema. +* Choose the on-disk directory layout for Talk and PresentationFamily records. +* Define the file-naming convention for file-backed records. +* Define how the configurable data-root path is supplied. +* Keep maintained catalog data generally outside this repo, while adding dedicated test repositories or fixture datasets here for validation. +* Add sample records that exercise the full schema. #### Phase 2: Parsing and validation -- Parse Talk and PresentationFamily files. -- Validate schema shape, required fields, and data types. -- Validate tag format, GUID fields, and unstructured-field boundaries. -- Validate cross-record links such as PresentationFamily membership and referenced records. +* Parse Talk and PresentationFamily files. +* Validate schema shape, required fields, and data types. +* Validate tag format, GUID fields, and unstructured-field boundaries. +* Validate cross-record links such as PresentationFamily membership and referenced records. #### Phase 3: Migration tooling -- Parse the initial migration sources from `Talk-Catalog.md` and `bss-notes`. -- Map source content into structured TalkFolio fields. -- Surface ambiguous content for manual review instead of guessing. +* Parse the initial migration sources from `Talk-Catalog.md` and `bss-notes`. +* Map source content into structured TalkFolio fields. +* Surface ambiguous content for manual review instead of guessing. #### Phase 4: Catalog read model -- Build a normalized read model representation of Talks and families. -- Implement list/filter capabilities for category, tag, lifecycle, audience, family, and flags. -- Expose stable catalog outputs for human and tool consumption. +* Build a normalized read model representation of Talks and families. +* Implement list/filter capabilities for category, tag, lifecycle, audience, family, and flags. +* Expose stable catalog outputs for human and tool consumption. #### Phase 5: Hardening and docs -- Add targeted tests for parsing, validation, migration, and filtering. -- Update repo docs to describe the file layout and validation workflows. -- Validate the sample data and migration flow end-to-end. +* Add targeted tests for parsing, validation, migration, and filtering. +* Update repo docs to describe the file layout and validation workflows. +* Validate the sample data and migration flow end-to-end. ### Risks to watch -- Overfitting the migration tooling to messy source notes. -- Letting validation rules drift from the ADRs and schema docs. -- Pulling TalkCircuit or SlideFed workflow concerns into TalkFolio. -- Leaving the feature surface too broad before the file model and migration path are proven. +* Overfitting the migration tooling to messy source notes. +* Letting validation rules drift from the ADRs and schema docs. +* Pulling TalkCircuit or SlideFed workflow concerns into TalkFolio. +* Leaving the feature surface too broad before the file model and migration path are proven. ### Suggested first implementation slice diff --git a/docs/TalkSchema.md b/docs/TalkSchema.md index 030303b..8ab225b 100644 --- a/docs/TalkSchema.md +++ b/docs/TalkSchema.md @@ -8,20 +8,20 @@ TalkFolio owns talk concepts and proposal metadata, not deck construction or con The domain concerns are: -- talk identity and canonical description -- talk proposal copy -- audience fit -- category/tags for discovery and CFP relevance -- grouping into a PresentationFamily -- concept-level lifecycle -- references to built decks or public presentations +* talk identity and canonical description +* talk proposal copy +* audience fit +* category/tags for discovery and CFP relevance +* grouping into a PresentationFamily +* concept-level lifecycle +* references to built decks or public presentations TalkFolio does not own: -- deck build status or slide structure -- publication mechanics in SlideFed -- CFP submission state, booking, or acceptance results -- execution of the no-duplicate-family rule +* deck build status or slide structure +* publication mechanics in SlideFed +* CFP submission state, booking, or acceptance results +* execution of the no-duplicate-family rule ## Core Entity: Talk @@ -98,21 +98,21 @@ UpdatedAt: 2026-08-21T00:00:00Z The current best-fit set of core fields is: -- Id: GUID -- Title: canonical title -- AlternateTitles: list of marketing or branding variants -- Category: coarse top-level selection bucket from a controlled list that can expand over time -- Tags: topic labels for overlap and CFP matching; free-form strings constrained to alphanumerics and `-` -- PresentationFamily: family membership object with `Id` and `Variant` (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`) -- LifecycleStatus: concept-level state -- ProposalCopyItems: typed array of inline proposal copy blocks, each with `Type` and `Copy` (`|-` literal block) -- TargetAudience: list of audience descriptors drawn from a controlled list that can expand over time -- Flags: optional key-value map for talk-level metadata flags such as `Locked`, `ForKids`, or `HandsOn` -- SlideDeckIds: list of LiquidVictor `SlideDeck.Id` values -- PublicPresentationReferences: optional links to SlideFed or publication resources -- RelatedContent: typed list of companion content references (`Type`, `Title`, optional `Url`, `Notes`) -- IdeationNotes: freeform notes for ideas not yet fully refined -- CreatedAt / UpdatedAt: operational metadata +* Id: GUID +* Title: canonical title +* AlternateTitles: list of marketing or branding variants +* Category: coarse top-level selection bucket from a controlled list that can expand over time +* Tags: topic labels for overlap and CFP matching; free-form strings constrained to alphanumerics and `-` +* PresentationFamily: family membership object with `Id` and `Variant` (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`) +* LifecycleStatus: concept-level state +* ProposalCopyItems: typed array of inline proposal copy blocks, each with `Type` and `Copy` (`|-` literal block) +* TargetAudience: list of audience descriptors drawn from a controlled list that can expand over time +* Flags: optional key-value map for talk-level metadata flags such as `Locked`, `ForKids`, or `HandsOn` +* SlideDeckIds: list of LiquidVictor `SlideDeck.Id` values +* PublicPresentationReferences: optional links to SlideFed or publication resources +* RelatedContent: typed list of companion content references (`Type`, `Title`, optional `Url`, `Notes`) +* IdeationNotes: freeform notes for ideas not yet fully refined +* CreatedAt / UpdatedAt: operational metadata ## Category @@ -120,18 +120,18 @@ Category is intentionally coarse and should not be a deep taxonomy. Current candidate values: -- Agile -- Algorithms -- Language Models -- Leadership & Community -- Software Engineering +* Agile +* Algorithms +* Language Models +* Leadership & Community +* Software Engineering ### Design intent -- user should be able to filter by a broad topic at a glance -- most CFPs only need broad topical grouping -- nuance belongs in Tags, not nested taxonomy branches -- the list is controlled by the repo but can expand over time as new categories emerge +* user should be able to filter by a broad topic at a glance +* most CFPs only need broad topical grouping +* nuance belongs in Tags, not nested taxonomy branches +* the list is controlled by the repo but can expand over time as new categories emerge ## Tags @@ -139,23 +139,23 @@ Tags are the main mechanism for overlap, cross-cutting classification, and CFP m ### Proposed rules -- Tags are free-form strings, not a deeply nested classification tree. -- A Talk may have many Tags. -- Tags capture overlap that a single Category cannot express. -- Tag values are constrained to alphanumerics and `-` only, with no whitespace. -- Conference submission systems may map TalkFolio Tags to a conference's fixed vocabulary. +* Tags are free-form strings, not a deeply nested classification tree. +* A Talk may have many Tags. +* Tags capture overlap that a single Category cannot express. +* Tag values are constrained to alphanumerics and `-` only, with no whitespace. +* Conference submission systems may map TalkFolio Tags to a conference's fixed vocabulary. ### Examples -- rag -- embeddings -- retrieval -- graph-rag -- optimization -- genetic-algorithms -- sports-analytics -- architecture -- software-engineering +* rag +* embeddings +* retrieval +* graph-rag +* optimization +* genetic-algorithms +* sports-analytics +* architecture +* software-engineering ## PresentationFamily @@ -165,8 +165,8 @@ A PresentationFamily groups talks that are materially the same core presentation The Talk owns the relationship through a nested `PresentationFamily` object: -- `PresentationFamily.Id`: the family the talk belongs to -- `PresentationFamily.Variant`: the talk's variant type within that family (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`) +* `PresentationFamily.Id`: the family the talk belongs to +* `PresentationFamily.Variant`: the talk's variant type within that family (for example `Canonical`, `ExecutiveOverview`, `Lightning`, `Workshop`) Grouping the two fields into one object keeps family membership cohesive rather than spreading flat fields across the Talk root. A talk with no family simply omits the object. @@ -187,11 +187,11 @@ Notes: |- ### Invariants -- PresentationFamily is not a taxonomy node. -- It is a grouping concept, not a category hierarchy. -- Two talks in the same PresentationFamily should not be co-submitted to the same conference. -- TalkCircuit enforces this rule at submission time. -- TalkCircuit can find a talk's family members by querying Talks that share its `PresentationFamily.Id`. +* PresentationFamily is not a taxonomy node. +* It is a grouping concept, not a category hierarchy. +* Two talks in the same PresentationFamily should not be co-submitted to the same conference. +* TalkCircuit enforces this rule at submission time. +* TalkCircuit can find a talk's family members by querying Talks that share its `PresentationFamily.Id`. ## LifecycleStatus @@ -199,15 +199,15 @@ The current working model is concept-level lifecycle rather than build-status li ### Proposed states -- Ideation -- Active -- Retired +* Ideation +* Active +* Retired ### Design intent -- Ideation: the idea exists, but may not yet have polished copy or a deck. -- Active: the talk is ready for proposal work or delivery. -- Retired: the talk should no longer be offered. +* Ideation: the idea exists, but may not yet have polished copy or a deck. +* Active: the talk is ready for proposal work or delivery. +* Retired: the talk should no longer be offered. ### Explicit non-goal @@ -219,19 +219,19 @@ A Talk can be Active while a deck is still being assembled or while it has not b Proposal copy supports the speaking portfolio and CFP process. The current proposal language falls into a few categories: -- Abstract -- ElevatorPitch -- ShortVersion -- CommitteeNotes -- AudienceNotes -- AlternateTitleCandidates +* Abstract +* ElevatorPitch +* ShortVersion +* CommitteeNotes +* AudienceNotes +* AlternateTitleCandidates ### Decision Proposal copy is stored inline on the Talk record as `ProposalCopyItems`, a typed array where each item has: -- `Type`: the copy classification (for example `Abstract`, `ElevatorPitch`, `ShortVersion`, `CommitteeNotes`) -- `Copy`: the proposal text stored as a YAML `|-` literal block +* `Type`: the copy classification (for example `Abstract`, `ElevatorPitch`, `ShortVersion`, `CommitteeNotes`) +* `Copy`: the proposal text stored as a YAML `|-` literal block This keeps proposal text extensible without changing the Talk schema whenever a new copy type is introduced. @@ -262,19 +262,19 @@ RelatedContent: ### Rules -- Related content is associated with the Talk concept, not with a specific built deck. -- A Talk may have zero, one, or many related content items. -- More than one item of the same `Type` is allowed. -- Each item has a `Type`, a `Title`, an optional `Url`, and `Notes`. -- There is no separate `Id` field on a related content item. When present, `Url` is the canonical identifier for the item. -- `Notes` is the primary place for context, framing, or reason for association, stored as a `|-` literal block. -- `Summary`, `Status`, and `PublishedAt` are intentionally not included here because those belong to the domain that actually owns the content lifecycle. -- If some associated material lives in CognitiveInheritance or another domain outside the TalkFolio repo, the TalkFolio entry can still reference it by type, title, URL, and notes without forcing that content to be modeled as a TalkFolio-owned resource. +* Related content is associated with the Talk concept, not with a specific built deck. +* A Talk may have zero, one, or many related content items. +* More than one item of the same `Type` is allowed. +* Each item has a `Type`, a `Title`, an optional `Url`, and `Notes`. +* There is no separate `Id` field on a related content item. When present, `Url` is the canonical identifier for the item. +* `Notes` is the primary place for context, framing, or reason for association, stored as a `|-` literal block. +* `Summary`, `Status`, and `PublishedAt` are intentionally not included here because those belong to the domain that actually owns the content lifecycle. +* If some associated material lives in CognitiveInheritance or another domain outside the TalkFolio repo, the TalkFolio entry can still reference it by type, title, URL, and notes without forcing that content to be modeled as a TalkFolio-owned resource. ### Usage guidance -- RelatedContent is intended for discovery, navigation, and finding companion material tied to a talk — for example, surfacing the blog posts, videos, articles, essays, or notebooks that expand on a talk's subject. -- It is a lightweight relationship model, not a content-management system or publication workflow. TalkFolio stores only the relationship and reference; the content's lifecycle (drafting, publication, updates, retirement) remains in the domain that owns that content, such as CognitiveInheritance for blog posts. +* RelatedContent is intended for discovery, navigation, and finding companion material tied to a talk — for example, surfacing the blog posts, videos, articles, essays, or notebooks that expand on a talk's subject. +* It is a lightweight relationship model, not a content-management system or publication workflow. TalkFolio stores only the relationship and reference; the content's lifecycle (drafting, publication, updates, retirement) remains in the domain that owns that content, such as CognitiveInheritance for blog posts. ### Why this belongs here @@ -293,9 +293,9 @@ SlideDeckIds: Rules: -- values are LiquidVictor `SlideDeck.Id` GUIDs -- LiquidVictor remains the source of truth for deck structure -- TalkFolio does not write back into the deck schema +* values are LiquidVictor `SlideDeck.Id` GUIDs +* LiquidVictor remains the source of truth for deck structure +* TalkFolio does not write back into the deck schema ### SlideFed publication references @@ -308,33 +308,33 @@ PublicPresentationReferences: Rules: -- SlideFed owns the public resource and its publication lifecycle -- TalkFolio only references it for display or cataloging +* SlideFed owns the public resource and its publication lifecycle +* TalkFolio only references it for display or cataloging ## Resolved Decisions The following decisions are now settled for TalkFolio: -- Talk identity uses GUIDs for `Id` values. See [ADR-005](ADRs.md#adr-005-talk-ids-use-guids). -- Tags are free-form strings, constrained to alphanumerics and `-` to keep the data clean and consistent. See [ADR-006](ADRs.md#adr-006-tags-are-free-form-string-tokens-constrained-to-alphanumerics-and-dash). -- Category is a controlled list that can expand over time. See [ADR-007](ADRs.md#adr-007-category-uses-a-controlled-extensible-list). -- TargetAudience is a list of strings drawn from a controlled list that can expand over time. See [ADR-008](ADRs.md#adr-008-targetaudience-uses-a-controlled-extensible-list-of-strings). -- Talk-level flags are modeled as a flexible key-value `Flags` map. See [ADR-009](ADRs.md#adr-009-extra-talk-metadata-flags-use-a-flexible-key-value-map). -- Only narrative context fields remain intentionally unstructured. See [ADR-010](ADRs.md#adr-010-only-narrative-context-fields-remain-unstructured). +* Talk identity uses GUIDs for `Id` values. See [ADR-005](ADRs.md#adr-005-talk-ids-use-guids). +* Tags are free-form strings, constrained to alphanumerics and `-` to keep the data clean and consistent. See [ADR-006](ADRs.md#adr-006-tags-are-free-form-string-tokens-constrained-to-alphanumerics-and-dash). +* Category is a controlled list that can expand over time. See [ADR-007](ADRs.md#adr-007-category-uses-a-controlled-extensible-list). +* TargetAudience is a list of strings drawn from a controlled list that can expand over time. See [ADR-008](ADRs.md#adr-008-targetaudience-uses-a-controlled-extensible-list-of-strings). +* Talk-level flags are modeled as a flexible key-value `Flags` map. See [ADR-009](ADRs.md#adr-009-extra-talk-metadata-flags-use-a-flexible-key-value-map). +* Only narrative context fields remain intentionally unstructured. See [ADR-010](ADRs.md#adr-010-only-narrative-context-fields-remain-unstructured). ## Current Recommendation The working baseline for the first TalkFolio implementation is: -- Talk entity with GUID `Id` and canonical field set -- controlled-but-extensible Category list -- Tags as free-form, hyphen-safe strings -- presentation family with the Talk owning membership via a nested `PresentationFamily` object (`Id` + `Variant`) -- concept lifecycle of Ideation | Active | Retired -- references to SlideDeckIds and optional public publication references -- proposal copy stored inline as `ProposalCopyItems` (typed items with `|-` literal-block copy) -- companion material referenced via `RelatedContent` (typed, talk-level, lightweight references) -- flexible talk-level flags via `Flags` -- unstructured prose limited to `ProposalCopyItems[].Copy`, `IdeationNotes`, `PresentationFamily.Notes`, and `RelatedContent[].Notes` +* Talk entity with GUID `Id` and canonical field set +* controlled-but-extensible Category list +* Tags as free-form, hyphen-safe strings +* presentation family with the Talk owning membership via a nested `PresentationFamily` object (`Id` + `Variant`) +* concept lifecycle of Ideation | Active | Retired +* references to SlideDeckIds and optional public publication references +* proposal copy stored inline as `ProposalCopyItems` (typed items with `|-` literal-block copy) +* companion material referenced via `RelatedContent` (typed, talk-level, lightweight references) +* flexible talk-level flags via `Flags` +* unstructured prose limited to `ProposalCopyItems[].Copy`, `IdeationNotes`, `PresentationFamily.Notes`, and `RelatedContent[].Notes` This gives a clean, minimal schema that matches the domain boundary without pulling in deck-building or submission-state concerns.