How Canonical Application States in `templates/states.yml` Ensure Consistent Status Tracking

The templates/states.yml file serves as the single source of truth for all application statuses, with merge-tracker.mjs enforcing these definitions at merge time to prevent invalid values from polluting the tracker.

In the santifer/career-ops repository, maintaining data integrity across multilingual job applications requires a centralized schema. The canonical application states defined in templates/states.yml standardize how every status—from "Applied" to "Evaluated"—is written, validated, and rendered across both the tracker and the dashboard.

The Single Source of Truth

templates/states.yml defines every allowable state exactly once, establishing a contract that both the data pipeline and the user interface must honor. Each state entry includes a unique identifier, a human-readable label, language-specific aliases, and a descriptive explanation.

The header comment on lines 1–4 explicitly mandates that both the writer (Career-Ops scripts) and the dashboard must use these exact values. This prevents drift between what gets stored in data/applications.md and what the user interface expects to display.


# Example structure from templates/states.yml

- id: applied
  label: Applied
  aliases: [aplicado, candidatado]
  description: Application submitted, awaiting response

Validation Pipeline in merge-tracker.mjs

When new entries are merged into data/applications.md, the merge-tracker.mjs script executes a strict validation sequence through the validateStatus() function.

Canonical State Matching

The validator first normalizes the raw input by stripping markdown bold markers and stray dates. It then compares the cleaned value against the CANONICAL_STATES constant defined on lines 52–54. Direct matches pass through unchanged.

Alias Resolution

If the value does not match a canonical label directly, the function checks the alias map on lines 65–74. This map mirrors the aliases field in states.yml, allowing inputs like "aplicado" to resolve to the canonical "Applied" state.

Fallback Handling

Any value that fails both checks triggers a warning log on line 82 and is coerced to Evaluated (lines 82–84). This prevents rogue strings from entering the tracker while preserving the data row.

Practical Examples

The following TSV patterns demonstrate how the validation layer handles different input scenarios:

Example 1: Direct canonical match

1	2026-06-10	Acme Corp	Senior Data Engineer	Applied	4.2/5	reports/001-acme-2026-06-10.md	First contact

validateStatus('Applied') finds an exact match in CANONICAL_STATES and stores the value unchanged.

Example 2: Spanish alias resolution

2	2026-06-11	TechCo	Backend Engineer	aplicado	3.8/5	reports/002-techco-2026-06-11.md	Skipped after interview

The function locates "aplicado" in the alias map (lines 66–68) and converts it to Applied before writing the row.

Example 3: Invalid status fallback

3	2026-06-12	StartupX	Full-Stack Engineer	unknown_status	4.0/5	reports/003-startupx-2026-06-12.md	-

The validator rejects unknown_status, logs a warning, and substitutes Evaluated to maintain schema integrity.

Bidirectional Safety

The architecture ensures consistency across both data ingress and egress.

  • Writer side: All scripts that generate tracker rows—including batch/tracker-additions/*.tsv handlers—must supply a status field matching either a canonical label or a supported alias. The validation step in merge-tracker.mjs guarantees only these values reach data/applications.md.

  • Reader side: The dashboard components (located in src/dashboard/…) load templates/states.yml directly to render status filters, color coding, and statistical aggregations. Because the UI and the pipeline share the same YAML file, any modification to a label or alias automatically propagates to both systems without code changes.

Extending States Without Breaking Changes

Adding a new application state requires only two steps: appending a new - id: block to templates/states.yml and optionally extending the alias map in merge-tracker.mjs. The validation logic immediately accepts the new label, and the dashboard instantly recognizes it, eliminating deployment coordination between the data pipeline and the frontend.

Summary

  • templates/states.yml defines the complete, version-controlled set of allowable application statuses and their multilingual aliases.
  • merge-tracker.mjs enforces these definitions through the validateStatus() function, normalizing inputs and coercing invalid values to Evaluated.
  • Bidirectional loading ensures the dashboard and the tracker remain synchronized by reading from the same YAML source.
  • Alias support permits natural language inputs while maintaining canonical data storage.

Frequently Asked Questions

What happens if I submit a status that is not defined in states.yml?

The validateStatus() function in merge-tracker.mjs logs a warning and coerces the value to Evaluated (lines 82–84). This prevents schema corruption while preserving the application record.

How does the dashboard stay synchronized with the tracker data?

The dashboard UI loads templates/states.yml directly to generate filter options and color mappings. Because both the writer (merge script) and reader (dashboard) consume the same file, changes to state definitions apply instantly to both systems.

Can I add custom aliases for existing states without modifying the code?

Yes. Add new aliases to the aliases array in templates/states.yml. For the validation pipeline to recognize them immediately, you may also need to update the alias map in merge-tracker.mjs (lines 65–74), though the YAML change alone suffices for dashboard rendering.

Where is the validation logic implemented in the codebase?

The primary validation logic resides in merge-tracker.mjs, specifically within the validateStatus() function (lines 52–84). This function references the CANONICAL_STATES constant and the alias map to normalize and verify all incoming status values.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →