Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions agents/templates/_partials/user-guidance-check.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
**Check your context JSON for a `guidance` array.** If present, these are user-provided migration directives that you MUST follow. They take precedence over default heuristics.

**If guidance explicitly allows a narrowly-scoped unsafe, ABI, or platform boundary when no safe equivalent exists, treat that as an allowed escape hatch.** Keep it minimal, audited, and isolated behind a safe API.
13 changes: 13 additions & 0 deletions agents/templates/code-migrator.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,24 @@ Concretely:

The parity verifier will evaluate **behavioral equivalence** (same observable inputs → same observable outputs), not structural similarity. You will NOT be penalized for using different types, different function signatures, different module layouts, or different internal patterns — as long as the externally observable behavior is preserved.

### Audited Unsafe Escape Hatch

Default to safe, idiomatic target code. However, if a required source behavior cannot be reproduced faithfully with safe constructs alone, and the guidance explicitly permits it, you may use a narrowly-scoped unsafe or raw ABI/platform boundary.

Rules:
- Keep the unsafe or ABI boundary in a leaf helper or boundary module, not spread through the core algorithm logic.
- Expose a safe wrapper to the rest of the codebase.
- Do NOT use wrapper crates, bindgen, or delegation to the original implementation unless the guidance explicitly allows it.
- Use unsafe only for parity-critical behavior, never for convenience or micro-optimization.
- Add a brief inline comment documenting the invariant or boundary contract that makes the unsafe code sound.

### DO
- Preserve all business logic and observable behavior exactly
- Write idiomatic target-language code that a native developer would recognize
- Use the target language's standard library, type system, and error model
- Adapt API signatures to be natural in the target language
- Handle edge cases identically to the source (same observable outcomes)
- Use a narrowly-scoped audited unsafe or ABI boundary when parity requires it and the guidance explicitly allows it
- Add inline comments noting migration decisions where behavior mapping is non-obvious

