Lint & Fix Workflow
Trigger: lint directive, or any time the user asks to βfix errorsβ, βfix issuesβ, or βclean up the specβ.
Phase 1 β Fetch issues
get_system_status()If the result is an empty list, report βNo issues foundβ and stop.
Group the returned issues by file. Within each file group, deduplicate issues with the same path and message (the compiler can emit the same error twice for the same attribute in some edge cases). Report the triage summary:
{n} issues in {m} files (errors: {x}, warnings: {y})Phase 2 β Classify each issue
For each issue, determine its class before touching any file:
| Class | How to recognise | Fix strategy |
|---|---|---|
| Missing required attribute | message: "Required" + path ends in an attribute name (e.g. .source, .reaction, .type, .code) | Add the missing attribute with a reasonable default or a TODO value |
| Wrong property name format | message contains "camelCase or kebab-case" | The name attribute on a \{% property %\} tag uses camelCase; convert to kebab-case |
| Wrong id prefix | message contains "must start with" or "invalid prefix" | Rename the id or name attribute to use the correct prefix from the naming table |
| Unknown attribute / wrong attribute name | message contains "unknown attribute" or "did you mean" | An agent used the wrong attribute name on a tag; rename to the correct one |
| Broken cross-document reference | type: "link" | The qualified id does not resolve; check if the target was renamed or mistyped |
| Semantic / logic issue | type: "semantic" | Requires judgment β do not auto-fix; flag for the user |
Skip any issue whose class is semantic or link β report them as βrequires manual reviewβ and move on.
Phase 3 β Fix file by file
For each file that has at least one auto-fixable issue:
- Read the file in full β never edit blindly.
- Apply all fixes for that file in one pass β do not write between each fix.
- Prefer the narrowest edit: change only the failing attribute, not the surrounding tag structure.
- If a missing required attribute has no obvious value (e.g.
sourceon a\{% policy %\}with no trigger context), writesource="TODO"and note it in the report. - Write the corrected file and record what changed.
Common fixes quick-reference:
| Error path pattern | Tag | Fix |
|---|---|---|
tag:policy.source | {% policy %} | Add source="TODO" attribute |
tag:policy.reaction | \{% policy %\} | Add reaction="TODO" attribute |
tag:operation[...].type | \{% operation %\} | Add type="query" or type="command" based on the operation name |
tag:error[...].code β Required | \{% error %\} | Add code="TODO" attribute |
tag:error[...].code β SCREAMING_SNAKE_CASE | \{% error %\} | Code must be SCREAMING_SNAKE_CASE (e.g. NOT_FOUND, VALIDATION_FAILED). Convert the error id to SCREAMING_SNAKE_CASE: task-type-not-found β TASK_TYPE_NOT_FOUND. Never use integer HTTP codes. |
tag:rule[...].force β Required | \{% rule %\} | Add force="must" or force="should" based on constraint strength. Default to force="must" unless the rule is advisory. |
frontmatter.tags β Expected array, received string | Any .mdoc frontmatter | tags must be a YAML array, not a space-separated string. Convert tags: foo bar baz β tags: [foo, bar, baz]. |
tag:property[...].name β camelCase | \{% property %\} | Rename name="fooBarBaz" β name="foo-bar-baz" |
tag:*.properties.N.name β camelCase | inline \{% property %\} inside action/event/operation | Same: convert name to kebab-case |
Wrong attribute name pattern: When an agent confuses attribute names (e.g. writes trigger= instead of source=, or body= instead of reaction=), the error appears as "unknown attribute". Read the tag schema from get_instructions("starspec/tag/{tagname}") if unsure of the correct attribute name before fixing.
Phase 4 β Re-verify
After all files have been written, call get_system_status() again. Compare the new issue list against the original:
- Issues resolved β list them as fixed
- Issues remaining that were auto-fixable β escalate to user (something structural may be wrong)
- Issues remaining that were skipped (semantic/link) β list them as βrequires manual reviewβ
Phase 5 β Report
Output a concise summary:
Lint complete β {n} fixed, {m} require manual review
Fixed: domains/foo.domain.mdoc β added policy.source, policy.reaction domains/bar.domain.mdoc β converted 3 property names to kebab-case
Requires manual review: flows/baz.flow.mdoc β broken ref: feature/nonexistent (link error) domains/qux.domain.mdoc β semantic: step order inconsistencyDo not re-display the quick-reference card after a lint run β the user is in a fix-focused context, not a creation context.
Doβs and Donβts
Do:
- Read each file in full before editing β never edit blindly
- Apply all fixes for a file in one pass
- Prefer the narrowest edit: change only the failing attribute, not the surrounding tag structure
- Re-verify with
get_system_status()after all fixes are applied - Report both fixed and remaining issues in the summary
Donβt:
- Auto-fix semantic or link issues β flag them for manual review
- Re-display the quick-reference card after a lint run
- Write
TODOvalues when a reasonable default can be inferred from context - Write between individual fixes for the same file
Definition of Done
- All lint issues classified (error, warning, info)
- All errors fixed or explicitly deferred by user
- Re-lint returns zero errors