Skip to content

fix(ci): unblock the feature-docs generator (76 consecutive failures) - #80

Merged
FahimaGold merged 8 commits into
mainfrom
fahima/fix-feature-docs-pipeline
Jul 27, 2026
Merged

fix(ci): unblock the feature-docs generator (76 consecutive failures)#80
FahimaGold merged 8 commits into
mainfrom
fahima/fix-feature-docs-pipeline

Conversation

@FahimaGold

@FahimaGold FahimaGold commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Why

generate-features.yml has failed on every run since 2026-05-12 — 76 consecutive failures. The feature pricing tables have not been refreshed in ~2.5 months. This PR fixes the pipeline; it deliberately contains no regenerated content, so the next scheduled run opens that as its own reviewable PR.

Opened while reviewing #13, which should be closed rather than merged — see below.

What's broken

1. The PR step can't push. Generation succeeds; create-pull-request fails:

remote: error: GH013: Repository rule violations found for refs/heads/auto/update-feature-docs
remote: - Cannot force-push to this branch
remote: - Cannot update this protected ref

It force-pushes as github-actions[bot] (Write role), and the agent-block ruleset blocks creation/update/non_fast_forward on every ref outside refs/heads/edenai-assistant/**, bypassable only by OrganizationAdmin or Triage/Maintain/Admin. Identical to the failure #50 fixed for update-dates.yml — the token was just never added here.

2. dateModified was hardcoded. Every generated page got a fixed 2026-05-06, resetting whatever update-dates.yml had bumped. 24 of #13's 27 files change nothing else: dateModified moving backwards from 2026-05-07 to 2026-05-06.

3. update_docs_json silently no-opped. It walked V3 Documentation tab → V3 Documentation group → pages, looking for a nested Expert Models dict. Expert Models is a sibling top-level group, not a child, so nothing matched. New pages were written to disk and never added to the nav — currently hiding 10 pages: web/ (7 firecrawl subfeatures), image/face-recognition, video/deepfake-detection-async.

4. Cosmetic: the API returns "seconde", which reached published tables as $0.05 per seconde (13 rows).

Changes

Commit Fix
995aab6 token: ${{ secrets.DOCS_BOT_PAT || secrets.GITHUB_TOKEN }} on the PR step
3f094c0 Read datePublished/dateModified off the existing page; only new pages get today's date
152a9c7 Find the Expert Models group by search; exit non-zero if absent instead of no-opping
f76dd83 Normalise French unit names (droppable independently)

Verification

Ran the generator against live /v3/info from the committed state:

  • 36 pages generated, zero date-only diffs (vs. 24 regressions in docs: update AI feature documentation #13)
  • Nav now picks up Web Features (7), Image Features 10 → 11, Video Features 1 → 2; the API Reference tab keeps its own AI Features group
  • New pages get datePublished/dateModified of today
  • per secondeper second

Why #13 should be closed, not merged

Its branch head is from 2026-05-08, 79 commits behind. Checking its 8 price edits against the API today: it fixes 2 (Leonardo Vision XL → $0.014, veryfi → $0.16), breaks 3 (leonardo default and AlbedoBase XL are still $0.017; Phoenix is still $0.014), and 3 are already stale again (image/generation/openai is $0.034, not its $0.018; bytedance video is $0.05/second, not its $0.4/request; dall-e-2 no longer exists in the API). Plus the 24 backwards dates.

Real drift a fresh run will close: 16 wrong prices, 3 rows for removed models, 37 models missing entirely (all Google Imagen, the gpt-image-* family, sora-2-pro, pixverse, and the whole web/ category).

Deploy notes

  • DOCS_BOT_PAT already exists (added in fix(ci): push date-bump commits via a bypass-eligible PAT #50) — please confirm it's visible to this workflow.
  • After merge, delete the stale auto/update-feature-docs branch so the next run starts clean, then trigger the workflow manually rather than waiting for 06:00 UTC.
  • The content PR will add 10 new pages whose Python snippets test-snippets.yml has never exercised; expect to fix snippets there, not here.

Summary by CodeRabbit

  • Documentation
    • Improved provider pricing formatting by normalizing French time unit names to English for consistent output.
    • Strengthened schema table rendering in generated Markdown by collapsing whitespace and escaping table cell content.
    • Unified feature section naming/labeling, including updated TechArticle schema metadata (e.g., web category).
    • Preserved existing datePublished/dateModified when regenerating TechArticle schemas; added safe UTC defaults for new pages.
    • Refined V3 documentation navigation by dynamically locating and rebuilding expert model feature groupings.
  • Chores
    • Improved automated pull request creation reliability by setting an explicit authentication token with a secure fallback.
  • Bug Fixes
    • Prevented accidental overwrites of existing subfeature pages when detail fetching fails; aborted generation when schema tables would otherwise be missing.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The feature-generation pipeline normalizes rendered content, preserves schema dates, synchronizes navigation labels, handles failed detail fetches safely, and uses explicit pull-request authentication.

Changes

Feature generation pipeline

Layer / File(s) Summary
Rendered pricing, tables, and schema metadata
scripts/generate_features.py
Pricing units and Markdown cells are normalized, web icons are mapped, section labels are shared, and TechArticle dates are preserved or initialized.
Dynamic documentation navigation
scripts/generate_features.py
Documentation groups are located dynamically and feature pages are rebuilt from static pages and generated subgroups.
Resilient subfeature page generation
scripts/generate_features.py
Handled fetch failures are restricted; existing pages remain unchanged when detail retrieval fails, while generation aborts when no page exists.
Pull-request workflow authentication
.github/workflows/generate-features.yml
The pull-request action uses DOCS_BOT_PAT with GITHUB_TOKEN as fallback.

Estimated code review effort: 4 (Complex) | ~40 minutes

Possibly related PRs

  • edenai/docs#50: Updates workflow authentication with the same PAT and token fallback.
  • edenai/docs#83: Updates feature navigation and TechArticle/MDX schema generation used by the feature pipeline.

Poem

A rabbit watched the tables gleam,
Preserved old dates within the stream.
New paths hopped into their place,
While tokens helped the workflow race.
Safe pages stayed through every flow—
Fresh docs now bloom and grow!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: fixing the feature-docs generator workflow after repeated failures.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fahima/fix-feature-docs-pipeline

Comment @coderabbitai help to get the list of available commands.

@mintlify

mintlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
edenai 🟢 Ready View Preview Jul 27, 2026, 11:44 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/generate_features.py (1)

505-508: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not assign today’s publication date to an existing partially dated page.

If an existing page has dateModified but no datePublished, Line 507 assigns today, despite the requirement that only new pages receive current dates. Resolve partial pairs before using the new-page fallback.

Proposed fix
-    date_published = date_published or today
-    date_modified = date_modified or date_published
+    if not date_published and not date_modified:
+        date_published = date_modified = today
+    elif not date_published:
+        date_published = date_modified
+    elif not date_modified:
+        date_modified = date_published
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/generate_features.py` around lines 505 - 508, Update the date
initialization flow around _existing_schema_dates so an existing page with only
dateModified receives a resolved publication date before applying the today
fallback. Reserve today’s date for genuinely new pages, while preserving the
existing datePublished/dateModified values and ensuring the final pair remains
consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/generate_features.py`:
- Around line 132-140: Update _render_techarticle_schema() to pass the value
returned by feature_section_name() through _js_str() before inserting it into
the raw articleSection attribute, matching the existing title and description
escaping while preserving the shared section-name source.

---

Outside diff comments:
In `@scripts/generate_features.py`:
- Around line 505-508: Update the date initialization flow around
_existing_schema_dates so an existing page with only dateModified receives a
resolved publication date before applying the today fallback. Reserve today’s
date for genuinely new pages, while preserving the existing
datePublished/dateModified values and ensuring the final pair remains
consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 05427e35-cfb9-44b2-b566-164d42632a7a

📥 Commits

Reviewing files that changed from the base of the PR and between f76dd83 and 485606e.

📒 Files selected for processing (1)
  • scripts/generate_features.py

Comment thread scripts/generate_features.py
FahimaGold added a commit that referenced this pull request Jul 27, 2026
Regenerated on top of the generator fixes in #80:

- image/generation: reference_images type is now escaped as
  `array[file_input \| object]`. The unescaped pipe was splitting the cell, so
  Required rendered as "object]" and the description was dropped.
- web/* (7 pages): articleSection "Expert Models" -> "Web Features",
  about "AI API" -> "Web Data API", keywords now web scraping / web search.
  Nav icon cube -> globe.
- video/* (2 pages): articleSection "Video Generation Features" -> "Video
  Features", matching the nav label; keywords gain "video analysis" so the
  deepfake page is not tagged as generation.

Also picks up upstream API drift since the previous commit: 18 output-schema
rows disappeared from four web pages (html, screenshot, structured_data,
metadata on scraping / crawl-async / batch-scrape-async; six fields on search).
/v3/info now advertises 13 output fields for web/scraping where it advertised 17
an hour ago, consistently across repeated calls. Worth confirming that firecrawl
really dropped them rather than this being an in-flight deploy.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/generate_features.py`:
- Around line 777-792: Update the error handling around fetch_subfeature_detail
to catch only its documented transport/response exception types, allowing
programming errors and malformed-response failures to propagate instead of
reaching the stale-page continue path. Preserve the existing behavior for
handled fetch failures, and add exception chaining with from e when raising
SystemExit on the no-existing-page abort path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 781792fc-3a95-4fe0-b8f4-5602dff173ef

📥 Commits

Reviewing files that changed from the base of the PR and between 485606e and 7ba8aa9.

📒 Files selected for processing (1)
  • scripts/generate_features.py

Comment thread scripts/generate_features.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
scripts/generate_features.py (1)

197-197: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Alias lookup is exact-match only. "Seconde" or " seconde" from the API bypasses normalization. A normalized key lookup is cheap insurance.

♻️ Proposed tweak
-    unit_type = _UNIT_ALIASES.get(unit_type, unit_type)
+    unit_type = _UNIT_ALIASES.get(unit_type.strip().lower(), unit_type)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/generate_features.py` at line 197, Update the alias lookup in the
unit normalization flow to normalize unit_type before querying _UNIT_ALIASES,
including trimming surrounding whitespace and applying the existing
case-normalization convention. Preserve the current fallback behavior when no
alias matches.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/generate_features.py`:
- Line 197: Update the alias lookup in the unit normalization flow to normalize
unit_type before querying _UNIT_ALIASES, including trimming surrounding
whitespace and applying the existing case-normalization convention. Preserve the
current fallback behavior when no alias matches.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2a024cb-2db3-48bf-9a56-e42a32016bd9

📥 Commits

Reviewing files that changed from the base of the PR and between 7ba8aa9 and a0dcc84.

📒 Files selected for processing (2)
  • .github/workflows/generate-features.yml
  • scripts/generate_features.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/generate-features.yml

FahimaGold added a commit that referenced this pull request Jul 27, 2026
Regenerated from current main with the generator fixes in #80. Rebuilt on top of
main (which now carries the hand-committed web pages from #83) rather than
rebased, so there are no conflict artifacts and the diff is exactly what the
pipeline produces from today's API.

Pricing (provider rows 195 -> 225):
- 16 corrected prices, incl. image/generation/openai $0.08 -> $0.034,
  ocr/financial_parser/veryfi $0.08 -> $0.16, video bytedance
  $1.8/1M tokens -> $0.05/second, NER openai $40/1M chars -> $10/1M tokens
- 33 new provider rows (Google Imagen, gpt-image-*, sora-2-pro, pixverse)
- 3 rows dropped for retired models (dall-e-2, dall-e-3, seedance-1-0-lite)
- 14 units corrected from "seconde" to "second"

Pages:
- new: image/face-recognition, video/deepfake-detection-async
- features/index.mdx gains the Web section. #83 added the web pages and their
  nav by hand but did not regenerate the index, so the feature index in prod has
  no Web cards at all.
- two broken tables repaired: the tts `voice` row and explicit_content
  `subcategory` row had embedded newlines that ended the table early and spilled
  ~30 lines of prose into the page body.
- image/generation reference_images type escaped as `array[file_input \| object]`

Metadata: web/* and video/* articleSection now match their nav group, with
per-category about/keywords instead of the generic fallback.

Nav: Web Features moves into API order, face-recognition and
deepfake-detection-async added, "Video Generation Features" -> "Video Features".

Quick Start examples for image ai_detection and deepfake_detection now use
resemble, which the API returns first for those subfeatures.

No dateModified edits — update-dates.yml owns those.

Verified: 1,070 table rows across 36 pages, zero malformed.
FahimaGold added a commit that referenced this pull request Jul 27, 2026
All four from CodeRabbit on #80; the first two are regressions from the earlier
commits in this PR.

- Escape articleSection. Deriving it from the API replaced a hardcoded literal
  with attacker-adjacent data written straight into articleSection="...", so a
  quote in a category name would end the attribute and break the MDX. Render it
  through _js_str() as a template literal, like title/description/about.
  Verified quotes, backticks, ${ and backslashes all come out inert.

- Don't stamp today's date on an existing page that has dateModified but no
  datePublished; that dated publication after modification. Fall back to the
  page's own dateModified.

- Only swallow fetch failures. The keep-the-old-page path caught bare Exception,
  so a bug in this script or a malformed response would be reported as a
  successful run with a stale page. Restrict to URLError / TimeoutError /
  JSONDecodeError and chain the abort with `from e`.

- Normalise unit_type before the alias lookup, so " Seconde " and "SECONDE"
  resolve like "seconde" instead of reaching the output raw.

Verified: 1,070 table rows across 36 pages still well-formed, zero date churn,
a simulated TypeError now propagates while a URLError still preserves the page.
The generate-features workflow has failed on every run since 2026-05-12
(76 consecutive failures). Generation itself succeeds; the create-pull-request
step is what fails, because it force-pushes as github-actions[bot] (Write role)
and the agent-block ruleset rejects create/update/force-push on every ref
outside refs/heads/edenai-assistant/**:

    remote: error: GH013: Repository rule violations found
    remote: - Cannot force-push to this branch
    remote: - Cannot update this protected ref

Same failure and same fix as update-dates.yml (#50), which was never applied
here. Falls back to GITHUB_TOKEN so the step still runs without the secret.
The generator wrote a fixed dateModified="2026-05-06" into every page it
produced, so each run reset the value that update-dates.yml had bumped. PR #13
shows the effect: 24 of its 27 files change nothing except dateModified going
backwards from 2026-05-07 to 2026-05-06.

Read both dates back off the existing page and reuse them; only a page that
does not exist yet gets today's date. dateModified stays owned by
update-dates.yml, which bumps it when content actually changes.

Verified against the live API: regenerating all 36 pages now produces zero
date-only diffs.
update_docs_json walked navigation → V3 → tab "V3 Documentation" → group
"V3 Documentation" → pages, looking for a nested "Expert Models" dict. But
"Expert Models" is a sibling top-level group of "V3 Documentation", not a
child of it, so the loop matched nothing and the function silently no-opped.
New feature pages were written to disk and never added to the nav.

Against the live API that currently hides 10 pages: web/ (7 firecrawl
subfeatures), image/face-recognition and video/deepfake-detection-async.

Search the V3 tabs for the group instead of assuming a fixed depth, and exit
non-zero if it is missing — quietly skipping the update is what hid this. The
legacy "AI Features" removal stays scoped to the V3 Documentation group so the
V3 API Reference tab keeps its own "AI Features" group.
The /v3/info API returns some price units as "seconde", which flowed verbatim
into published pricing tables ("$0.05 per seconde"). Currently affects 13 rows
across the video pages.
An unescaped pipe in a cell value ends the cell early and shifts every later
column left, silently corrupting the row. The API now returns a union type for
image/generation: `array[file_input | object]`, which rendered as
Type=`array[file_input`, Required=`object]`, Description=`No`, with the real
description pushed into a phantom fifth column that renderers drop.

Escape cell values in both the schema and provider tables.
The nav group title was derived from the API while the JSON-LD articleSection
was hardcoded in _FEATURE_SCHEMA_META, so the two drifted. video's nav label
became "Video Features" as soon as it gained a second subfeature, while its
pages still declared articleSection "Video Generation Features" and keyword
"video generation" — wrong for deepfake detection. A brand-new category hit the
same gap from the other side: web had no entry at all, so its 7 pages fell back
to generic metadata and a "cube" icon.

feature_section_name() is now the single source of truth for both the nav group
and articleSection, so they cannot diverge and a new category needs no entry to
be labelled correctly.

_FEATURE_SCHEMA_META keeps only `about` and `keywords`, which have no
counterpart in /v3/info (per category it exposes just name, fullname — a repeat
of name — description, and subfeatures), plus a `web` entry and a globe icon.

Verified: articleSection matches the nav group for all 7 categories.
Found by auditing every live schema plus a synthetic new-category run.

1. Collapse whitespace in table cells. A newline in a cell value terminates the
   row mid-sentence and ends the table, spilling the remainder into the page as
   loose prose. Two live descriptions do this today, so main is publishing two
   broken tables right now: the tts `voice` field and explicit_content
   `subcategory`. _cell() now collapses whitespace runs before escaping pipes.

2. Never overwrite a good page with a gutted one. A failed detail fetch left
   detail={}, which renders "_No schema information available._" and drops both
   schema tables — so one transient 5xx during the daily run would open a PR
   that silently strips documentation. Now the existing page is kept, and if
   there is no page to keep the run aborts instead of publishing an empty one.

3. Don't double the plural when the API already sends one: a unit_type of
   "tokens" rendered as "per 1,000 tokenss". Latent today (every live unit is
   singular), but the next new unit would hit it.

Verified: 1,070 table rows across 36 pages, zero malformed. A synthetic unknown
category generates pages, derives articleSection, lands in the nav with the
fallback icon, and escapes pipes in provider labels; simulated API failures
preserve or abort as intended; a removed subfeature is cleaned from disk and nav.
All four from CodeRabbit on #80; the first two are regressions from the earlier
commits in this PR.

- Escape articleSection. Deriving it from the API replaced a hardcoded literal
  with attacker-adjacent data written straight into articleSection="...", so a
  quote in a category name would end the attribute and break the MDX. Render it
  through _js_str() as a template literal, like title/description/about.
  Verified quotes, backticks, ${ and backslashes all come out inert.

- Don't stamp today's date on an existing page that has dateModified but no
  datePublished; that dated publication after modification. Fall back to the
  page's own dateModified.

- Only swallow fetch failures. The keep-the-old-page path caught bare Exception,
  so a bug in this script or a malformed response would be reported as a
  successful run with a stale page. Restrict to URLError / TimeoutError /
  JSONDecodeError and chain the abort with `from e`.

- Normalise unit_type before the alias lookup, so " Seconde " and "SECONDE"
  resolve like "seconde" instead of reaching the output raw.

Verified: 1,070 table rows across 36 pages still well-formed, zero date churn,
a simulated TypeError now propagates while a URLError still preserves the page.
@FahimaGold
FahimaGold force-pushed the fahima/fix-feature-docs-pipeline branch from 67c8bc6 to a4dabfa Compare July 27, 2026 18:18
FahimaGold added a commit that referenced this pull request Jul 27, 2026
Regenerated from current main with the generator fixes in #80.

Pricing (provider rows 195 -> 225):
- 16 corrected prices, incl. image/generation/openai $0.08 -> $0.034,
  ocr/financial_parser/veryfi $0.08 -> $0.16, video bytedance
  $1.8/1M tokens -> $0.05/second, NER openai $40/1M chars -> $10/1M tokens
- 33 new provider rows (Google Imagen, gpt-image-*, sora-2-pro, pixverse)
- 3 rows dropped for retired models (dall-e-2, dall-e-3, seedance-1-0-lite)
- 14 units corrected from "seconde" to "second"

Pages:
- new: image/face-recognition, video/deepfake-detection-async
- features/index.mdx gains the Web section; #83 added the web pages and nav by
  hand without regenerating the index, so prod has no Web cards
- two broken tables repaired: the tts `voice` and explicit_content
  `subcategory` rows had newlines that ended the table early
- image/generation reference_images escaped as `array[file_input \| object]`

Metadata: articleSection is now a JSX template literal on all 36 pages and
matches each page's nav group; web/* and video/* get real about/keywords.

Nav: Web Features moves into API order, the two new pages are added,
"Video Generation Features" -> "Video Features".

Verified: 1,070 table rows, zero malformed, zero date churn.
@FahimaGold
FahimaGold merged commit 0ca46a0 into main Jul 27, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant