Skip to content

feat(skills): /parity engine-parity audit skill + titan-run integration#1474

Merged
carlos-alm merged 4 commits into
mainfrom
feat/parity-skill
Jun 12, 2026
Merged

feat(skills): /parity engine-parity audit skill + titan-run integration#1474
carlos-alm merged 4 commits into
mainfrom
feat/parity-skill

Conversation

@carlos-alm

Copy link
Copy Markdown
Contributor

Stacked on #1465 (refactor/engine-structure-parity) — only the last commit (1709a2c) is new here.

Summary

  • scripts/parity-compare.mjs — permanent correctness-parity gate. Builds every resolution-benchmark fixture (36 today) with the wasm and native engines (plus the hybrid JS-pipeline + napi-solver path with --hybrid) into isolated temp dirs and compares the full node and edge multisets — kind, name, file, line, confidence, dynamic flag. Zero divergence is the only passing state; exit 1 on any diff, --json for machine-readable reports, --langs to scope.
  • .claude/skills/parity/SKILL.md — the /parity skill: pre-flight (fresh dist + napi build + macOS codesign + loader check), audit, root-cause localization via the wasm/hybrid/native disagreement table, fix rules (mirror semantics exactly in both engines, never document a gap as expected), verification loop, report.
  • .claude/skills/titan-run/SKILL.md — new conditional Step 4.7 — PARITY between GRIND and CLOSE. titan-run is shared across repos, so the step is repo-agnostic: a repo opts in by shipping its own /parity skill; without one the orchestrator prints a skip note and continues. Drift introduced by the run blocks CLOSE; pre-existing divergences are filed as issues per scope discipline.

Proven in anger

The script's first run caught a real native-engine bug — the missing Phase 8.2 cross-file return-type propagation, fixed in #1465 (aa88fda). The subsequent full sweep (--hybrid) found 26/36 fixtures at exact three-path parity and surfaced pre-existing divergences in the other 10, filed as #1466, #1467, #1468, #1469, #1470, #1471, #1472. Until those land, a full-sweep audit honestly exits 1 — that is the gate working as designed, not a defect of this PR.

Test plan

@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Claude finished @carlos-alm's task —— View job


PR #1474 Review — feat(skills): /parity engine-parity audit skill + titan-run integration

  • Read changed files (scripts/parity-compare.mjs, .claude/skills/parity/SKILL.md, .claude/skills/titan-run/SKILL.md)
  • Read FOUNDATION.md and BACKLOG.md
  • Analyze root cause and approach
  • Code quality review
  • Backlog compliance
  • Final assessment

Root Cause Analysis

Problem Being Solved: This PR adds a permanent, automated gate to enforce the core CLAUDE.md invariant that WASM and native engines must produce identical results. The problem is real and well-evidenced — the script's first run caught the missing Phase 8.2 return-type propagation (fixed in the base branch #1465), and the full sweep exposed 10/36 fixtures with pre-existing divergences (filed as #1466#1472). Without this gate, engine-parity regressions are discovered incidentally or not at all.

Why This Approach: The approach is correct. Rather than embedding engine comparisons in the existing vitest resolution-benchmark (which tests accuracy against hand-annotated ground truth), this script directly compares engine outputs against each other — a complementary, orthogonal signal. The three-path (wasm/hybrid/native) localization table in SKILL.md is particularly valuable: it gives the fixer a crisp diagnostic framework before reading any code.

Risk Assessment: Low. All three changed files are in non-compiled paths (.claude/skills/ and scripts/). No runtime behavior, no DB schema, no public API is touched. The worst that can happen is a false positive exit-1, which blocks CLOSE in titan-run — an acceptable false-safety failure mode.


Phase 2: Configuration Change Detection

✓ No linting rules disabled, no test timeouts increased, no TypeScript strict flags touched. Clean.


Phase 3: Test Integrity

✓ No test files modified. No assertions weakened. The script itself adds a new verification surface that is stricter, not looser.


Phase 4: Code Quality

scripts/parity-compare.mjs

Solid overall. A few observations:

Line 148–154 — buildHybrid is clever but fragile:

// Hybrid path: an incremental wasm build followed by an incremental native
// build on the same dir triggers "Engine changed (wasm -> native), promoting
// to full rebuild", which sets forceFullRebuild and skips the orchestrator
await buildGraph(dir, { ...BUILD_OPTS, incremental: true, engine: 'wasm' });
await buildGraph(dir, { ...BUILD_OPTS, incremental: true, engine: 'native' });

The comment documents why two sequential builds in the same dir produce the hybrid path, but this is an implementation-internal detail of the build system — if the engine-change promotion logic changes (e.g. is removed, renamed, or the trigger condition changes), buildHybrid silently stops testing what it claims to test with no error. A safety assertion — e.g. reading the engine field from the DB's metadata table after both builds and asserting it changed — would catch this. Not a blocker, but worth noting as a known fragility.

Line 165 — __TOTAL_ROWS__ as a sentinel in the multiset Map:

nodes.set('__TOTAL_ROWS__', nodeRows.length);

Using a sentinel key in the same Map that's fed to diffMultisets means if a node ever has kind|name|file|line matching __TOTAL_ROWS__, it silently corrupts the row-count display (but not the diff logic, since diffMultisets would just report it as a divergence). Vanishingly unlikely, but using a separate variable would be cleaner. Non-blocking.

Line 269–275 — rmSync in finally swallows all errors silently:

try {
  rmSync(dir, { recursive: true, force: true });
} catch {
  // best-effort cleanup of temp dirs
}

This is fine for cleanup, but on Windows (or any platform with locked files) it can leave temp dirs filling disk if many fixtures run. Not a CI concern since this runs on the developer's machine, but worth flagging. Non-blocking.

Line 292 — process.exit() comment is accurate and necessary:

// The WASM worker pool keeps the event loop alive; exit explicitly.
process.exit(report.ok ? 0 : 1);

Good defensive practice. Well-documented.

No new npm runtime dependencies — uses only node:fs, node:os, node:path, node:url, node:module (all built-in), better-sqlite3 (already a runtime dep), and the repo's own dist/index.js. ✓

.claude/skills/parity/SKILL.md

Exceptional quality. The wasm/hybrid/native localization table (Phase 2) is a standout — it turns a debugging session into a lookup. The "Gotchas that mask fixes" section addresses the three most common ways a fix gets applied but not tested (stale dist, stale native binary, missing SerializedExtractorOutput fields, missing pipeline.rs assembly).

One clarity issue:

