Repository navigation
Releases: ctcstack/ctcdocs
Release list
v0.24.0
Changed
- A sync exports only what a change reaches. Adding, removing or moving
a document no longer exports the whole corpus again, nor does renaming a
folder. A document is exported again when its own file changed, when a
folder above it was renamed or moved, or when an item it links to
started or stopped being published; a full sync and a converter upgrade
still export everything. A narrow run produces the same bytes a full
run would, which a property test checks over random corpora and changes
(ADR-053). - A sync runs the content gate, not the project's full gate. When
anything changed, it validates the output, builds once, and runs the
denial suite and the search check; with nothing changed it checks
nothing. Formatting, lint, types, unit tests and the browser suite are
code checks and no longer run on every sync, nor does the denial suite
run twice (ADR-053). - Callers: drafts wait, merges are verified once. The
NEW_PROJECT.md
templates runci.ymlon pull requests that are not drafts and weekly,
and verify a merge indeploy.ymlbefore deploying it, instead of
verifying it in both. The platform's own CI skips drafts too. - Eight exports at a time.
SYNC_CONCURRENCYdefaults to 8 instead of
4: most of a full export is waiting on Google, so this about halves it.
Upgrade note
Replace .github/workflows/ci.yml and deploy.yml with the templates in
docs/NEW_PROJECT.md. Until then, a merge is still verified twice.
v0.23.2
Added
- Phase timings.
ctcdocs-sync syncprints how long the inventory,
planning, export, assembly, validation and write took, and how many
times it planned the corpus. They go to the log only; nothing generated
carries them.
Changed
- A held document is not exported again until it changes. A document
the sync could not export for a reason of its own (too large, download
restricted, content refused) is recorded in the manifest underheld,
with the Drive version it failed at. Later syncs keep it held without
exporting it again until Drive reports a newer version; a full sync, or
a converter upgrade, tries it again. Before, every sync exported it again
and planned the corpus twice (ADR-053).
Security
- Dependencies past new advisories.
zod4.6.6 in the sync and site
packages; the lockfile takes patchedundici,vite,dompurify,
fast-uriandpostcss-selector-parser, and the override for
Miniflare's pinnedundicimoves to 7.30.1.vitestis 4.1.12.
katexstays at 0.16 with one low advisory: its fix is a new minor line.
Upgrade note
The first sync after the upgrade records any held document in
data/sync-manifest.json, so it changes that file once.
v0.23.1
Added
- Connectors show the site's mark. The MCP server names the brand icons
in its implementation info, and a private deployment serves them before
sign-in, so Claude, ChatGPT and other clients show the mark beside the
connector. The build renders the favicon as/icon-192.pngand
/favicon.icounlesspublic/holds its own; those, the favicon and its
dark variant are the only paths an anonymous request is answered with
(ADR-052).
Upgrade note
Bump the packages and the workflow pins, and deploy. A connector added
before the upgrade may keep showing no icon until it is added again, since
assistants cache what they fetched.
v0.23.0
Added
- Assistants search in the documents' language. A project that sets
mcp.language, such asen, has the MCP server's instructions, the
searchdescription and its query field tell an assistant that the
documents are written in it and that a query in it finds more. - Content health names near-duplicate documents. A document whose text is
at least 80% the same as another's, or stands 95% inside a longer one, is
noted under Fix next with the other named (ADR-049). - What people and assistants could not find. With
insights.enabled,
the Worker records each MCP call and each settled search on the site in a
D1 database of its own, by the access classes the reader may read and
never the reader, and every Monday, in UTC, reports the week before: what was not
found, grouped by its words, what is asked most, what is found and not
opened, and how the server is used. Admins read it on the content health
page, under What people could not find;ctcdocs-insightsprints it for
maintainers and writes the week's misses as candidate evaluation
questions. Records are keptinsights.retentionDays, 90 unless set
(ADR-050, ADR-051). - The deploy workflow migrates the state database. With insights on,
project-deploy.ymlapplies the platform's migrations to the
environment's database before it deploys the Worker. - Content health asks for the review of stale documents. A document not
edited in Drive forsync.staleAfterMonths, 12 by default, is noted under
Improve with the day of its last edit;sync.staleFoldersgives a folder
its own line, 0 for none (ADR-049).
Upgrade note
Bump the packages and the workflow pins, set mcp.language if the documents
are in one language, and deploy. Nothing in R2 or the search index changes.
The two notes appear after the next sync.
Insights are off unless a project turns them on, and need nothing until
then. To turn them on: add D1 Edit to each environment's deploy token, create
each environment's database and bind it as KB_STATE_DB with the platform's
migrations_dir, then set insights.enabled; it needs mcp.enabled and
access.admins. The next deployment applies the migrations
(Cloudflare setup). Running
the platform's tests now needs Node 22.13 or newer.
v0.22.3
Added
- Documents by format, for assistants. The MCP server's
searchand
recentgive each document itsformat—doc,pdf,sheet,video
oraudio, the valuefetchreports — andbrowsegives it to each
document that is not a Google Doc. Every folder of abrowsetree, and the
answer itself, counts its documents by format informatsbesidecount,
collapsed folders included, so onebrowsewithout a folder says how many
documents of each format a reader may open, without reading any. All three
tools take an optionalformatto keep to one, and the descriptions and
the server's instructions say so (ADR-044).
Fixed
- A
browsetree that leaves documents out keeps to its budget. The
omittedcount was added after the budget was spent, and could take the
answer a few dozen characters pastmcp.browseCharacters.
Upgrade note
Bump the packages and the workflow pins, and deploy. No sync is needed: the
build already records each document's format.
v0.22.2
Fixed
- A PDF shows on its page again. 0.22.0 gave the private deployment's
Content Security Policy aframe-srcfor Google Drive's player, which
replaced the default for frames rather than adding to it, and browsers
frame a PDF's<object>: every PDF was blocked.frame-srcnow admits the
site's own files beside Drive, and the Worker's test asserts both.
Upgrade note
Bump the packages and the workflow pins. No sync is needed.
v0.22.1
A calmer reading interface, and one statement of the kinds of published page.
Changed
- The sidebar. Folders are named at the size of the documents in them,
at weight 600 in the muted ink; the folders that hold the current page take
the strong ink. Rows are taller, with 0.4rem of inline padding, a thin
chevron and clearer hover and current-page fills. The sidebar is 20.75rem
wide. - Format icons. A PDF, spreadsheet, video or audio page carries a colored
tile of its format — the letters PDF, a grid, a play button, sound bars —
after its title in the sidebar, and before it in the section listing, the
full index, the recency band and the home page's folder cards, in place of
a badge or the outline of a page. The file-type colors are the one
exemption from the reserved accent inDESIGN.md. - Breadcrumbs are set at 0.8125rem and weight 500 with chevron
separators, and the title sits 1rem below them. - Headings. The sync drops bold that covers a whole heading, as editors
add it in Google Docs, and the page draws bold inside a heading at 700. - A spreadsheet's page records whether it is a Google Sheet, which the
source link's label reads instead of the address. - The header's mark is the project's
brand.faviconPath, not a fixed
/favicon.svg, and keeps the file's own shape.
Added
brand.faviconDarkPath, optional: the mark drawn for a dark ground. The
header shows it under the dark theme the reader chose on the site, whatever
the system's setting, and a browser with a dark interface shows it in the
tab.
Internal
@ctcstack/ctcdocs-core/document-formatnames the kinds of page, their
sourceType, badges, nouns and MCP formats once. The sync, the site and
the Worker read them from there, and the PDF, spreadsheet and recording
facts a page records are one zod schema each.
Upgrade note
Bump the packages and the workflow pins, then run a sync. NORMALIZER_VERSION
and SHEET_VERSION moved, so that sync exports every Google Doc and reads
every spreadsheet again once, and the MCP server stores every document again
on its next schedule. Until it runs, headings keep their bold and a Google
Sheet's label is read from its address, as before.
v0.22.0
Video and audio files get pages
(ADR-047,
proposed): every video or audio file, and every Google Vids video, in a
published folder gets a page written from its Drive metadata, and an uploaded
one plays on it in Google Drive's own player. Nothing is downloaded, hosted
or transcribed.
Added
- Recording pages.
sourceType: drive-media, markedVideoorAudioin
the sidebar,videooraudioindata/docs-index.json,llms.txtand the
MCP server'sformat. The title is the Drive name without its extension.
The page opens with a sentence of facts, its length and frame size when
Drive reports them, then the description written in Drive, whose first line
is its summary; its web and mail addresses become links. - Drive's player on the page. An uploaded recording's card frames
drive.google.com/file/d/<id>/previewin the video's own shape, with a link
to it in Drive below. Drive's sharing decides who may play it. Google Vids
has no player to frame, so its card has the link alone. - Content health notes a recording with no description in Drive
(media-undescribed). The sync report'ssummary.publishedgainsmedia. - The manifest records
exportMode: videooraudio, and for a recording
asourceChecksumof the metadata its page is written from, so a page is
written again when its description or length changes. - The inventory asks Drive for each file's
descriptionand
videoMediaMetadata.
Changed
- The private deployment's Content Security Policy admits frames from
https://drive.google.com, and from nowhere else. - A link to a recording, by its Drive or Google Vids address, leads to its
page, as a link to a published PDF does. - Video and audio are no longer listed as not on the site. The
media-filereason is retired; a report that names it still validates until
the next sync replaces it.
Upgrade note
Bump the packages and the workflow pins, then run a sync: every recording in
the published folders gets a page on it. No existing page changes. In Safari,
or any browser that blocks third-party cookies, Drive's player cannot use the
reader's Google sign-in and shows an error or a sign-in request; the link
below it always opens the recording in Drive.
v0.21.4
Fixed
- A deployment no longer fails between a platform upgrade and the next
sync. The sync report records the version of the Markdown its lengths
were measured on,documentLengths.markdownVersion, and the gate compares
the content health page's length notes with what the MCP server returns
only when that version is the one the build writes. After 0.21.0 changed
the Markdown, every deployment before the first sync failed on notes the
last sync had measured on the old text.
PUBLISHED_MARKDOWN_VERSION in @ctcstack/ctcdocs-core/published-markdown
moves whenever the Markdown version of a page changes.
v0.21.3
Fixed
Spreadsheet pages read the way a model is laid out:
- A note beside an input stays with it. A column of text beside a
block, on rows the block fills, joins it even across an empty column, and
a label and value with notes readsLabel: value — note. It used to be cut
off into a list of its own after the inputs. - A table split by empty rows keeps its header. A table whose first row
is data, written with a currency, a percent, a fraction or more than four
digits, takes the header of the table above it on the same columns, and
its formulas are named by that header. It used to take its first row of
data for a header. A header of years is still a header. - A sentence on its own line is a paragraph. A caption is a heading when
it is at most 80 characters and does not end like a sentence. - An empty column a block spans is no column of its table.
sheetVersion moves to 2, so the next sync reads every spreadsheet again
once, unchanged uploaded files included.