gleanwork / gleanwork/glean-developer-site
changelog: history normalizer is lossy on rich entries (un-skip normalize-history idempotency test)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 8
- Forks
- 26
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 65
Description
Background
In #586 the vitest test normalizeHistoryEntries > dry-runs every historical changelog entry without parse failures (packages/changelog-generator/src/__tests__/normalize-history.test.ts) was skipped (it.skip) so the suite could go green. This issue tracks fixing the root cause and re-enabling it.
Requested in https://github.com/gleanwork/glean-developer-site/pull/586#discussion_r3444400812.
Problem
The history normalizer (packages/changelog-generator/src/commands/normalize-history.ts → normalizeRelease / renderNormalizedRelease) re-renders every entry through a flat NormalizedChange model. That model can't represent several constructs used by rich, hand-authored entries, so re-normalizing them is lossy and the test's expect(result.rewritten).toBe(0) invariant fails.
Failure modes
- Markdown links stripped —
[Label](/relative/path)becomes bareLabel.(relative links aren't recognized as source refs). - Prose sections deleted — anything that isn't a
## Changes/## Sourcebullet list (e.g. a "When to use it" paragraph) is dropped. - Nested lists flattened — sub-bullets are collapsed to a single level.
- Frontmatter
tagsdropped — not re-emitted by the renderer. - Stray trailing periods — a
.is appended even to lines ending in:or to URL paths (e.g./people/{person_id}/photo→/people/{person_id}/photo.).
Example cases (use as test fixtures)
Case 1 — 2026-05-18-custom-metadata-api-ga.md (rich entry)
Input (excerpt):
---
title: 'Custom Metadata API is Generally Available'
categories: ['API']
tags: ['Indexing API', 'Feature']
---
## What's new
- **New endpoints** under `/rest/api/index`:
- `PUT /custom-metadata/schema/{groupName}` — create or update a metadata group schema
- `GET /custom-metadata/schema/{groupName}` — retrieve a metadata group schema
## When to use it
Custom Metadata works with any document already indexed in Glean. ... see [Custom Properties vs Custom Metadata](/api-info/indexing/custom-metadata/custom-properties-vs-custom-metadata).
## Documentation
- [Custom Metadata Overview](/api-info/indexing/custom-metadata/overview)
- [Authentication](/api-info/indexing/custom-metadata/authentication)
Current normalizer output (degraded):
---
title: 'Custom Metadata API is Generally Available'
categories: ['API']
---
## Changes
- **New endpoints** under `/rest/api/index`:.
- `PUT /custom-metadata/schema/{groupName}` — create or update a metadata group schema.
- `GET /custom-metadata/schema/{groupName}` — retrieve a metadata group schema.
...
- Custom Metadata Overview.
- Authentication.
Regressions: tags dropped, ## When to use it section deleted, nested endpoint list flattened, doc links → orphaned bare-text bullets, stray :..
Case 2 — 2026-05-05-rest-api-changes-open-api.md (URL period + spurious source)
-- Added endpoint: /people/{person_id}/photo
+- Added endpoint: /people/{person_id}/photo.
...
- [open-api d485d2c](https://github.com/gleanwork/open-api/commit/d485d2c...)
+- [Release notes](https://github.com/gleanwork/open-api/commit/2800e7a...)
Regressions: trailing . appended to a URL path; an inferred "Release notes" source link added.
The full set of entries that currently fail to normalize idempotently (7): 2026-05-05, 2026-05-07, 2026-05-11, 2026-05-12, 2026-05-13 (-rest-api-changes-open-api), 2026-05-18-custom-metadata-api-ga, 2026-06-09-rest-api-changes-open-api.
Possible approaches
- Idempotency guard — leave already-well-formed entries untouched (entry has a title + none of the known broken-formatting patterns the sibling test enforces). Lowest risk; doesn't touch the live release-generation renderer. (A prototype of this existed earlier in #586.)
- Enrich the model — teach
NormalizedChange/renderNormalizedReleaseto preserve links, prose sections, nesting, and tags. Higher value but changes the shared renderer used by live changelog generation (broader blast radius). - Fix the narrow bugs regardless of approach: don't append
.after:or to URL paths; preserve relative-link bullets.
Acceptance criteria
- Re-running the normalizer over current history reports 0 rewrites with no content loss (links, sections, nesting, tags preserved).
- The narrow bugs above are fixed (no stray periods on
:/URLs). - Add the example cases above as regression test fixtures.
- Un-skip
normalizeHistoryEntries > dry-runs every historical changelog entry without parse failuresand confirm it passes. -
renderNormalizedReleaseoutput for live release generation is unchanged (or intentionally improved with sign-off).
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/changelog-generator/src/tests/normalize-history.test.ts and the skipped historical-entry test, then read packages/changelog-generator/src/commands/normalize-history.ts, especially normalizeRelease and renderNormalizedRelease. Use the seven listed changelog entries and the two example cases as regression fixtures. Done means the test is re-enabled, historical normalization reports zero rewrites without losing content, narrow formatting bugs are covered, and live renderer output remains unchanged or is intentionally approved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- documentation, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100