Lines 86–88 — "the one missing edges or producing lower-quality resolution is usually the buggy one":
This heuristic is correct for the common case but could mislead for a false-positive scenario — WASM producing extra spurious edges makes it look like the one not missing edges. The table handles this correctly (it's symmetric in both directions), but the prose framing of "missing = buggy" could be tightened. Minor.

.claude/skills/titan-run/SKILL.md

Step 4.7 is well-scoped. The repo-agnostic opt-in design (presence of .claude/skills/parity/SKILL.md) is the right call — titan-run should not hardcode any repo-specific parity surface.

Lines 760–761 — skip condition is slightly under-specified:

Skip also if: --start-from is close, or the pipeline made no code changes this run
(titan-state.json → execution.commits empty/absent AND no grind adoption commits)
— unless --start-from parity was given explicitly

The "no grind adoption commits" check isn't explained — there's no variable tracking grind commits separately from forge commits in the preceding loop logic. An orchestrator implementing this would need to compare git rev-parse HEAD before and after grind to determine if grind actually committed anything. The condition is logically correct but under-specified for implementation. Consider adding a headAfterGrind variable to the grind loop for this purpose, or noting that the orchestrator can compare headAfterForge vs headAfterGrind to decide. Minor.

Line 784–785 — "pre-existing divergences filed as issues are not blockers":
This is correct per CLAUDE.md scope discipline. The PR description's honesty here ("a full-sweep audit honestly exits 1 — that is the gate working as designed") is exactly right.


Backlog Compliance

  • Zero-dep: ✓ — no new npm runtime dependencies. Uses only Node built-ins, better-sqlite3 (already a dep), and the repo's own dist.
  • Foundation-aligned: ✓ — this is operational tooling for the development process (.claude/skills/, scripts/), not a change to the core pipeline. It enforces P2 (dual-engine correctness) without touching P1/P4/P5/P8.
  • Problem-fit: 4/5 — directly prevents engine divergence from silently producing different call graphs for different users depending on their platform (native vs WASM fallback). A user on a platform with native gets different analysis results than a user on WASM → hallucinated or missing blast radius data. This is a real correctness concern for the tool's core value proposition.
  • Breaking: No — purely additive. No CLI output, API signatures, DB schema, or MCP contracts changed.
  • Tier: 1 (zero-dep ✓ + foundation-aligned ✓)

Critical Concerns

None that block merging.

The only real fragility is the buildHybrid implementation depending on an internal engine-change promotion detail that could silently stop testing the hybrid path if that detail changes. Worth a // FRAGILE: comment or a follow-up issue.


Final Recommendation

Rating: ⭐⭐⭐⭐ (4/5)
Action: APPROVE

Reasoning: This PR is exactly what it says — a permanent correctness gate with evidence of having caught a real bug on first use. The script is clean (no new deps, isolated temp dirs, three-path comparison, machine-readable JSON output, correct exit codes). The skill documents a tight diagnostic loop that turns "engines diverge" into "here's which layer to fix" in one lookup. The titan-run integration is appropriately repo-agnostic via skill-presence detection. No configuration is relaxed, no test expectations are lowered, and the PR is honest about the fact that the gate currently exits 1 on a full sweep (because the 10 pre-existing divergences are tracked as open issues, not silenced). That honesty is the correct posture.

The buildHybrid fragility and the grind-skip condition gap are noted for a follow-up but don't warrant blocking this.

@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a correctness-parity gate (scripts/parity-compare.mjs) that builds every resolution-benchmark fixture with the wasm, native, and optional hybrid engine into isolated temp dirs and compares the full node/edge multisets, then wires that gate into the titan-run pipeline as an optional Step 4.6 (triggered only when the repo ships .claude/skills/parity/SKILL.md).

  • scripts/parity-compare.mjs: New 298-line script; exit 0/1/2 semantics, --langs, --hybrid, --json flags, temp-dir-safe cleanup, __TOTAL_ROWS__ sentinel excluded from diffs, and empty---langs guard — all previously flagged issues are addressed in this version.
  • .claude/skills/parity/SKILL.md: New AI skill driving pre-flight (fresh dist + napi build + macOS codesign + require.resolve binary check), audit, wasm/hybrid/native disagreement-pattern localisation table, fix rules, and re-verification loop.
  • .claude/skills/titan-run/SKILL.md: Adds Step 4.6 (PARITY) between GRIND and CLOSE; repo-agnostic opt-in via presence of the parity skill file; drift introduced by the run blocks CLOSE while pre-existing divergences are filed as issues.

Confidence Score: 5/5

Safe to merge — all three files are purely additive and don't touch existing production code paths.

All previously flagged blocking issues have been resolved in the head commit. The remaining comments are style-level improvements that don't affect correctness of the gate itself.

scripts/parity-compare.mjs warrants a second look for the minor nits; the two SKILL.md files are clean.

Important Files Changed

Filename Overview
scripts/parity-compare.mjs New parity gate script; previously flagged bugs (sentinel leak, temp dir leak, empty --langs false-pass, native binary detection) are all fixed. Minor: fixtures directory is not existence-checked before readdirSync, and the JSON report omits variant node/edge counts.
.claude/skills/parity/SKILL.md New AI skill; Phase 0 now includes require.resolve binary-path verification (previously flagged issue fixed), localisation table and fix rules are clear and non-negotiable.
.claude/skills/titan-run/SKILL.md Adds conditional Step 4.6 (PARITY) between GRIND and CLOSE; headBefore/headAfter capture, --start-from parity skip logic, and error recovery are all well-specified.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[titan-run start] --> B[RECON]
    B --> C[GAUNTLET]
    C --> D[SYNC]
    D --> E[FORGE]
    E --> F[GRIND]
    F --> G{.claude/skills/parity/SKILL.md exists?}
    G -- NO --> K[Print: PARITY skipped]
    G -- YES --> H{Code changes this run?}
    H -- NO --> K
    K --> L[CLOSE]
    H -- YES --> I[Step 4.6 PARITY - Dispatch /parity sub-agent]
    I --> J{Divergences introduced by this run?}
    J -- None or pre-existing --> L
    J -- New drift unfixed --> M[STOP - block CLOSE]

    subgraph parity-compare.mjs
        P1[Pre-flight: dist + native + codesign + require.resolve]
        P2[Build each fixture: wasm / native / hybrid]
        P3[readMultisets: node + edge multisets]
        P4[diffMultisets: wasm vs native, wasm vs hybrid]
        P5{Diffs?}
        P6[exit 0 PARITY OK]
        P7[exit 1 DIVERGED]
        P1 --> P2 --> P3 --> P4 --> P5
        P5 -- No --> P6
        P5 -- Yes --> P7
    end

    I -.-> parity-compare.mjs
Loading

Reviews (7): Last reviewed commit: "fix(parity): guard empty --langs, captur..." | Re-trigger Greptile

Comment on lines +193 to +196
function diffMultisets(base, other) {
const diffs = [];
const keys = new Set([...base.keys(), ...other.keys()]);
for (const key of keys) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 __TOTAL_ROWS__ sentinel leaks into diff output and inflates counts. diffMultisets iterates over all keys in both maps, including the synthetic __TOTAL_ROWS__ entry. Whenever node or edge counts differ this sentinel appears as an extra diff entry (e.g. [node] __TOTAL_ROWS__ wasm=100 native=101) in human-readable output, increments nodeDiffs.length/edgeDiffs.length by one, and appears in the JSON report's nodeDiffs/edgeDiffs arrays — making automated consumers see N+1 diffs and making the human output harder to read. Filter it out before diffing.

Suggested change
function diffMultisets(base, other) {
const diffs = [];
const keys = new Set([...base.keys(), ...other.keys()]);
for (const key of keys) {
function diffMultisets(base, other) {
const diffs = [];
const keys = new Set([...base.keys(), ...other.keys()]);
keys.delete('__TOTAL_ROWS__');
for (const key of keys) {

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — added keys.delete('__TOTAL_ROWS__') in diffMultisets before iterating, so the sentinel is never included in diffs or diff counts (commit f062fb9).

Comment thread scripts/parity-compare.mjs Outdated
Comment on lines +137 to +154
async function buildEngine(fixtureDir, engine, label) {
const dir = mkdtempSync(join(tmpdir(), `parity-${label}-`));
cpSync(fixtureDir, dir, { recursive: true });
await buildGraph(dir, { ...BUILD_OPTS, engine });
return dir;
}

// Hybrid path: an incremental wasm build followed by an incremental native
// build on the same dir triggers "Engine changed (wasm -> native), promoting
// to full rebuild", which sets forceFullRebuild and skips the orchestrator —
// the JS pipeline then drives the napi buildCallEdges resolver.
async function buildHybrid(fixtureDir, label) {
const dir = mkdtempSync(join(tmpdir(), `parity-${label}-`));
cpSync(fixtureDir, dir, { recursive: true });
await buildGraph(dir, { ...BUILD_OPTS, incremental: true, engine: 'wasm' });
await buildGraph(dir, { ...BUILD_OPTS, incremental: true, engine: 'native' });
return dir;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Temp dir leak when buildGraph throws inside buildEngine/buildHybrid. Both helpers mkdtempSync a directory and then call buildGraph. If buildGraph rejects, the function throws before returning dir, so the caller never reaches tempDirs.push(...) — the directory is orphaned and the finally block won't clean it up. On a 36-fixture run where several fixtures fail, this can silently accumulate multiple copied-fixture trees in /tmp. A try/finally inside each helper (or tracking the dir on the caller side before awaiting) would ensure cleanup on failure.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — tempDirs.push(dir) is now called immediately after mkdtempSync, before the first await buildGraph(), in both buildEngine and buildHybrid. The helpers now accept tempDirs as a parameter. Call sites updated accordingly (commit f062fb9).

Comment thread .claude/skills/parity/SKILL.md Outdated
Comment on lines +49 to +57
```bash
codesign --sign - --force crates/codegraph-core/*.node
```
4. Verify the loader picks it up:
```bash
node -e "import('./dist/infrastructure/native.js').then(m => console.log(m.isNativeAvailable()))"
```
If `false`, stop and report — auditing parity without the native engine is
meaningless. Note: if the repo (or a parent) has

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Pre-flight check can't distinguish locally-built binary from the installed package binary. The skill asks the agent to verify isNativeAvailable() returns true, but that call returns true for the published node_modules/@optave/codegraph-<platform>-<arch>/ binary just as readily as for the freshly built one. If the installed package is present, Node resolves it first, isNativeAvailable() passes, and the entire parity audit silently benchmarks the published binary — missing any bug introduced by local Rust changes. The skill documents the manual override (copy the .node file), but doesn't instruct the agent to verify which path is actually resolved (e.g. via require.resolve or checking the binary's mtime against the Rust source). Without that check, Phase 0 can pass even when auditing the wrong binary.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — Phase 0 step 4 now instructs the agent to run require.resolve to check the actual resolved path first. If it points to the installed package binary, the agent copies the freshly built binary over it before running the availability check (commit f062fb9).

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

8 functions changed7 callers affected across 2 files

  • usage in scripts/parity-compare.mjs:33 (1 transitive callers)
  • buildGraph in scripts/parity-compare.mjs:89 (6 transitive callers)
  • isNativeAvailable in scripts/parity-compare.mjs:90 (4 transitive callers)
  • buildEngine in scripts/parity-compare.mjs:141 (1 transitive callers)
  • buildHybrid in scripts/parity-compare.mjs:153 (1 transitive callers)
  • bump in scripts/parity-compare.mjs:162 (2 transitive callers)
  • readMultisets in scripts/parity-compare.mjs:166 (1 transitive callers)
  • diffMultisets in scripts/parity-compare.mjs:199 (1 transitive callers)

@carlos-alm

Copy link
Copy Markdown
Contributor Author

Addressed Greptile and Claude review feedback:

  • __TOTAL_ROWS__ sentinel leaks into diffs — fixed: keys.delete('__TOTAL_ROWS__') added to diffMultisets before iterating (commit f062fb9).
  • Temp dir leak on buildGraph throw — fixed: tempDirs.push(dir) now happens immediately after mkdtempSync, before the first await, in both buildEngine and buildHybrid. Both helpers accept tempDirs as a parameter (commit f062fb9).
  • Pre-flight can't distinguish local vs installed binary — fixed: SKILL.md Phase 0 step 4 now instructs the agent to resolve the actual binary path via require.resolve first. If the path points to the installed package, the agent copies the freshly built binary over it before running the availability check (commit f062fb9).
  • Step numbering gap (4.5 → 4.7) — fixed: PARITY step renumbered from 4.7 to 4.6 (commit 8c967d0).

Claude review observations acknowledged:

  • buildHybrid implementation detail fragility: valid point, but the comment in the code already documents why two sequential incremental builds in the same dir produce the hybrid path. A follow-up assertion on the DB metadata engine field would make it self-validating — filed as a note; not blocking this PR.
  • Grind skip condition under-specified: also valid. The "no grind adoption commits" check can be implemented by comparing git rev-parse HEAD before and after the grind loop. The text is clear enough for an implementor, but a headAfterGrind note in the loop would help — minor follow-up.

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@claude

@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Claude finished @carlos-alm's task —— View job


Re-review: Fixes from f062fb9 + 8c967d0

  • Read current state of scripts/parity-compare.mjs
  • Read current state of .claude/skills/parity/SKILL.md
  • Read current state of .claude/skills/titan-run/SKILL.md
  • Verify all fixes
  • Post updated assessment

All four issues raised in the first review and by Greptile are correctly addressed. Walking through each:

Fix 1 — __TOTAL_ROWS__ sentinel leak (scripts/parity-compare.mjs:198)
keys.delete('__TOTAL_ROWS__') is called before the diff iteration. The sentinel is still stored in the maps for the count display lines (239, 249) — that's the right split: summary uses the sentinel, diff logic ignores it. Clean.

Fix 2 — Temp dir leak on buildGraph throw (parity-compare.mjs:138–155)
tempDirs.push(dir) now happens synchronously after mkdtempSync and before the first await in both buildEngine and buildHybrid. Comments confirm the intent (// register before await so cleanup runs even if buildGraph throws). Both helpers accept tempDirs as a parameter. The finally block on the outer loop cleans all registered dirs. Correct.

Fix 3 — Pre-flight can't detect installed vs. locally built binary (SKILL.md:53–70)
Phase 0 step 4 now instructs the agent to run require.resolve('codegraph-core') against the dist to determine the actual resolved path, and to copy the freshly built binary over the installed one if needed — before re-checking isNativeAvailable(). The check is explicit and reproducible.

Fix 4 — Step numbering gap (.claude/skills/titan-run/SKILL.md)
Confirmed: PARITY step is now 4.6, immediately following GRIND (4.5). The section headers read ## Step 4.6 — PARITY, ### 4.6a, ### 4.6b, etc. No gap.


Rating: ⭐⭐⭐⭐⭐ (5/5)
Action: APPROVE

All previously raised issues are resolved cleanly. The buildHybrid implementation-detail fragility noted in the first review is acknowledged upstream and not blocking — the in-code comment documents the mechanism and the follow-up intent is noted. No new issues introduced by the fixes.

View job

Comment on lines +111 to +114
let fixtures = allFixtures;
if (langsFilter) {
const unknown = langsFilter.filter((l) => !allFixtures.includes(l));
if (unknown.length > 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 --langs with no value (e.g. the flag is the last argument or passed as --langs=) produces langsFilter = [] via ''.split(',').filter(Boolean). An empty array is truthy, so the if (langsFilter) branch executes, fixtures is filtered to nothing, the loop runs zero iterations, report.ok stays true, and the script exits 0 with "PARITY OK — 0 fixture(s), all engines identical". A CI gate that passes on zero audited fixtures gives a completely false signal.

Suggested change
let fixtures = allFixtures;
if (langsFilter) {
const unknown = langsFilter.filter((l) => !allFixtures.includes(l));
if (unknown.length > 0) {
let fixtures = allFixtures;
if (langsFilter) {
if (langsFilter.length === 0) {
console.error('parity-compare: --langs requires at least one fixture name.');
process.exit(2);
}
const unknown = langsFilter.filter((l) => !allFixtures.includes(l));
if (unknown.length > 0) {

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — added an early guard: if langsFilter.length === 0 (empty after parse), exits 2 with an explicit error message before reaching the fixture filter. Also fixed the related headBefore/headAfter capture gap in titan-run step 4.6b/4.6e noted in the Greptile summary.

Base automatically changed from refactor/engine-structure-parity to main June 12, 2026 03:41
@carlos-alm carlos-alm force-pushed the feat/parity-skill branch 2 times, most recently from 0d590ea to 14f5232 Compare June 12, 2026 04:13
@carlos-alm

Copy link
Copy Markdown
Contributor Author

Addressed latest Greptile feedback:

  • --langs empty-value false-pass — fixed: added early guard in parity-compare.mjs; if langsFilter.length === 0 exits 2 with an explicit error before reaching the fixture filter (commit d7e5d0e).
  • headBefore/headAfter missing in step 4.6 — fixed: step 4.6b now captures headBefore=$(git rev-parse HEAD) and step 4.6e captures headAfter before the commit-audit command uses them (commit d7e5d0e).
  • Commitlint header-max-length failure — fixed: shortened the fix(parity) commit header from 126 to 88 characters via rebase + force-push.

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

…/titan-run

scripts/parity-compare.mjs builds every resolution-benchmark fixture with
the wasm, native, and (--hybrid) hybrid paths and compares the full node
and edge multisets (kind, name, file, line, confidence, dynamic flag) —
zero divergence is the only passing state. It caught the Phase 8.2
cross-file return-type propagation gap in the native orchestrator on its
first run, plus the pre-existing divergences now tracked in #1466-#1472.

The /parity skill runs the audit, localizes each divergence by which
build paths disagree (wasm/hybrid/native table), fixes the root cause in
whichever engine is wrong, and re-verifies until clean.

/titan-run gains a conditional Step 4.7 — PARITY between grind and close.
The orchestrator stays repo-agnostic: a repo opts in by shipping its own
.claude/skills/parity/SKILL.md; without one the step prints a skip note
and continues.
…p 4.6

- Guard against --langs with no value: an empty langsFilter array is truthy
  so filtering produces zero fixtures and exits 0 — a false pass. Now exits 2
  with an explicit error message.
- Add headBefore capture to step 4.6b and headAfter capture to step 4.6e so
  the commit-audit command in 4.6e has concrete variables to expand.
@carlos-alm carlos-alm merged commit 06e7452 into main Jun 12, 2026
22 checks passed
@carlos-alm carlos-alm deleted the feat/parity-skill branch June 12, 2026 05:16
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant