Skip to content
Model Sanitization Workflow
AutoXXS (320px)XS (375px)SM (640px)MD (768px)LG (1024px)XL (1280px)XXL (1536px)
SketchMaterialiOSTamagui
DataInjectionKeyPatternsServiceTransactionProcessResearchProductQualityPerformanceSpecDomainFunctionTechnologyArchitectureConfigMiddlewareDataDatabaseDrizzleMigrationModelop-sqliteSchemaSQLState ManagementDraftKeystoneMergePatchPatchesPersistenceReactiveRedoStoreUndoTestingDeviceFactoryIsolationTypeScriptZodTopicsCommunicationBidsNVCDesignDesign ImplicationsEducationPedagogyFoundationsPsychologyAttachmentFloodingRelatingAuthentic RelatingUIEditorReact Native

Model Sanitization Workflow

Workflow Model Sanitization Workflow
agent starfix
tags
workflowsanitize

Trigger: sanitize directive, or any time the user asks to “clean up the model”, “fix model issues”, or “check document quality”.

This workflow applies semantic rules that go beyond schema validation — it detects documents where content is placed in the wrong tag type or where relationships are expressed as prose instead of structured references. Unlike lint, it does not call get_system_status; it reads documents directly and applies the rules below.

Rules

Each rule has a detection hint (how to spot the problem) and a fix (what to change).


Rule S-1 — Policy that is actually a requirement

Detection: A {% policy %} block whose body describes a constraint, invariant, or property of the system — not a reactive “when X, then Y” rule. These often read as declarative statements of fact or obligation.

Hint phrases: “is stored”, “must be”, “are encrypted”, “is limited to”, “only”, “always”, “never” — without a causal trigger clause.

Example (wrong tag):

\{% policy id="local-storage" %\}
All data is stored locally.
\{% /policy %\}

Fix: Convert to \{% requirement %\} with an appropriate id, priority, and optionally scope. Remove the \{% policy %\} block.

\{% requirement id="local-storage" priority="must" %\}
All data must be stored locally on the user's device.
\{% /requirement %\}

Detection: A \{% policy %\} block whose body describes a reactive flow in prose — “when X happens, Y is triggered” — but whose source and reaction attributes are missing, set to TODO, or do not match the bare name of a declared API item.

Hint phrases: “when”, ”→”, “automatically”, “triggers”, “is triggered”, “upon”, “after”, “on”.

Example (missing links):

\{% policy id="auto-transcribe" %\}
When SessionEnded → automatically trigger transcription.
\{% /policy %\}

Fix: Add source (referencing the declared \{% event %\}) and reaction (referencing the declared \{% action %\}) attributes. If the referenced event or action does not yet exist in an \{% api %\} block, add it there first.

\{% policy id="auto-transcribe" source="session-ended" reaction="start-transcription" %\}
When a session ends, transcription is automatically started.
\{% /policy %\}

If the required event or action does not exist anywhere in the domain, create it in the appropriate \{% api %\} block before writing the policy reference.


Rule S-3 — Root tag id uses a type prefix

Detection: The root document tag (\{% feature %\}, \{% domain %\}, \{% role %\}, etc.) has an id attribute that includes a type prefix — e.g. id="domain:conversation" or id="feature:structured-formats". The compiler rejects this because the root tag id must match the frontmatter id exactly.

Why it happens: Agents apply the in-document child-tag convention ({type}:{name}) to root tags, where it does not apply. Type prefixes are only for in-document child tags (req:, action:, policy:, etc.) — never for the root document tag.

Hint: The compiler error reads: Root tag ID "…" does not match frontmatter ID "…".

Example (wrong):

---
id: conversation
---
\{% domain id="domain:conversation" scope="public agent" %\}

Fix: Strip the type prefix so the root tag id matches the frontmatter id exactly.

\{% domain id="conversation" scope="public agent" %\}

Rule S-4 — Error definition missing a code

Detection: A \{% error %\} tag has no code attribute. The compiler reports this as a required-field schema error on the path tag:error[name].code.

Hint: get_system_status() returns entries with path matching tag:error[...].code and message: "Required".

Example (missing code):

\{% error id="recording-failed" %\}
Raised when the audio device cannot be initialised.
\{% /error %\}

Fix: Add a code attribute. Infer an appropriate value from the error name using HTTP-style conventions; use "TODO" only when no reasonable value can be determined.

Error name patternSuggested code
*-not-found404
*-failed, *-error500
*-invalid, *-rejected422
*-forbidden, *-denied403
*-conflict, *-duplicate409
Anything else"TODO"
\{% error id="recording-failed" code="500" %\}
Raised when the audio device cannot be initialised.
\{% /error %\}

Rule S-5 — Cross-document reference using wrong format

Detection: Cross-document references in context frontmatter or in tag attributes (domains, roles, feature, implements, ref, etc.) that use:

  • An unqualified id — e.g. memory-reflection instead of domain/memory-reflection
  • The : separator instead of / — e.g. domain:memory-reflection, role:user

Hint: get_system_status() returns type: "link" warnings with messages like "context ref not found: \"X\"" where X is unqualified or uses :.

Example (wrong):

context: [memory-reflection, role:user]
\{% feature domains="domain:memory-reflection" roles="user" %\}

Fix: Qualify all cross-document refs using {type}/{id} format with / as separator. First confirm the target document exists by checking content/{type}/ or calling get_document. Apply the fix to both frontmatter and tag attributes in the same file in one pass.

context: [domain/memory-reflection, role/user]
\{% feature domains="memory-reflection" roles="user" %\}

Auto-fixable: Yes — when the target document exists and can be identified. If the ref cannot be resolved to a known document (the target file is missing), flag for manual review.


Procedure

  1. Fetch current issues.

    get_system_status()

    Use the returned issue list to scope the work — prioritise files that already have reported errors. If the result is empty, proceed to step 2 with no pre-scoped files.

  2. Identify scope. If the user names a file or domain, restrict to that. Otherwise apply to all content/ files that have reported issues — including link warnings — or that contain \{% policy %\} blocks.

  3. Read each file in full before making any judgement — never edit blindly.

  4. Apply each rule independently. A single policy block may trigger more than one rule.

  5. For each violation, confirm the intended semantics with the user before rewriting — converting a policy to a requirement is a structural change.

  6. Write corrected files one at a time. Apply all fixes for a file in a single write pass.

  7. Report using the format:

Sanitize complete — {n} issues fixed, {m} flagged for review
Fixed:
domains/session.domain.mdoc — S-1: converted policy local-storage → requirement local-storage
domains/session.domain.mdoc — S-2: added source/reaction links to policy auto-transcribe
Flagged for review:
domains/recording.domain.mdoc — S-2: policy cleanup-on-error references no declared event (manual check needed)

Do’s and Don’ts

Do:

  • Read each file in full before making any judgement
  • Apply each rule independently — a single block may trigger more than one rule
  • Confirm the intended semantics with the user before rewriting (converting a policy to a requirement is a structural change)
  • Write corrected files one at a time with all fixes for a file in a single write pass
  • Create missing events or actions in the appropriate \{% api %\} block before writing policy references

Don’t:

  • Edit files blindly without reading them first
  • Auto-fix without user confirmation — structural changes require approval
  • Mix fixes across multiple files in a single write pass
  • Flag issues that can be resolved by checking existing declared API items

Definition of Done

  • All applicable rules (S-1 through S-5) checked against scoped files
  • All fixes confirmed by user before writing
  • Sanitization report output with fixed and flagged counts