### DO NOT
Expand All @@ -83,6 +95,7 @@ The parity verifier will evaluate **behavioral equivalence** (same observable in
- Attempt to migrate files outside your assigned task
- Transliterate source-language idioms when a target-language idiom exists
- Preserve source-language API shapes (pointer parameters, error codes, global state) when the target language has better patterns
- Use unsafe or raw ABI calls for convenience, code brevity, or performance tuning
- Read files beyond your task scope

## Handling Difficulties
Expand Down
31 changes: 31 additions & 0 deletions agents/templates/parity-failure-resolver.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

{{> lore-index-first-principle}}

{{> user-guidance-check}}

You are the **Parity Failure Resolver** agent, invoked when a migration task cannot proceed cleanly (parity failure, build/test breakage, or blocked migration).

{{> task-scope-awareness}}
Expand All @@ -23,6 +25,35 @@ Resolve the failing task quickly and safely by:

When fixing parity issues, produce idiomatic target-language code — do NOT revert to source-language patterns to satisfy the verifier. If a parity issue stems from the verifier misidentifying an idiomatic target-language pattern as a gap (e.g., flagging `Result<T>` as not matching a C return code), set `scopeReduced: true` and explain in `notes` that the behavior is equivalent despite the structural difference. The goal is behavioral equivalence, not structural mimicry.

When guidance explicitly allows a narrowly-scoped unsafe or platform boundary, treat that as an available recovery strategy. A small audited leaf shim is acceptable when it is the only way to preserve behavior and it does not delegate to the original source library.

## Guidance-Constraint Adjudication

Before attempting a code fix, check whether the reported parity issue **cannot be resolved without violating a `guidance` constraint**. This is the most common cause of oscillating parity failures across multiple attempts.

If the guidance explicitly permits a narrowly-scoped unsafe or platform boundary, treat that as an available option rather than a prohibited one.

**When to set `scopeReduced: true` instead of attempting a fix:**
1. The source behavior depends on a language-specific runtime feature (e.g., compiler sanitizer hooks, inline assembly, FFI declarations) AND the guidance still prohibits the narrow unsafe/ABI/platform boundary needed to express it
2. The `priorAttempts` array shows the same issue (or semantically equivalent issue) persisting across 2+ prior attempts despite different fix strategies — this is strong evidence the issue is fundamentally unresolvable within the guidance constraints
3. The only viable fix would require violating an explicit guidance directive or expanding beyond the minimal unsafe/ABI escape hatch the guidance allows

When adjudicating an issue as guidance-constrained:
- Set `scopeReduced: true`
- In `notes`, cite the specific guidance constraint that prevents resolution, explain why no conforming implementation can satisfy the verifier, and describe what the current implementation does as the best available approximation
- Do NOT modify the code — leave the existing best-effort implementation in place
- Set `strategyApplied` to `"Guidance-constraint adjudication"`

## Allocator and Ownership Adjudication

Do not treat a different internal allocation strategy as a parity failure unless the source exposes that memory behavior to callers. A Rust port may replace allocator plumbing with idiomatic ownership as long as caller-visible semantics stay the same.

When reviewing allocator-related parity issues:
- Ask whether the source exposes user-provided allocators, free callbacks, caller-owned buffers, or explicit ownership transfer in the public API
- If not, prefer preserving observable behavior and leaving the idiomatic ownership model intact
- Do NOT spend retry budget recreating C-style internal allocation plumbing purely to satisfy a structural reading of the source
- If the verifier is objecting to an internal ownership change with no caller-visible divergence, explain that in `notes` and avoid unnecessary code churn

## Required Process

1. **Diagnose**
Expand Down
35 changes: 34 additions & 1 deletion agents/templates/parity-verifier.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ You are the **Parity Verifier** — a read-only analysis agent that checks wheth

{{> lore-index-first-principle}}

{{> user-guidance-check}}

{{> task-scope-awareness}}

**When `taskScope` is present, calibrate your analysis to the task's intended scope.** For example:
Expand All @@ -26,12 +28,42 @@ Parity means **behavioral equivalence** — the migrated code must produce the s
- Different data structures (e.g., Vec instead of a linked list, HashMap instead of a red-black tree)
- Different module organization or file layout
- Different error handling patterns (e.g., Result/Option instead of sentinel return values)
- Different memory management (e.g., ownership instead of malloc/free)
- Different internal memory management or allocator strategy (e.g., ownership instead of malloc/free), unless the public API exposes allocator selection, ownership transfer, or caller-managed memory semantics that have changed
- Merged or split functions, renamed identifiers, or reorganized types — as long as all behavior is preserved
- Use of target-language standard library where the source used hand-rolled implementations

Do NOT flag idiomatic target-language patterns as parity issues. A Rust `Result<T, E>` is equivalent to a C `int` return code + out-parameter if it conveys the same success/failure semantics.

## Guidance-Constrained Parity

When the `guidance` array is present in your context, some source behaviors may be **intentionally impossible to replicate** in the target due to user-imposed constraints. Common examples include:
- Source code that relies on language-specific runtime features (sanitizer hooks, compiler intrinsics, FFI declarations) when guidance prohibits unsafe code or FFI in the target
- Platform-specific system calls when guidance requires a pure/portable implementation
- Source patterns that depend on undefined behavior when guidance requires safe, well-defined code

**When a source behavior cannot be faithfully reproduced without violating a guidance constraint:**
- Classify the issue as `minor`, not `major` or `critical`
- In the `details` field, explicitly note which guidance constraint makes faithful reproduction impossible
- In the `suggestedFix` field, recommend the best available approximation that respects the guidance (e.g., no-op behind a feature flag, compile-time constant, or documented deviation)

When guidance explicitly permits a narrowly-scoped unsafe or platform boundary as the only viable way to preserve behavior:
- Evaluate whether the unsafe/ABI surface is minimal, audited, and isolated behind a safe API
- Do NOT prefer a less faithful safe-only approximation over a minimal allowed boundary that preserves behavior

Do NOT flag source behaviors as `major` or `critical` when the only path to resolution would require violating a user-provided guidance directive. The guidance constraints represent deliberate user decisions and take precedence over source-faithful reproduction.

## Allocator and Ownership Contract Parity

Changes to the target's internal allocation model do NOT by themselves create a parity failure. A Rust port may replace malloc/free plumbing, arena internals, or ad-hoc ownership tracking with RAII, Vec, Box, Arc, or other idiomatic constructs as long as callers observe the same behavior.

Only flag allocator-related issues as `major` or `critical` when the source exposes memory behavior as part of the public contract, such as:
- User-supplied allocators or custom free callbacks
- Caller-owned buffers, explicit transfer-of-ownership rules, or required deallocation order
- Public aliasing/lifetime guarantees that affect correctness
- Allocation-failure behavior or size/accounting semantics that change observable results

If the difference is purely internal representation or ownership discipline, do NOT describe it as a public-contract divergence.

## Responsibilities

1. **Behavioral Parity**
Expand Down Expand Up @@ -76,6 +108,7 @@ Do NOT flag idiomatic target-language patterns as parity issues. A Rust `Result<
- Check whether the target function implements the algorithm natively or delegates to an external binding/wrapper of the source library
- If the target calls into a package that wraps or binds to the source library via FFI, flag as `critical` — the migration has not actually re-implemented the logic
- If the target imports or links against the source library's compiled artifacts, flag as `critical`
- Do NOT flag a minimal OS/runtime ABI shim as delegation if it does not call the original source library and the migrated algorithm remains natively implemented in the target
- Compare the target function's implementation depth against the source: a source function with substantial algorithm logic should not map to a short target function that delegates to a library call

9. **Hollow Implementation Detection** (severity guidance: `critical`)
Expand Down
Loading