Fix module section heading collisions#73
Conversation
Ravion Module Publish PlanDry run only. No Ravion API mutations were made.
Diffsrvn-aws-static 0.3.4 -> 0.3.5--- remote
+++ compiled
type: string
values: $values:aws/regions
- id: section_hosting
- label: Static hosting
+ label: Static hosting config
type: section
- default: <<project.given_id>>-<<environment.given_id>>-<<module.given_id>>
description: Name for the bucket and other resources' prefix. Must be globally unique.
@@
Every deployment is versioned. The deploy step promotes an S3 directory by updating the CloudFront KeyValueStore active pointer. CloudFront rewrites viewer requests to the active version prefix before it reads from S3.
- Terraform source: [flightcontrolhq/modules/hosting/static_site](https://github.com/flightcontrolhq/modules/tree/rvn-aws-static@0.3.4/hosting/static_site)
+ Terraform source: [flightcontrolhq/modules/hosting/static_site](https://github.com/flightcontrolhq/modules/tree/rvn-aws-static@0.3.5/hosting/static_site)
## Use cases
@@
base_path: hosting/static_site
branch: main
execution_environment_id: << module.input.execution_environment_id >>
- ref: rvn-aws-static@0.3.4
+ ref: rvn-aws-static@0.3.5
repo: https://github.com/flightcontrolhq/modules
stack_id: <<stack.id>>
terraform_variables:rvn-ec2-service 0.1.1 -> 0.1.2--- remote
+++ compiled
label: Run in private subnets
type: boolean
- id: section_service
- label: EC2 service
+ label: EC2 service config
type: section
- default: <<project.given_id>>-<<environment.given_id>>-<<module.given_id>>
description: Name for the instance group and related resources.
@@
Ravion provisions the launch template, Auto Scaling Group, instance role and security group, SSM deploy document, app log group, and optional target group and listener rule. Web services can attach to a standalone Application Load Balancer or reuse the public or private ALB from an ECS cluster. The selected network and load balancer must use the same AWS account, region, and VPC. The Auto Scaling Group can still terminate instances because of scaling, health failures, or operator action. Root and data EBS volumes survive releases, but not instance termination.
- Terraform source: [flightcontrolhq/modules/compute/ec2_service](https://github.com/flightcontrolhq/modules/tree/rvn-ec2-service@0.1.1/compute/ec2_service)
+ Terraform source: [flightcontrolhq/modules/compute/ec2_service](https://github.com/flightcontrolhq/modules/tree/rvn-ec2-service@0.1.2/compute/ec2_service)
## Use cases
@@
base_path: compute/ec2_service
branch: main
execution_environment_id: << module.input.execution_environment_id >>
- ref: rvn-ec2-service@0.1.1
+ ref: rvn-ec2-service@0.1.2
repo: https://github.com/flightcontrolhq/modules
stack_id: <<stack.id>>
terraform_variables:rvn-ecs-cluster 0.3.1 -> 0.3.2--- remote
+++ compiled
required: true
type: $ref:rvn-aws-network
- id: section_cluster
- label: ECS cluster
+ label: ECS cluster config
type: section
- default: <<project.given_id>>-<<environment.given_id>>
description: Name prefix for all resources. Terraform requires 1-28 characters so generated ALB names fit AWS limits.
@@
- **Public and private Network Load Balancers** for TCP/UDP and static IP use cases
- **CloudWatch Container Insights** dashboard metrics for production visibility
- Terraform source: [flightcontrolhq/modules/compute/ecs_cluster](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-cluster@0.3.1/compute/ecs_cluster)
+ Terraform source: [flightcontrolhq/modules/compute/ecs_cluster](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-cluster@0.3.2/compute/ecs_cluster)
## Use cases
@@
base_path: compute/ecs_cluster
branch: main
execution_environment_id: << module.input.execution_environment_id >>
- ref: rvn-ecs-cluster@0.3.1
+ ref: rvn-ecs-cluster@0.3.2
repo: https://github.com/flightcontrolhq/modules
stack_id: <<stack.id>>
terraform_variables:rvn-lambda 0.3.2 -> 0.3.3--- remote
+++ compiled
type: string
values: $values:aws/regions
- id: section_function
- label: Lambda function
+ label: Lambda function config
type: section
- default: regional
id: lambda_type
@@
The Lambda Function module creates an AWS Lambda function, execution role, CloudWatch log group, optional artifact bucket, and a live alias that Ravion updates during deployments. Terraform provisions the long-lived function infrastructure with either a bootstrap zip package or a bootstrap container image. Deployments publish a new function version and move the live alias.
- Terraform source: [flightcontrolhq/modules/compute/lambda](https://github.com/flightcontrolhq/modules/tree/rvn-lambda@0.3.2/compute/lambda)
+ Terraform source: [flightcontrolhq/modules/compute/lambda](https://github.com/flightcontrolhq/modules/tree/rvn-lambda@0.3.3/compute/lambda)
## Use cases
@@
base_path: compute/lambda
branch: main
execution_environment_id: << module.input.execution_environment_id >>
- ref: rvn-lambda@0.3.2
+ ref: rvn-lambda@0.3.3
repo: https://github.com/flightcontrolhq/modules
stack_id: <<stack.id>>
terraform_variables: |
|
Closing this PR because section labels are product-facing module configuration. The search-anchor workaround belongs only in docs generation. |
| function slugifyHeading(value: string): string { | ||
| return value | ||
| .trim() | ||
| .toLowerCase() | ||
| .replace(/[^a-z0-9_\s-]/g, "") | ||
| .replace(/\s+/g, "-"); | ||
| } |
There was a problem hiding this comment.
slugifyHeading diverges from Mintlify's actual anchor algorithm
According to Mintlify's documentation, their algorithm preserves & and /, converts . to -, and turns straight apostrophes into right single quotation marks. The current regex .replace(/[^a-z0-9_\s-]/g, "") strips all of these, so a section labeled "Read/write config" would produce readwrite-config here but read/write-config in Mintlify — a real collision against a definition named "Read/Write Config" would pass the guardrail undetected. All current labels are simple English phrases so there is no present defect, but the check could silently miss future collisions that involve &, /, ., or '.
Prompt To Fix With AI
This is a comment left during a code review.
Path: tools/ravion-modules/src/guardrails.ts
Line: 175-181
Comment:
**`slugifyHeading` diverges from Mintlify's actual anchor algorithm**
According to Mintlify's documentation, their algorithm preserves `&` and `/`, converts `.` to `-`, and turns straight apostrophes into right single quotation marks. The current regex `.replace(/[^a-z0-9_\s-]/g, "")` strips all of these, so a section labeled "Read/write config" would produce `readwrite-config` here but `read/write-config` in Mintlify — a real collision against a definition named "Read/Write Config" would pass the guardrail undetected. All current labels are simple English phrases so there is no present defect, but the check could silently miss future collisions that involve `&`, `/`, `.`, or `'`.
How can I resolve this? If you propose a fix, please make it concise.
Summary
Why
Mintlify appends a slugified page title to page-level search links. When a later section has the same slug, selecting the page result jumps to that section instead of the page top.
Verification
npm run typechecknpm test(74 tests)compileAllDefinitions()Greptile Summary
This PR fixes a Mintlify navigation bug where section headings whose slugified labels matched the slugified page title caused search results to jump to the section rather than the page top. It renames the colliding section labels in four definition files and adds a compile-time guardrail to prevent the pattern from reoccurring.
rvn-*-definition.ymlfiles rename their primary section label by appending " config" (e.g. "EC2 service" → "EC2 service config"), each receiving a patch version bump. All new labels follow the sentence-case rule in AGENTS.md.guardrails.tsaddsvalidateSectionLabelsDoNotCollideWithDefinitionNames, which slugifies each section label and compares it against the definition's own name slug;compiler.tswires it intocompileAllDefinitions.guardrails.test.tswrites a real on-disk fixture and asserts the guardrail throws the expectedGuardrailError.Confidence Score: 4/5
Safe to merge. The YAML renames and guardrail logic are correct for all existing module definitions and the new test validates the failure path end-to-end.
The slugifyHeading helper approximates Mintlify's anchor algorithm but strips characters (&, /, .) that Mintlify actually preserves or converts differently. This won't affect any current module labels, which are all plain English phrases, but could silently miss a real collision if a future label or definition name contains those characters.
Files Needing Attention: tools/ravion-modules/src/guardrails.ts — the slugifyHeading regex is worth tightening to match Mintlify's documented algorithm before new modules with special characters in their names are added.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A["compileAllDefinitions()"] --> B["compile each rvn-*-definition.yml"] B --> C["validateUniqueDefinitionTypes()"] C --> D["validateSectionLabelsDoNotCollideWithDefinitionNames()"] D --> E{For each definition} E --> F["slugifyHeading(definition.name)"] E --> G["For each section input:\nslugifyHeading(input.label)"] F --> H{slugs equal?} G --> H H -- Yes --> I["Collect collision"] H -- No --> E I --> J["throw GuardrailError"] D --> K["Return compiled definitions"]Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "fix module section heading collisions" | Re-trigger Greptile