You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: build-context factory, resolveEntryTitle and toPlainText
Resolves backlog cross-link conflicts: both branches moved a task file to
resolved/ while updating its link to the other on the assumption the other
was still open. Both now live in resolved/, so the links are siblings.
Also drops two stale open rows that a keep-both merge left alongside their
own resolved rows -- caught by lint:tasks, which is exactly the drift that
guard exists to catch.
Copy file name to clipboardExpand all lines: .claude/future-tasks/index.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -166,7 +166,6 @@ silently skips conflict detection. It is rated P1 because its trigger is narrow
166
166
|[url-mapping-system.md](url-mapping-system.md)| Flexible URL-to-content mapping: date-based URLs, custom slug transforms, multiple patterns per collection. The heaviest and most speculative of the URL designs — keep shelved unless the marketing site needs pattern-based URLs (a dated blog) that a per-entry override can't express. Treat as an appendix to `isurlpath-field-marker`[MKT]|
167
167
|[list-permission-level.md](list-permission-level.md)| New "list" permission level: see content exists without read/edit access. Unstarted; `PermissionLevel` is still `'read' \| 'edit' \| 'review'`. Two path drifts corrected 2026-08-13 (the named `path-permissions.ts` no longer exists; the `EditorEntry` sketch uses field names the real interface doesn't have). Note it would add a **sixth** ACL matcher unless the consolidation lands first [NEITHER]|
168
168
|[transform-lambda-bundle-bloat.md](transform-lambda-bundle-bloat.md)| Transform Lambda's `handler.js` bundles unrelated octokit/simple-git/proper-lockfile code via the broad `canopycms/server` barrel (~1 MB dead weight). Non-functional, but **the only blocker is a yes/no decision** — the repo bans new package entrypoints without approval, and the code change itself is a small re-export module. **Re-tagged 2026-08-14** — the transform Lambda ships with whichever site deploys first: the KB [BOTH]|
169
-
|[search-document-extraction-primitives.md](search-document-extraction-primitives.md)| New 2026-08-14 — adopter request #17. The requested `extractSearchDocuments` API is the wrong shape (the two adopters' derivations share nothing at that level); what's actually duplicated is the boot block, a markdown→plaintext stripper (`ai/strip-mdx.ts:19`, unexported), and title derivation (`utils/title-field.ts:60`, unexported) — plus the unrelated-but-same-shape `parseTypedFilename` (`content-listing.ts:94`, unreachable) and `listEntries` dropping `updatedAt`. **This epic is exporting the primitives now**; `extractSearchDocuments` itself is not being built [BOTH]|
170
169
|[toc-heading-id-contract.md](toc-heading-id-contract.md)| New 2026-08-14 — from the site audits. Both sites independently built `rehype-heading-attrs.ts`; `website`'s `toc.ts` hand-mirrors rehype-slug's dedup counter as a second, unsynced piece of state, and desyncs the first time a heading contains `#`/`####`. Ship one canonical heading-ID pass plus an `extractToc()` that reads it, not a second slugger [BOTH]|
171
170
|[resolved-references-url.md](resolved-references-url.md)| New 2026-08-14 — from the site audits. A resolved reference carries no URL, so the KB built `getDocLinkIndex()` — a **second full `listEntries` pass** just to link to referenced entries — and some pages set `resolveReferences: false` entirely to avoid paying for both. Carry a `urlPath` on resolved references (the target entry is already loaded) and delete the workaround [KB]|
172
171
|[trailing-slash-router-helpers.md](trailing-slash-router-helpers.md)| New 2026-08-14 — from the site audits. Both sites solved the same static-export trailing-slash problem at very different weight: the KB built a whole subsystem (`paths.ts` + a wrapped router hook + a custom ESLint rule), `website` built one function. Ship the primitive (`withTrailingSlash`), let adopters choose enforcement strictness [BOTH]|
@@ -245,6 +244,7 @@ The tables above list OPEN work only.
245
244
|[block-registry-types.md](resolved/block-registry-types.md)| RESOLVED (2026-08-14, branch `feat/block-registry-types-and-recipes`, `integration-202608-b` epic) — adopter request #13, shipped as decided: types, not a component. `BlockValueOf<Blocks, N>` and `BlockComponentRegistry<Blocks, ExtraProps>` added to `entry-schema.ts`, exported off the `canopycms` root entry, with type-level tests proving exhaustiveness in both directions (missing template, unknown extra key). README's new "Block Component Registries" section documents the recipe, including the one contained type assertion the dispatch loop needs. `apps/example1/app/components/PostView.tsx` now uses the registry instead of the if-chain this file originally flagged [BOTH]|
246
245
|[field-fragments-docs.md](resolved/field-fragments-docs.md)| RESOLVED (2026-08-14, branch `feat/block-registry-types-and-recipes`, `integration-202608-b` epic) — adopter request #15, pure documentation gap closed. README's new "Reusable Field Fragments" section covers both mechanisms (spreading a `const`-inferred field array, nesting `defineInlineFieldGroup` inside a block template) plus a per-use-override worked example. A small `defineFieldFragment()` identity helper was added beside `defineBlockTemplate` for discoverability [BOTH]|
247
246
|[shared-blocks-listentries-caveat.md](resolved/shared-blocks-listentries-caveat.md)| RESOLVED (2026-08-14, branch `feat/block-registry-types-and-recipes`, `integration-202608-b` epic) — adopter request #16, recipe + caveat documented. README's new "Shared / Referenced Blocks" section gives the full recipe (snippet-style entry type + one-field block template holding a `reference`); the `listEntries`-never-resolves-references caveat is called out in that section and again at the top of "Listing Entries". `apps/example1/app/schemas.ts` now wires one real shared-block reference, rendered null-safely in `PostView.tsx`. The underlying capability gap (`listEntries` still doesn't resolve references) remains open — this closed the documentation gap only [BOTH]|
247
+
|[search-document-extraction-primitives.md](resolved/search-document-extraction-primitives.md)| RESOLVED (2026-08-14, epic `integration-202608-b`) — adopter request #17. `parseTypedFilename`/`defaultBuildPath`/`updatedAt` landed first (commit `4a8992fe`); this closes the rest: `resolveEntryTitle` exported from `canopycms/server` and the root `canopycms` entry (client-safe), `toPlainText` (new, built on `ai/strip-mdx.ts`'s `stripMdxImports`) exported from `canopycms/ai`, and the boot-block pattern formalized as `createBuildCanopy(config, options)` in `canopycms/server` rather than left as prose. `extractSearchDocuments` itself remains deliberately unbuilt — see `docs/adopter-migration.md`[BOTH]|
248
248
|[optional-property-inference.md](resolved/optional-property-inference.md)| RESOLVED (2026-08-14, epic `integration-202608-b`, commit `8da62672`) — adopter request #14, shipped as proposed. `InferContentShape`/`RequiredValue` now infer a field as an optional property (`subheading?: string`) iff its schema entry has an explicit `required: false`; README's two previously-contradicting sections reconciled; covered by `entry-schema.test.ts`'s three-way required/optional/omitted distinction [BOTH]|
249
249
|[readbyurlpath-entry-type.md](resolved/readbyurlpath-entry-type.md)| RESOLVED (2026-08-14, epic `integration-202608-b`, commit `4a8992fe`) — shipped as proposed, widened to also return `entryId`. `read()` and `readByUrlPath()` both surface `meta.entryType`/`meta.entryId`, closing the gap that forced adopters into per-content-type Next.js routes or a separate `listEntries` lookup for catch-all routing [BOTH]|
250
250
|[leaf-slug-static-params-docs-gap.md](resolved/leaf-slug-static-params-docs-gap.md)| RESOLVED (2026-08-14) — adopter request #12 was already fully shipped before it was asked: `collectStaticParams(..., {shape: 'single'})` (`canopycms-next/src/static.ts:23,64-66`), documented (`README.md:1420-1428`), used in-repo (`apps/example1/app/posts/[slug]/page.tsx:14-15`), and already available on the website's pinned 0.0.41. Zero work — a discoverability gap on the request side, not a package gap [BOTH]|
0 commit comments