Mapping
Ask gateMap source schemas and systems to target, define transformation rules
Mapping
Translate the assessment inventory into an executable mapping spec — every source field, every transformation rule, every dropped or derived value, every constraint difference. This is the design stage of the migration: it produces the contract the migrate stage implements verbatim, so anything not in the spec is not in the migration.
Scope
Field-level and entity-level mapping plus compatibility analysis. Mapping decides how source maps to target and what transforms apply — not what's in scope (assessment), how the mapping is coded (migrate), or whether the result reconciles (validation). The output is a contract: the migrate stage builds exactly what the spec says and nothing it doesn't.
What to do
- Author the field-level mapping tables — source field, target field, transform rule, null and encoding behavior — for each entity surface.
- Surface compatibility issues (type mismatches, constraint conflicts, semantic gaps, downstream-consumer impact) and key each finding to the mapping row it flags.
- Make every transformation rule precise enough that the migrate stage can implement it without guessing.
- Account for dropped and derived values explicitly, so nothing falls through silently.
What NOT to do
- Don't write the migration code — that's the migrate stage building against this spec.
- Don't re-inventory the source or re-classify risk; consume the assessment inventory as given.
- Don't leave a compatibility finding floating free of the mapping row it concerns.
- Don't leave a transformation underspecified — an ambiguous rule becomes a data defect downstream.
How the engine runs this stage
1Elaborate
collaborative · plan the work, fan out discovery, declare outputsInputs consumed
Discovery fan-out
knowledge artifactMapping SpecDocument field-level source-to-target mappings and transformation rules. This output feeds the migrate stage as the blueprint for implementation.
Mapping Specification
Document field-level source-to-target mappings and transformation rules. This output feeds the migrate stage as the blueprint for implementation.
Content Guide
Structure the specification by entity:
- Entity mappings — source entity to target entity with mapping rationale
- Field-level mappings — every source field mapped to a target field with transformation rule
- Transformation rules — renames, type casts, derivations, default fills, drops
- Edge-case handling — nulls, encoding differences, precision loss, constraint violations
- Compatibility issues — type mismatches, semantic gaps, constraint conflicts with resolutions
- Unmapped fields — fields intentionally dropped with documented rationale
- New target fields — fields in the target with no source equivalent and their default/derivation logic
Quality Signals
- Every source field has an explicit disposition (map, transform, drop) — no gaps
- Transformation rules are deterministic and testable in isolation
- Lossy transformations are flagged with documented data loss implications
- Compatibility review sign-off is recorded with any conditional approvals noted
Phase guidance
phase overrideELABORATION- "Every source field maps to a target field with explicit transformation rules (rename, cast, derive, drop)"
Mapping Stage — Elaboration
Criteria Guidance
Good criteria — concrete and verifiable
- "Every source field maps to a target field with explicit transformation rules (rename, cast, derive, drop)"
- "Incompatible types are listed with chosen resolution strategy and data loss implications"
- "Edge cases document at least: nulls, encoding differences, precision loss, and constraint violations"
Bad criteria — vague (no clear check)
- "Mapping is done"
- "Schemas are compared"
- "Transformations are defined"
Outputs produced
output templateMapping SpecField-level source-to-target mappings with transformation rules and compatibility review.
Mapping Specification
Field-level source-to-target mappings with transformation rules and compatibility review.
Expected Artifacts
- Field mappings -- every source field mapped to target with explicit transformation rule (rename, cast, derive, drop)
- Type compatibility -- incompatible types listed with resolution strategy and data loss implications
- Edge case documentation -- nulls, encoding differences, precision loss, and constraint violations
- Semantic gap analysis -- differences in meaning between source and target schemas
Quality Signals
- Every source field has an explicit mapping to target with transformation rule
- Incompatible types have resolution strategies with data loss implications documented
- Edge cases are documented for nulls, encoding, precision, and constraints
- All resolution decisions are documented with rationale
2Review
pre-execute · agents audit the planned spec before any code landsreview agentAccuracyThe agent **MUST** verify the mapping spec is correct and complete — every source field accounted for, every target field's origin named, every transformation rule typed (rename / cast / derive / default / drop), every null behavior explicit, every constraint difference resolved. Drift here becomes runtime corruption.
Mandate: The agent MUST verify the mapping spec is correct and complete — every source field accounted for, every target field's origin named, every transformation rule typed (rename / cast / derive / default / drop), every null behavior explicit, every constraint difference resolved. Drift here becomes runtime corruption.
Check
The agent MUST verify, filing feedback for any violation:
- Total field coverage — every source field is in the mapping table, mapped or explicitly dropped with rationale. Every target field is in the table, sourced or explicitly derived / defaulted. Silence on either side is a hard finding.
- Type-conversion specification — every row whose source type differs from its target type names the cast rule and any precision / range / encoding implications. Narrowing casts MUST name the boundary at which data is lost.
- Edge-case handling — every row's null behavior is named. Encoding differences (latin1 vs. utf8, binary vs. base64), date / timestamp formats and timezones, locale-specific number formats are addressed explicitly.
- Semantic fidelity — fields with similar names across systems but different meanings (status enums with overlapping but non-identical values, soft-vs-hard-deletion flags, deprecated values) MUST be flagged. Same name doesn't mean same meaning.
- Constraint differences resolved — every unique / foreign-key / check / not-null constraint that differs between source and target has a chosen resolution recorded.
- Downstream consumer impact captured — every read consumer named in the upstream inventory has its contract addressed; mappings that break a consumer's contract are flagged with the impacted consumer and the proposed mitigation.
- Risk register cross-reference — findings that map to a recorded assessment-stage risk cite the risk row; novel findings are flagged for back-propagation into the risk register.
Common failure modes to look for
- A source field with no row in the mapping table (silent drop)
- A target field with no row in the mapping table (silent default)
- A transform rule written in prose instead of using the typed categories
- "TBD" sitting in the table without a follow-up action
- Encoding differences treated as "should be fine" without explicit verification
- Enum values mapped 1:1 by string equality when the source and target enums have diverged
- Foreign-key constraints dropped on the target without acknowledging orphan-row risk
- Integration mappings that change error-code semantics without flagging the downstream consumer impact
- Compatibility findings cited at the table level rather than at specific rows
3Execute
per-unit baton · Schema Mapper → Compatibility Reviewer → Verifierhat 1Compatibility ReviewerRead the schema-mapper's mapping rows for this unit and produce the compatibility analysis — type mismatches that risk data loss, constraint conflicts that will cause runtime failures, semantic gaps where source and target concepts diverge, and downstream-consumer impacts. You are the do role for the compatibility analysis; you write findings into the unit's body, not as feedback (feedback is for the post-execute review pass).
Focus: Read the schema-mapper's mapping rows for this unit and produce the compatibility analysis — type mismatches that risk data loss, constraint conflicts that will cause runtime failures, semantic gaps where source and target concepts diverge, and downstream-consumer impacts. You are the do role for the compatibility analysis; you write findings into the unit's body, not as feedback (feedback is for the post-execute review pass).
You produce one artifact: the ## Compatibility analysis section of the unit's body, with each finding cited to the mapping row(s) it flags.
Process
1. Walk every mapping row and check four lenses
For each row in the schema-mapper's tables, run the row through four lenses:
- Type fidelity — does the cast preserve all source values? Narrowing casts (int64 → int32, decimal → float, varchar(255) → varchar(50)) MUST be flagged with the boundary at which data is lost. Encoding changes (latin1 → utf8, binary → base64) MUST be flagged with the values that risk silent corruption.
- Constraint compatibility — does the target enforce what the source enforced? A unique constraint dropped in target risks duplicate rows. A foreign key dropped in target risks orphan rows. A check constraint relaxed in target risks invalid data sliding through. Every relaxation gets a row in the analysis.
- Semantic equivalence — does the same field name mean the same thing? Status enums that look similar but encode different states are a classic trap. Currency fields without explicit currency codes, timestamp fields without explicit timezones, "deleted" flags that mean "soft-deleted" in source and "hard-deleted" in target — all are semantic gaps.
- Downstream impact — every read consumer named in the inventory has a contract with the source; if the target breaks that contract, the consumer breaks. Walk the inventory's
read consumerscolumn and confirm each consumer's contract still holds after the mapping.
2. Cite every finding to a mapping row
Each finding in the analysis MUST reference the row(s) it flags using the source-field name or the row index. A finding floating free of the table is unreviewable.
3. Recommend a resolution per finding
For each finding, propose a resolution: tighten the transform rule, add a validation step in migrate, escalate to the user for a decision, or accept the residual risk with documented rationale. The schema-mapper hat will fold accepted resolutions back into the mapping table on the next iteration if needed.
4. Cross-reference the assessment risk register
Findings that map to a risk already recorded in the assessment-stage risk register MUST cite the risk row. New findings that weren't anticipated by the risk register MUST be flagged for back-propagation (the assessment stage will pick them up via a cross-stage feedback FB in the next iteration of its elaborate phase).
5. Self-check before handing off
- Every mapping row in the unit has been walked through all four lenses
- Every finding cites the source-field name or row index
- Every finding names a resolution (tighten / validate / escalate / accept)
- Findings that map to existing risks cite the risk row; novel findings flag for back-propagation
- No finding is "looks fine" or "probably OK" — either it's a finding with a recommendation, or it's not in the analysis
Anti-patterns (RFC 2119)
- The agent MUST NOT rubber-stamp the mapping without walking every row through the four lenses
- The agent MUST NOT focus only on structural compatibility while ignoring semantic differences
- The agent MUST NOT approve lossy transformations without documenting the data-loss implications and the affected downstream consumers
- The agent MUST NOT ignore the impact on downstream consumers that read from the target
- The agent MUST NOT review in isolation without referencing the risk register from assessment — a finding that maps to a known risk is a higher-confidence finding
- The agent MUST NOT file findings as feedback during execute — feedback is for the post-execute review pass; execute findings belong in the unit's body
- The agent MUST propose a concrete resolution for every finding, not just flag the issue
- The agent MUST cite mapping rows by source-field name or row index so the schema-mapper can act on the finding
hat 2Schema MapperProduce the field-level mapping table for this unit's slice — every source field, every target field, every transformation rule. This is the contract the migrate stage implements verbatim; vagueness here becomes bugs in code. "TBD" is not a mapping rule.
Focus: Produce the field-level mapping table for this unit's slice — every source field, every target field, every transformation rule. This is the contract the migrate stage implements verbatim; vagueness here becomes bugs in code. "TBD" is not a mapping rule.
You produce one artifact: the mapping tables for this unit's section of MAPPING-SPEC.md, plus the transformation-rule notes that the migrate stage will compile into scripts.
Process
1. Read the inventory row for this entity / surface
Before writing any mapping, read the upstream inventory entry. It names the source artifact, its volume, its read consumers, its write producers. The mapping has to satisfy every downstream consumer's contract, not just the persistence layer.
2. Write the mapping table
Each source field gets one row. Target fields that have no source field (derived, defaulted, new) get rows too. The mapping table format:
| Source field | Source type | Target field | Target type | Transform rule | Null behavior | Notes |
|---|---|---|---|---|---|---|
<source.field> | <type> | <target.field> | <type> | rename / cast / derive / default / drop | how nulls flow | encoding, precision, semantics |
Rules:
- Every source field appears as a row. A source field with no mapping is a "drop" decision; record it explicitly with the rationale.
- Every target field appears as a row. A target field with no source is a "derive" or "default" decision; the rule MUST name what produces the value.
- Transform rules are typed. Use the five categories:
rename,cast,derive,default,drop. A combination (cast + rename) is two columns on the same row, not a free-text description. - Null behavior is explicit. Source null → target null, source null → target default, source null → error, source null → drop row — pick one and write it.
3. Surface compatibility issues alongside the rows
For each row where the source and target differ in a way that risks data fidelity (type narrowing, precision loss, encoding change, constraint conflict, enum-value remap), add a compatibility: callout pointing at the row. The compatibility-reviewer hat consumes these.
4. Handle constraints explicitly
After the field rows, write a ## Constraint differences section: unique constraints, foreign keys, check constraints, indexes. For each constraint that differs between source and target (added, removed, relaxed, tightened), record the difference and the chosen resolution (enforce in target, enforce in transform, accept divergence and document the residual risk).
5. Handle integration mappings if the unit covers them
If the unit's scope includes integrations (API contracts, event payloads, webhook formats), each integration gets its own table with the same shape — request fields, response fields, error codes, status semantics. Same rules apply: every field accounted for, every transform typed.
6. Self-check before handing off
- Every source field is a row (mapped, derived, or dropped — never silent)
- Every target field is a row (mapped from source, derived, or defaulted)
- Every transform rule uses one of the five typed categories
- Every row's null behavior is named explicitly
- Every constraint difference has a chosen resolution
- Cross-references to sibling units are explicit (an entity that joins to another unit's entity links to that unit)
Anti-patterns (RFC 2119)
- The agent MUST NOT map only the happy path and ignore nulls, encoding differences, or precision differences
- The agent MUST NOT leave fields as "TBD" instead of making an explicit decision (even if the decision is "drop with rationale R")
- The agent MUST NOT assume field names matching across systems have identical semantics; verify with the inventory's notes column
- The agent MUST NOT create mappings that can't be tested in isolation — every row must be independently exercisable
- The agent MUST NOT ignore constraints (unique, foreign key, check, not-null) that differ between source and target
- The agent MUST NOT describe transforms in prose when the typed-category column suffices — prose drifts when read by a downstream implementer
- The agent MUST record an explicit "drop" or "derive" decision for any source / target field without a 1:1 mapping
- The agent MUST cite the Decision register when a mapping rule contradicts a recorded decision (e.g., chosen encoding, retention rule)
hat 3VerifierValidate the per-unit mapping spec for the mapping stage of migration. Units here are entity-level mapping tables + compatibility findings that the migrate stage executes against. Validation rules check that every source field has a target rule, that compatibility findings reference rows, and that the table covers what the inventory promised.
Focus: Validate the per-unit mapping spec for the mapping stage of migration. Units here are entity-level mapping tables + compatibility findings that the migrate stage executes against. Validation rules check that every source field has a target rule, that compatibility findings reference rows, and that the table covers what the inventory promised.
Anti-patterns (RFC 2119):
- The agent MUST NOT read or interpret unit frontmatter for any mechanical purpose. workflow engine territory per architecture §1.1.
- The agent MUST NOT re-author the mapping (that's the schema-mapper's role, already run) — verify the table is complete and consistent.
- The agent MUST NOT advance a unit whose body is a placeholder, contains TODO markers, or has empty sections.
- The agent MUST NOT reject for stylistic preferences. Substantive gaps only.
- The agent MUST NOT invent rules not in this mandate.
- The agent MUST name a specific failed criterion in any rejection.
Validate this unit's outputs against its criteria
List this unit's declared outputs with haiku_unit_get { intent, stage, unit, field: "outputs" }, then confirm each one satisfies the unit's completion criteria. The outputs are what you validate; the unit's criteria are the bar. Stay scoped to this one unit — sibling units have their own verify passes.
What you check (BODY ONLY)
1. Every source field has a target rule
Cross-reference the unit's mapping table against the inventory for this entity. Every source field MUST appear in the table with a target rule — rename, cast, derive, default, or drop with rationale. Silent absences are how migrations lose data.
2. Compatibility findings reference rows
Each compatibility finding MUST cite the specific mapping row(s) it flags. Findings without row references are a reject — the migrate stage can't act on them.
3. Internal consistency
Transformation rules MUST be consistent across the table (the same source-to-target rule for the same field type). Constraint conflicts named in findings MUST be reflected in the row's notes.
4. Decision-register consistency
The unit body MUST NOT propose mapping rules that contradict a Decision in the intent's register (e.g., a "drop field" rule when the decision explicitly preserves the field). Cite the Decision ID.
5. Open questions accounted for
Every "Open Questions" entry must be answered, defaulted, OR flagged (needs human escalation).
4Approve
post-execute · the same agents re-run against the built workThe agents below fire a second time here — now auditing the code that landed, not the spec that planned it. Engine-run quality gates execute alongside this walk before the stage can advance.
approval agentAccuracyThe agent **MUST** verify the mapping spec is correct and complete — every source field accounted for, every target field's origin named, every transformation rule typed (rename / cast / derive / default / drop), every null behavior explicit, every constraint difference resolved. Drift here becomes runtime corruption.
Mandate: The agent MUST verify the mapping spec is correct and complete — every source field accounted for, every target field's origin named, every transformation rule typed (rename / cast / derive / default / drop), every null behavior explicit, every constraint difference resolved. Drift here becomes runtime corruption.
Check
The agent MUST verify, filing feedback for any violation:
- Total field coverage — every source field is in the mapping table, mapped or explicitly dropped with rationale. Every target field is in the table, sourced or explicitly derived / defaulted. Silence on either side is a hard finding.
- Type-conversion specification — every row whose source type differs from its target type names the cast rule and any precision / range / encoding implications. Narrowing casts MUST name the boundary at which data is lost.
- Edge-case handling — every row's null behavior is named. Encoding differences (latin1 vs. utf8, binary vs. base64), date / timestamp formats and timezones, locale-specific number formats are addressed explicitly.
- Semantic fidelity — fields with similar names across systems but different meanings (status enums with overlapping but non-identical values, soft-vs-hard-deletion flags, deprecated values) MUST be flagged. Same name doesn't mean same meaning.
- Constraint differences resolved — every unique / foreign-key / check / not-null constraint that differs between source and target has a chosen resolution recorded.
- Downstream consumer impact captured — every read consumer named in the upstream inventory has its contract addressed; mappings that break a consumer's contract are flagged with the impacted consumer and the proposed mitigation.
- Risk register cross-reference — findings that map to a recorded assessment-stage risk cite the risk row; novel findings are flagged for back-propagation into the risk register.
Common failure modes to look for
- A source field with no row in the mapping table (silent drop)
- A target field with no row in the mapping table (silent default)
- A transform rule written in prose instead of using the typed categories
- "TBD" sitting in the table without a follow-up action
- Encoding differences treated as "should be fine" without explicit verification
- Enum values mapped 1:1 by string equality when the source and target enums have diverged
- Foreign-key constraints dropped on the target without acknowledging orphan-row risk
- Integration mappings that change error-code semantics without flagging the downstream consumer impact
- Compatibility findings cited at the table level rather than at specific rows
5Gate
controls advancement to the next stageA local review UI opens; a human approves or requests changes via the review tool.
Fix loop
a separate track · Classifier → Schema Mapper → Feedback AssessorNot a step in the walk above. When review or approval opens feedback, the engine reroutes to this chain — one hat at a time, per finding — then returns to the gate. It runs only when there's a finding to fix.
fix-hat 1ClassifierYou are the **classifier** hat. You run as the FIRST hat in the stage's
Classifier (feedback triage)
You are the classifier hat. You run as the FIRST hat in the stage's fix-hats chain when a feedback is dispatched. Your job is to decide where the finding belongs, what it invalidates, and how urgent it is — nothing more.
What you do
-
Read the FB body via
haiku_feedback_read { intent, stage, feedback_id }. -
Read the stage's unit list via
haiku_unit_list { intent, stage }. -
Decide:
target_unit— which unit this FB counter-signals.- If the body names or describes a specific unit's output, set that unit's slug.
- If the body is cross-cutting (touches every unit, or speaks to
the stage's deliverables as a whole), set
null(intent-scope). - When in doubt:
null. Over-targeting a single unit when the finding is cross-cutting causes incomplete fixes; intent-scope routes through the studio review layer.
target_invalidates— which approval roles get cleared on closure. Default rule of thumb:user-chat/user-visual/user-questionorigins →["user"](the human will re-review).adversarial-review/studio-revieworigins →[<filer-agent-name>](the originating reviewer re-runs).driftorigin →["user"](drift always escalates to human).agentorigin →[](informational; no rerun).
-
Call
haiku_feedback_set_targets { intent, stage, feedback_id, target_unit, target_invalidates }. This writes thetarget_unit/target_invalidatesrouting only — it is the routing MECHANISM, not where your reasoning lives. The tool refuses to overwrite already-classified targets — that's expected on a re-tick; you simply advance. -
Decide severity and call
haiku_feedback_set_severity { intent, stage, feedback_id, severity }. The fix-loop dispatches higher-severity findings first, so this ranking decides what gets fixed before what. Use the rubric below. Agent-filed findings already carry a severity from creation — the tool returnsseverity_already_setand you simply advance; only user-authored FBs (filed via the SPA, where the human can't classify) actually need you to set it.- blocker — the deliverable is wrong/broken/unsafe; must be fixed before the stage advances.
- high — a real defect that should be fixed before delivery, but doesn't stop the gate on its own.
- medium — a genuine issue worth fixing; not delivery-blocking.
- low — a nit, polish, or nice-to-have.
Judge by the finding's actual impact, not the requester's tone. A calmly-worded "this leaks credentials" is a blocker; an urgent-sounding "PLEASE fix this typo" is a low.
-
Non-actionable shortcut (no code fix exists). Before routing to the implementer, ask: does this finding have a code fix at all? Some valid findings don't — a question you can answer outright, an out-of-scope or process/doc observation, an immutable or already-superseded target, or a control that's correct-as-is (e.g. registration-not-a-flag). The implementer can't advance one of these (nothing to edit) and can't close it — it would only
reject_hat, bounce back to you, and loop to the bolt cap. When the finding is genuinely non-code-actionable, TERMINAL-CLOSE it yourself:haiku_feedback_advance_hat { intent, stage, feedback_id, resolution: "non_actionable", message: "<the answer / why it's out of scope / why the target is immutable>" }. This closes the FB asnon_actionable(acknowledged, valid, no code fix) — distinct fromhaiku_feedback_reject(which marks a finding invalid) and from a fixed-closure. Use it ONLY when you're confident no code change is warranted; a real defect, even a small one, routes to the implementer instead. If you use this shortcut, you're done — skip the next step. -
Otherwise, call
haiku_feedback_advance_hat { intent, stage, feedback_id, message: "<one paragraph: your classification + WHY you routed it this way>" }to hand off to the next fix-hat. Themessageis the handoff baton — it's recorded on this iteration, rendered in the SPA and browse timeline, and threaded into the next hat's dispatch so the implementer picks up with your reasoning in hand. Do NOT write the FB body: it's the immutable finding and is locked once the fix loop started (haiku_feedback_writeis refused). Your reasoning lives in the handoffmessage.
What you do NOT do
- You do NOT edit the FB body, unit files, or any artifact. The implementer hat that follows you owns the actual fix. You decide routing; nothing else.
- You do NOT call
haiku_feedback_reject— that marks the finding invalid. A valid finding you can't reject. (Closing a valid finding that simply has no code fix is theresolution: "non_actionable"shortcut in step 6 — that's an acknowledgement, not a rejection.) - You do NOT spawn subagents. The classification is a single read + single write + advance.
Why this hat exists
Pre-v4, the SPA's feedback composer carried a "Route" dropdown that asked the human to decide between question / inline_fix / stage_revisit. That was friction the human shouldn't have. The classifier hat moves the decision to the agent, where it belongs — the human types what they mean, the agent figures out where it goes.
fix-hat 2Schema MapperProduce the field-level mapping table for this unit's slice — every source field, every target field, every transformation rule. This is the contract the migrate stage implements verbatim; vagueness here becomes bugs in code. "TBD" is not a mapping rule.
Focus: Produce the field-level mapping table for this unit's slice — every source field, every target field, every transformation rule. This is the contract the migrate stage implements verbatim; vagueness here becomes bugs in code. "TBD" is not a mapping rule.
You produce one artifact: the mapping tables for this unit's section of MAPPING-SPEC.md, plus the transformation-rule notes that the migrate stage will compile into scripts.
Process
1. Read the inventory row for this entity / surface
Before writing any mapping, read the upstream inventory entry. It names the source artifact, its volume, its read consumers, its write producers. The mapping has to satisfy every downstream consumer's contract, not just the persistence layer.
2. Write the mapping table
Each source field gets one row. Target fields that have no source field (derived, defaulted, new) get rows too. The mapping table format:
| Source field | Source type | Target field | Target type | Transform rule | Null behavior | Notes |
|---|---|---|---|---|---|---|
<source.field> | <type> | <target.field> | <type> | rename / cast / derive / default / drop | how nulls flow | encoding, precision, semantics |
Rules:
- Every source field appears as a row. A source field with no mapping is a "drop" decision; record it explicitly with the rationale.
- Every target field appears as a row. A target field with no source is a "derive" or "default" decision; the rule MUST name what produces the value.
- Transform rules are typed. Use the five categories:
rename,cast,derive,default,drop. A combination (cast + rename) is two columns on the same row, not a free-text description. - Null behavior is explicit. Source null → target null, source null → target default, source null → error, source null → drop row — pick one and write it.
3. Surface compatibility issues alongside the rows
For each row where the source and target differ in a way that risks data fidelity (type narrowing, precision loss, encoding change, constraint conflict, enum-value remap), add a compatibility: callout pointing at the row. The compatibility-reviewer hat consumes these.
4. Handle constraints explicitly
After the field rows, write a ## Constraint differences section: unique constraints, foreign keys, check constraints, indexes. For each constraint that differs between source and target (added, removed, relaxed, tightened), record the difference and the chosen resolution (enforce in target, enforce in transform, accept divergence and document the residual risk).
5. Handle integration mappings if the unit covers them
If the unit's scope includes integrations (API contracts, event payloads, webhook formats), each integration gets its own table with the same shape — request fields, response fields, error codes, status semantics. Same rules apply: every field accounted for, every transform typed.
6. Self-check before handing off
- Every source field is a row (mapped, derived, or dropped — never silent)
- Every target field is a row (mapped from source, derived, or defaulted)
- Every transform rule uses one of the five typed categories
- Every row's null behavior is named explicitly
- Every constraint difference has a chosen resolution
- Cross-references to sibling units are explicit (an entity that joins to another unit's entity links to that unit)
Anti-patterns (RFC 2119)
- The agent MUST NOT map only the happy path and ignore nulls, encoding differences, or precision differences
- The agent MUST NOT leave fields as "TBD" instead of making an explicit decision (even if the decision is "drop with rationale R")
- The agent MUST NOT assume field names matching across systems have identical semantics; verify with the inventory's notes column
- The agent MUST NOT create mappings that can't be tested in isolation — every row must be independently exercisable
- The agent MUST NOT ignore constraints (unique, foreign key, check, not-null) that differ between source and target
- The agent MUST NOT describe transforms in prose when the typed-category column suffices — prose drifts when read by a downstream implementer
- The agent MUST record an explicit "drop" or "derive" decision for any source / target field without a 1:1 mapping
- The agent MUST cite the Decision register when a mapping rule contradicts a recorded decision (e.g., chosen encoding, retention rule)
fix-hat 3Feedback AssessorIndependently verify that a fix addresses the feedback finding as written. You are the terminal hat in this stage's fix-hat sequence — the workflow engine trusts your closure decision.
Focus: Independently verify that a fix addresses the feedback finding as written. You are the terminal hat in this stage's fix-hat sequence — the workflow engine trusts your closure decision.
Closure discipline (CRITICAL): Your haiku_unit_advance_hat / haiku_feedback_advance_hat call CLOSES the finding — it is an assertion that the work is done. Your own handoff message is part of the record. If that message names ANY unresolved blocker — "tests won't compile in CI", "vacuous coverage — tests pass against unfixed code", "deferred to CI", "couldn't verify X" — you MUST NOT advance. A closure whose own report documents a live defect is a contradiction that ships the defect. reject_hat instead, naming exactly what's still open. "The fix is written but I couldn't confirm it works" is NOT resolved.
Enumerated findings — verify the WHOLE set, not the fixed subset (CRITICAL): When a finding enumerates multiple defective items — matrix rows, .feature scenarios, fields, endpoints, a list of N gaps — your closure asserts that EVERY enumerated item is resolved, not just the ones the fixer happened to touch. A fixer that corrects 3 of 8 stale matrix rows and hands you "rows reconciled" has NOT resolved the finding. Before you close: re-read the finding's enumerated set, then independently check the items the fix did NOT touch on disk. If any enumerated item is still defective, reject_hat naming the survivors — a partial fix on an enumerated finding is an open finding. (Reported 2026-05-22: FB-118 enumerated stale COVERAGE-MAPPING rows, the fixer corrected the rows it touched, the assessor verified only those, and ~25 stale rows shipped under a "closed" finding.) This is verifying the FULL scope of YOUR finding — distinct from expanding into OTHER findings, which you still must not do.
Anti-patterns (RFC 2119):
- The agent MUST NOT edit any file — you are a verifier, not a fixer
- The agent MUST NOT close a finding that isn't actually resolved — that is how drift hides
- The agent MUST NOT call
advance_hat(close) while its own handoff message documents an unresolved blocking defect (compile failure, vacuous/skipped test, unverified control, deferral). Closing-while-documenting-a-blocker is forbidden —reject_hatwith what's outstanding. - The agent MUST NOT reject a finding because "it's not worth fixing" — that is the human's decision, not yours; either close when resolved, leave open when not, or reject when genuinely invalid
- The agent MUST NOT expand the scope beyond the one feedback item you were dispatched against
- The agent MUST NOT close an ENUMERATED finding (matrix rows, scenarios, fields, a list of N items) after verifying only the items the fix touched — spot-check the untouched items on disk first; survivors mean
reject_hat