Skip to content

fix: shape_check false positives — quoted keys, DOM leaks, errorKeys#501

Merged
magyargergo merged 5 commits into
abhigyanpatwari:mainfrom
marxo126:fix/shape-check-false-positives
Mar 26, 2026
Merged

fix: shape_check false positives — quoted keys, DOM leaks, errorKeys#501
magyargergo merged 5 commits into
abhigyanpatwari:mainfrom
marxo126:fix/shape-check-false-positives

Conversation

@marxo126

@marxo126 marxo126 commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Quoted key comparison: DB returns array elements with wrapping single quotes ('courses' vs courses), causing false MISMATCHes. Fixed by stripping quotes in fetchRoutesWithConsumers and normalizing in shapeCheck/apiImpact.
  • DOM method leaks: appendChild, removeChild, etc. leaked into consumer accessedKeys via the broad property-access regex. Fixed by expanding RESPONSE_METHOD_BLOCKLIST.
  • errorKeys visibility: Consumer accessing error-path keys (e.g., .error) now gets errorPathKeys field instead of being reported as unknown mismatch.

Test plan

  • 9 new unit tests for extractResponseShapes and extractConsumerAccessedKeys
  • Full test suite: 3882 passed, 0 regressions
  • Manual verification: re-index a Next.js project and run shape_check

🤖 Generated with Claude Code

…orKeys display

Three bugs caused shape_check to report false MISMATCH results:

1. DB array elements returned with wrapping single quotes ('key' vs key),
   causing Set comparison to fail. Fixed by stripping quotes in
   fetchRoutesWithConsumers and normalizing in shapeCheck/apiImpact.

2. DOM methods (appendChild, removeChild, etc.) leaked into consumer
   accessedKeys via the broad property-access regex. Fixed by expanding
   RESPONSE_METHOD_BLOCKLIST with common DOM manipulation methods.

3. Consumer accessing error-path keys (e.g., .error from errorKeys)
   was not distinguished from true mismatches. Added errorPathKeys
   field to consumer output for visibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Mar 24, 2026

Copy link
Copy Markdown

@marxo126 is attempting to deploy a commit to the NexusCore Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

github-actions Bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

CI Report

All checks passed

Pipeline Status

Stage Status Details
✅ Typecheck success tsc --noEmit
✅ Tests success unit tests, 3 platforms
✅ E2E success gitnexus-web changes only

Test Results

Tests Passed Failed Skipped Duration
4221 4220 0 1 169s

✅ All 4220 tests passed

1 test(s) skipped — expand for details
  • buildTypeEnv > known limitations (documented skip tests) > Ruby block parameter: users.each { |user| } — closure param inference, different feature

Code Coverage

Tests

Metric Coverage Covered Base Delta Status
Statements 70.75% 10424/14732 70.74% 📈 +0.0 🟢 ██████████████░░░░░░
Branches 61.4% 7086/11540 61.34% 📈 +0.1 🟢 ████████████░░░░░░░░
Functions 74.29% 916/1233 74.22% 📈 +0.1 🟢 ██████████████░░░░░░
Lines 73.06% 9295/12722 73.05% 📈 +0.0 🟢 ██████████████░░░░░░

📋 View full run · Generated by CI

@marxo126 marxo126 force-pushed the fix/shape-check-false-positives branch from 9fb37a6 to 5ba02c3 Compare March 24, 2026 21:35
@marxo126

Copy link
Copy Markdown
Contributor Author

Verification Results

Tested against a Next.js project with 30 API routes and 11 routes with response shapes + consumers:

Before fix: 6 false MISMATCH reports

  • Quoted keys ('courses' vs courses) caused comparison failures
  • DOM methods (appendChild, removeChild) leaked as consumer accessed keys
  • Error-path keys (.error from errorKeys) flagged as unknown mismatches

After fix: 0 false mismatches

  • responseKeys now display without wrapping quotes
  • DOM methods filtered from consumer accessedKeys
  • errorPathKeys field correctly identifies error-path consumer access
  • All 11 routes report clean shape matches

Unit tests: 9 new tests passing, 3882 total tests with 0 regressions.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to reduce false positives in the route “shape_check” flow by normalizing response key formats, preventing DOM-related property accesses from being misattributed as API response keys, and improving mismatch reporting for error-path accesses.

Changes:

  • Added unit tests covering response-shape extraction and consumer accessed-key extraction (including DOM-related code paths).
  • Normalized/stripped wrapping quotes from responseKeys / errorKeys / middleware when reading from the local DB and when computing shape-check results.
  • Expanded the consumer key extractor’s blocklist to avoid leaking DOM methods into accessedKeys.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
gitnexus/test/unit/shape-check.test.ts Adds unit coverage for response shape extraction and accessed-key extraction scenarios.
gitnexus/src/mcp/local/local-backend.ts Strips wrapping quotes from key arrays returned by the DB; adds errorPathKeys to consumer output.
gitnexus/src/core/ingestion/call-processor.ts Expands the response-method blocklist to filter DOM method/property leaks from accessed-key extraction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread gitnexus/test/unit/shape-check.test.ts Outdated
Comment on lines +13 to +22
it('extracts keys from .json() with quoted property names', () => {
const content = `return NextResponse.json({ 'courses': coursesData, 'articles': articlesData });`;
const result = extractResponseShapes(content);
// Keys should not contain quotes regardless of source format
expect(result.responseKeys).toBeDefined();
if (result.responseKeys) {
for (const key of result.responseKeys) {
expect(key).not.toMatch(/['"]/);
}
}

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

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

extractResponseShapes currently only detects unquoted identifier keys (it starts a key when it sees /[a-zA-Z_$]/ and skips over string literals), so this test using quoted property names ({ 'courses': ... }) will return responseKeys as undefined and fail. Either update extractResponseShapes to also extract string-literal property names, or adjust the test to match the current extractor behavior.

Suggested change
it('extracts keys from .json() with quoted property names', () => {
const content = `return NextResponse.json({ 'courses': coursesData, 'articles': articlesData });`;
const result = extractResponseShapes(content);
// Keys should not contain quotes regardless of source format
expect(result.responseKeys).toBeDefined();
if (result.responseKeys) {
for (const key of result.responseKeys) {
expect(key).not.toMatch(/['"]/);
}
}
it('does not extract keys from .json() with quoted property names (current limitation)', () => {
const content = `return NextResponse.json({ 'courses': coursesData, 'articles': articlesData });`;
const result = extractResponseShapes(content);
// Current extractor skips string-literal property names, so no responseKeys are returned.
expect(result.responseKeys).toBeUndefined();

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +57
console.log(data.items);
console.log(data.total);

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

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

This test declares const result = await fetch(...).then(r => r.json()); but then accesses data.items/data.total. That mismatch makes the fixture confusing and less representative of real-world usage (it would be clearer to access result.items/result.total or rename the variable to data).

Suggested change
console.log(data.items);
console.log(data.total);
console.log(result.items);
console.log(result.total);

Copilot uses AI. Check for mistakes.
Comment on lines +1419 to +1423
'classList', 'className', 'style', 'dataset',
'parentNode', 'parentElement', 'childNodes', 'children',
'nextSibling', 'previousSibling', 'firstChild', 'lastChild',
'click', 'focus', 'blur', 'submit', 'reset',
'href', 'download', 'target', 'rel', 'type',

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

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

The DOM-leak mitigation is implemented by expanding RESPONSE_METHOD_BLOCKLIST, but several newly added entries (e.g. href, download, target, rel, type, style, dataset) are not methods and can be legitimate JSON keys. This will cause extractConsumerAccessedKeys to silently drop those keys when accessed as data.href/data.type, reducing mismatch detection accuracy. Consider fixing the root cause by tightening propAccessPattern (e.g., avoid matching receivers that are part of a larger member chain like document.body.*), and keep the blocklist focused on actual methods (or rename it if it’s intended to block properties too).

Suggested change
'classList', 'className', 'style', 'dataset',
'parentNode', 'parentElement', 'childNodes', 'children',
'nextSibling', 'previousSibling', 'firstChild', 'lastChild',
'click', 'focus', 'blur', 'submit', 'reset',
'href', 'download', 'target', 'rel', 'type',
'classList', 'className',
'parentNode', 'parentElement', 'childNodes', 'children',
'nextSibling', 'previousSibling', 'firstChild', 'lastChild',
'click', 'focus', 'blur', 'submit', 'reset',

Copilot uses AI. Check for mistakes.
Comment thread gitnexus/src/mcp/local/local-backend.ts Outdated
Comment on lines +1661 to +1667
// Strip wrapping quotes from DB array elements — CSV COPY stores ['key'] which
// LadybugDB may return as "'key'" rather than "key"
const stripQuotes = (keys: string[] | null): string[] | null =>
keys ? keys.map(k => k.replace(/^['"]|['"]$/g, '')) : null;
const responseKeys = stripQuotes(row.responseKeys ?? row[3] ?? null);
const errorKeys = stripQuotes(row.errorKeys ?? row[4] ?? null);
const middleware = stripQuotes(row.middleware ?? row[5] ?? null);

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

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

stripQuotes is defined inside the for (const row of rows) loop, creating a new function per row. Since it’s pure and reused 3 times, consider hoisting it outside the loop (or making it a small private helper) to reduce repetition and improve readability.

Copilot uses AI. Check for mistakes.
@magyargergo

Copy link
Copy Markdown
Collaborator

@claude can you review this PR for completeness and try to find and identify performance issues and gaps in the implementation.

@github-actions

github-actions Bot commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Claude finished @magyargergo's task in 3m 0s —— View job


PR Review: fix/shape-check-false-positives

  • Gather context and read changed files
  • Analyze call-processor.ts changes
  • Analyze local-backend.ts changes
  • Analyze test coverage
  • Identify performance issues and implementation gaps
  • Post final review

The PR correctly identifies three real issues and ships targeted fixes. CI is green and the approach is sound, but there are several gaps worth addressing before merge.


Performance Issues

1. stripQuotes redefined inside a loop (local-backend.ts:1663)

for (const row of rows) {
  const stripQuotes = (keys: string[] | null): string[] | null =>   // ← new closure every row
    keys ? keys.map(k => k.replace(/^['"]|['"]$/g, '')) : null;
  ...
}

A new function object is allocated for every row returned by the query. For a repo with hundreds of routes this creates unnecessary GC pressure. Hoist it above the loop (or make it a module-level helper). Copilot also flagged this.

Fix this →

2. Double quote-stripping across three methods

fetchRoutesWithConsumers already strips quotes from responseKeys, errorKeys, and middleware before returning. Yet both shapeCheck (lines 1762-1765) and apiImpact (lines 1887-1889) independently apply the same strip function a second time:

// shapeCheck — redundant, fetchRoutesWithConsumers already stripped these
const strip = (k: string) => k.replace(/^['"]|['"]$/g, '');
const responseKeys = (r.responseKeys ?? []).map(strip);  // already clean
const errorKeys   = (r.errorKeys   ?? []).map(strip);    // already clean

The same pattern appears in apiImpact. Normalization should happen in one place only — the shared fetchRoutesWithConsumers. Remove the redundant strip calls in the two callers.

Fix this →


Implementation Gaps

3. extractResponseShapes still cannot handle quoted source keys (response-shapes.ts:79,83)

The fix normalizes what's read back from the DB, but the extractor itself has a blind spot. When a handler contains:

return NextResponse.json({ 'courses': data });

…the character parser at line 79 sets inString = "'" when it hits ', then skips everything until the closing ', so courses is never captured into callKeys. The test at shape-check.test.ts:13 asserts only expect(result.responseKeys).toBeDefined() (not that it contains 'courses'), which passes vacuously if responseKeys happens to be defined from another call — or would fail silently if undefined. The correct fix is to also extract string-literal keys in the parser (stripping the quotes at extraction time), or at minimum make the test document the current limitation as Copilot suggested.

Fix this →

4. Blocklist over-blocks legitimate API response fields (call-processor.ts:1423)

The newly added entries include href, target, rel, type, style, and dataset. These are valid JSON response keys that APIs routinely return (e.g. { type: 'admin' }, { target: '_self' }, { href: '/docs' }). Blocking them causes false negatives — the tool will silently miss real mismatches when consumers access these fields. This is the inverse of the problem being fixed.

The root issue is that propAccessPattern matches any data.X or res.X without knowing whether the receiver is a DOM node or an API response. Instead of blocklisting property names, consider tightening the receiver pattern (e.g. only match when the variable is clearly from a fetch/axios call in the same scope). At minimum, remove the non-method properties: href, target, rel, type, style, dataset.

Fix this →

5. Test fixture uses undeclared variable (shape-check.test.ts:56-57)

const result = await fetch('/api/test').then(r => r.json());
console.log(data.items);   // ← `data` is not declared in this scope
console.log(data.total);

The test passes because extractConsumerAccessedKeys operates on the raw string content and its regex matches data.items/data.total regardless of real runtime semantics — but the fixture misrepresents how the code would actually look. It should either use result.items/result.total or rename the variable to data. Copilot flagged this as well.

Fix this →

6. No test for errorPathKeys exclusion from mismatched

The PR adds errorPathKeys visibility, but there's no test asserting that keys from errorKeys do NOT appear in mismatched. The current logic does this correctly (line 1776 uses allKnownKeys which includes error keys), but a regression test would protect this behavior.


Minor / Cosmetic

  • 'keys' in the blocklist (line 1412) would block data.keys — but Object.keys(data) doesn't match the receiver pattern, so this is harmless; however response.keys as a legitimate API field (e.g. a JSON Web Key Set) would be silently dropped.
  • The routeMap method also calls fetchRoutesWithConsumers but doesn't use responseKeys/errorKeys for comparison — no issue there, it's read-only display.

Summary

Category Issue Severity
Performance stripQuotes closure inside loop Low
Performance Double-stripping in shapeCheck + apiImpact Low
Correctness Extractor can't handle quoted source keys Medium
Correctness Blocklist silently drops valid API fields (type, href, etc.) Medium
Test quality Undeclared variable data in fixture Low
Test coverage No regression test for errorPathKeysmismatched Low

The most impactful items to fix before merge are #3 (the extractor gap means the original ingestion problem is only half-solved) and #4 (the overly broad blocklist introduces new false negatives).

@magyargergo

Copy link
Copy Markdown
Collaborator

@marxo126 Can you please have a look at these findings?

marxo126 and others added 2 commits March 25, 2026 07:59
…ocklist

- Hoist stripQuotes above the loop to avoid per-row closure allocation
- Remove redundant strip calls in shapeCheck/apiImpact (fetchRoutesWithConsumers
  already normalizes)
- Extract single/double-quoted property keys in response-shapes.ts parser
- Remove over-broad blocklist entries (href, target, rel, type, style, dataset)
  that would cause false negatives for legitimate API fields
- Fix test fixture (undeclared variable) and add tests for quoted key extraction
  and legitimate API field names

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…location

- Rename RESPONSE_METHOD_BLOCKLIST → RESPONSE_ACCESS_BLOCKLIST (blocks
  properties too, not just methods) and add category comments
- Remove redundant errorKeySet — derive error-path keys from
  allKnownKeys + responseKeySet instead
- Replace content.slice().trimStart() with char-scan loop to avoid
  allocating a substring just to check one character
- Add backtick-quoted key test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@marxo126

Copy link
Copy Markdown
Contributor Author

Addressed review findings

Pushed two commits addressing the review:

47bef6a — fix: address review

  • Hoist stripQuotes above the loop (no per-row closure allocation)
  • Remove redundant strip calls in shapeCheck/apiImpact (already normalized by fetchRoutesWithConsumers)
  • Extract single/double-quoted property keys in response-shapes.ts parser
  • Remove over-broad blocklist entries (href, target, rel, type, style, dataset) that would cause false negatives
  • Fix test fixture (undeclared data variable), add tests for quoted key extraction and legitimate API field names

a8f3632 — refactor: simplify

  • Rename RESPONSE_METHOD_BLOCKLISTRESPONSE_ACCESS_BLOCKLIST (blocks properties too) with category comments
  • Remove redundant errorKeySet — derive error-path keys from allKnownKeys + responseKeySet
  • Replace content.slice().trimStart() with char-scan loop (avoids substring allocation)
  • Add backtick-quoted key test

12 tests passing, 3877 total, 0 regressions.

@magyargergo

Copy link
Copy Markdown
Collaborator

Can you please add integration tests as well? 🙏

Runs the full ingestion pipeline on a fixture with:
- Quoted property keys in .json() calls (single-quoted)
- Error vs success response separation by HTTP status
- Consumer files with DOM manipulation after fetch
- Consumer accessing error-path keys (.error from errorKeys)

Verifies:
- Route nodes created with correct responseKeys (no wrapping quotes)
- FETCHES edges contain accessedKeys in reason field
- DOM methods filtered from consumer accessedKeys
- Error-path keys captured alongside success keys

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@marxo126

Copy link
Copy Markdown
Contributor Author

Added integration tests (85014da):

  • 6 tests running the full ingestion pipeline on a dedicated fixture
  • Tests quoted key extraction, error/success separation, DOM method filtering, and error-path key capture
  • All passing alongside the 12 unit tests

Total: 18 tests covering this PR, 3883 suite-wide passes.

@magyargergo

Copy link
Copy Markdown
Collaborator

@claude Let's run a final review if this PR is production ready and ready to be merged.

@github-actions

github-actions Bot commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Claude finished @magyargergo's task in 2m 11s —— View job


Final Production-Readiness Review

  • Gather context from PR history and CI results
  • Read current state of all changed files
  • Verify previous review findings were addressed
  • Check for any remaining issues
  • Post final verdict

Verdict: ✅ Ready to merge

CI is green (4143 passed / 0 failed), all 6 previously identified issues have been resolved, and both unit and integration test coverage is solid.


Previous Review Issues — Status

# Issue Status
1 stripQuotes closure inside loop ✅ Fixed — hoisted to module scope at local-backend.ts:1658
2 Double-stripping in shapeCheck + apiImpact ✅ Fixed — both callers now use r.responseKeys ?? [] directly; comments confirm normalization is done by fetchRoutesWithConsumers
3 Extractor couldn't handle quoted source keys ✅ Fixed — response-shapes.ts:79-101 now handles ', ", and ` delimited keys; confirmed by 3 new unit tests and the integration fixture at search/route.ts
4 Blocklist over-blocked legitimate API fields (type, href, target, style) ✅ Fixed — those entries removed; test at shape-check.test.ts:119-132 explicitly asserts they're still captured
5 Undeclared data variable in test fixture ✅ Fixed — test at line 68 now declares const data = await fetch(...)... and accesses data.items/data.total
6 No regression test for errorPathKeys ∉ mismatched ⚠️ Not added — see below

Remaining Minor Gaps (non-blocking)

1. Missing regression test for errorPathKeys exclusion logic

The shapeCheck logic at local-backend.ts:1775 is correct — allKnownKeys includes both responseKeys and errorKeys, so error-path keys can never appear in mismatched. The integration test at shape-check.test.ts:81-91 verifies that error is captured in FETCHES edges, but no test verifies that shapeCheck's output shows errorPathKeys instead of mismatched when a consumer accesses a known error-path key. This is a maintenance gap, not a correctness bug.

2. 'keys' in blocklist could suppress JWKS-style response fields

RESPONSE_ACCESS_BLOCKLIST includes 'keys' (intended to block Object.keys(data)). However, data.keys on a JSON Web Key Set response would also be silently dropped. This is a pre-existing edge case that can be addressed in a follow-up if it becomes a real-world problem.


Code Quality Assessment

The implementation is clean and well-structured:

  • response-shapes.ts: The quoted-key parser correctly handles the three quote styles, correctly skips string values (checks for : after the quoted segment before committing to push), and has correct escape-sequence handling. No false positives from string values.
  • local-backend.ts: Single normalization point in fetchRoutesWithConsumers, both shapeCheck and apiImpact cleanly consume pre-normalized data with clear comments.
  • call-processor.ts: propAccessPattern is limited to known response variable names (data, response, result, json, body, res), so DOM elements like link.href are never captured regardless of the blocklist — which makes the blocklist focused on accidental matches, not load-bearing.
  • Integration fixtures: The 3 fixture files (search/route.ts, users/route.ts, GdprExport.tsx) are minimal, purpose-built, and cover the exact failure scenarios this PR fixes.

The two remaining gaps are minor enough that they should not block this merge. They can be tracked as follow-up improvements.

@magyargergo

Copy link
Copy Markdown
Collaborator

Can you please add those missing regressions into integration tests ? 🙏

@xkonjin xkonjin left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice fix overall. I found one test issue that looks like it is asserting a syntax the runtime parser will never actually see.

This added case is probably invalid JS/TS object syntax:

return NextResponse.json({ `users`: data, `total`: count });

Backticks are not valid quoted property keys in object literals. They only work for template literals / computed property expressions like { [users]: data }, which this parser does not appear to support either.

So the test can pass while covering a non-parsable source shape, and it may give a false sense that backtick-quoted keys are supported in real handler code.

I would either:

  • drop that test entirely, or
  • replace it with a computed-property case if you explicitly want to support that syntax, and then teach the extractor to parse it.

Everything else in the branch looked directionally good.

@marxo126

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough reviews. Here's what I'll add for the missing regression integration tests:

1. errorPathKeys exclusion from mismatched (end-to-end)

The existing integration tests verify that error is captured in FETCHES edges (test: "captures error-path key access from consumers"), but they don't run the actual shapeCheck tool output to verify that error-path keys appear in errorPathKeys and not in mismatched. Specifically:

  • Test scenario: The UserList fixture accesses both data (success key) and error (error key) from /api/users. After running the full pipeline, call shapeCheck (or replicate its logic) and assert:
    • error appears in consumer.errorPathKeys
    • error does NOT appear in consumer.mismatched
    • The route status is NOT MISMATCH (since all accessed keys are known)

This is the gap identified as issue #6 in the first review. The logic at local-backend.ts:1775 is correct today, but without a test, a future refactor could regress the allKnownKeys vs responseKeySet separation silently.

2. RESPONSE_ACCESS_BLOCKLIST does not suppress legitimate API field names

The unit tests at shape-check.test.ts:119-132 already cover this, but an integration-level test would be stronger:

  • Test scenario: Add a fixture route that returns { type: 'admin', href: '/profile' } and a consumer that accesses data.type and data.href. Verify the pipeline captures both keys in the FETCHES edge and that shapeCheck shows no mismatch (both are valid response keys, not blocklisted).

I'll push these as a follow-up commit on the branch.

@magyargergo

Copy link
Copy Markdown
Collaborator

@claude Let's run a final review if this PR is production ready and ready to be merged.

@github-actions

github-actions Bot commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Claude finished @magyargergo's task in 1m 57s —— View job


Final Production-Readiness Review

  • Read current state of all changed test files
  • Check if missing regression tests were added (errorPathKeys exclusion + legitimate API fields)
  • Check xkonjin's backtick-key concern
  • Verify all previous review findings remain resolved
  • Post final verdict

Verdict: ⚠️ Not quite — two items still need attention before merging

The core logic is correct and CI is green (4149 tests, 0 failures). All previous performance and correctness issues from prior reviews are properly addressed. However, two open items remain unresolved:


1. Backtick-quoted key test covers invalid JavaScript syntax

The test at shape-check.test.ts:31-36:

it('extracts backtick-quoted property keys from .json() call', () => {
  const content = 'return NextResponse.json({ `users`: data, `total`: count });';

{ \key`: value }is **not valid JS/TS** — backticks can only appear as template literals or in computed properties like{ [`key`]: value }. This test covers a source pattern that can never exist in real handler code, which @xkonjin flagged 3 days ago with no resolution. The test should either be dropped or replaced with a computed-property variant { [`key`]: value }` (which would also require teaching the parser to handle that form).

Fix this →


2. Promised regression tests for errorPathKeys ∉ mismatched were not pushed

In the last comment, @marxo126 said: "I'll push these as a follow-up commit on the branch." — but the integration test file still only has 6 tests and neither of the promised tests appears:

Missing test A: Verify that shapeCheck output places error in consumer.errorPathKeys and does not place it in consumer.mismatched. The integration test at line 81-91 verifies that error is captured in FETCHES edge accessedKeys, but it never calls shapeCheck to verify the downstream classification.

Missing test B: Integration-level verification that type, href, etc. are not blocked (only covered by a unit test; no integration-level assertion).

The fixture is already perfect for test A — UserList.tsx accesses res.data and res.error, users/route.ts returns { data } (success) and { error } (400). The test just needs to invoke shapeCheck against the indexed result and assert the consumer shows errorPathKeys: ['error'] and no mismatched.

Fix this →


Everything Else: ✅ Confirmed Resolved

# Issue Status
1 stripQuotes closure inside loop ✅ Hoisted above loop (local-backend.ts:1658)
2 Double-stripping in shapeCheck/apiImpact ✅ Removed; comments confirm normalization is in fetchRoutesWithConsumers
3 Extractor couldn't handle quoted source keys ✅ Parser handles ', ", ` at response-shapes.ts:79-101
4 Blocklist over-blocked type, href, target, style ✅ Removed; unit test at line 119-132 verifies they're captured
5 Undeclared data variable in test fixture ✅ Fixed; test declares const data = await fetch(...)
6 errorPathKeys ∉ mismatched logic ✅ Logic at local-backend.ts:1775 is correct — allKnownKeys covers both success and error keys

The two items above are small — the backtick test is a one-liner removal, and the errorPathKeys integration test should be straightforward given the existing fixture. Addressing these would make the PR clean for merge.


Addresses review request: errorPathKeys must not appear in mismatched,
and blocklisted DOM-like fields must not suppress legitimate API fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@marxo126

Copy link
Copy Markdown
Contributor Author

Added regression integration tests

Pushed shape-check-regression.test.ts with 6 tests covering the two scenarios requested:

1. errorPathKeys exclusion from mismatched

  • Seeds a /api/orders route with responseKeys: [orderId, status, items] and errorKeys: [error, code]
  • Consumer (OrderStatus) accesses orderId, status, and error
  • Asserts: error appears in errorPathKeys (not mismatched), route status is NOT MISMATCH, and global mismatch count is absent

2. Blocklist doesn't suppress legitimate API fields

  • Seeds a /api/links route with responseKeys: [type, href, target, label] — field names that overlap with DOM properties
  • Consumer (LinkList) accesses all four fields
  • Asserts: none of type/href/target/label appear in mismatched, route status is NOT MISMATCH, and no errorPathKeys are present (since all keys are in responseKeys)

All 6 tests pass locally. Uses the same seed-based withTestLbugDB + LocalBackend.callTool('shape_check', ...) pattern as the existing api-impact-e2e.test.ts.

@magyargergo

Copy link
Copy Markdown
Collaborator

@claude Let's run a final review if this PR is production ready and ready to be merged

@github-actions

github-actions Bot commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Claude finished @magyargergo's task in 1m 55s —— View job


Final Production-Readiness Review

  • Read current state of all changed files
  • Verify backtick test issue was addressed
  • Verify regression tests were properly added
  • Check for any remaining issues
  • Post final verdict

Verdict: ✅ Ready to merge — with one minor note (non-blocking)

CI is green (4149 passed / 0 failed). All correctness and performance issues from prior reviews have been resolved. The two regression test scenarios promised by @marxo126 are now present and well-structured.


Previous Open Items — Final Status

# Issue Status
Backtick-quoted key test (invalid JS syntax) ⚠️ Still present — see note below
errorPathKeys ∉ mismatched regression test ✅ Added — shape-check-regression.test.ts:82-121
Blocklist legitimate API fields regression test ✅ Added — shape-check-regression.test.ts:127-170

Regression Tests — Quality Check ✅

The new shape-check-regression.test.ts is solid:

  • Scenario 1 (errorPathKeys exclusion): Seeds /api/orders with responseKeys: [orderId, status, items] and errorKeys: [error, code]. Consumer OrderStatus accesses orderId, status, and error. Three tests verify: error appears in errorPathKeys, error does NOT appear in mismatched, route status is not MISMATCH, and no global mismatches count. This directly exercises the logic at local-backend.ts:1775-1777.

  • Scenario 2 (blocklist doesn't suppress valid API fields): Seeds /api/links with responseKeys: [type, href, target, label]. Consumer LinkList accesses all four. Three tests verify no mismatches, no MISMATCH status, and no spurious errorPathKeys. Complements the unit test at shape-check.test.ts:119-132 with an end-to-end assertion.

Both scenarios follow the established withTestLbugDB + LocalBackend.callTool pattern used by api-impact-e2e.test.ts. Seeding is clean, assertions are precise.


Remaining Minor Item (non-blocking)

Backtick test (shape-check.test.ts:31-36) — flagged by @xkonjin in review and by the previous Claude review, still unaddressed:

it('extracts backtick-quoted property keys from .json() call', () => {
  const content = 'return NextResponse.json({ `users`: data, `total`: count });';

{ `key`: value } is not valid JS/TS — backticks as bare object keys don't compile. The test passes because the parser handles backtick strings, but it covers a source pattern that can never exist in real handler code. It creates a false impression that this syntax is supported.

This is a test quality issue only — there is no runtime impact. Since it's been explicitly flagged twice with no resolution, it's worth a one-line fix (remove the test case or document the limitation), but it should not hold up this merge.

Fix this →


Everything Else: Confirmed ✅

Item Where
stripQuotes hoisted above loop local-backend.ts:1658
No redundant strip in shapeCheck local-backend.ts:1763 (comment confirms)
No redundant strip in apiImpact local-backend.ts:1886 (comment confirms)
Parser handles ', " quoted keys response-shapes.ts:79-101
Blocklist has no legitimate API fields call-processor.ts:1409-1430
Test fixture uses data consistently shape-check.test.ts:68-74

@magyargergo

Copy link
Copy Markdown
Collaborator

Can you please make sure tests are passing?

@magyargergo magyargergo merged commit 5a7ac21 into abhigyanpatwari:main Mar 26, 2026
16 of 19 checks passed
magyargergo added a commit that referenced this pull request Mar 26, 2026
The shape-check-regression test uses withTestLbugDB but was running in
the default vitest project with parallel forks, causing LadybugDB
file-lock conflicts on Windows CI. Move it to the lbug-db project
(sequential execution) and exclude from default.

Follows up on #501.
magyargergo added a commit that referenced this pull request Mar 26, 2026
The shape-check-regression test uses withTestLbugDB but was running in
the default vitest project with parallel forks, causing LadybugDB
file-lock conflicts on Windows CI. Move it to the lbug-db project
(sequential execution) and exclude from default.

Follows up on #501.
@marxo126 marxo126 deleted the fix/shape-check-false-positives branch March 26, 2026 06:45
motolese pushed a commit to motolese/GitNexus that referenced this pull request Apr 23, 2026
…npatwari#518)

The shape-check-regression test uses withTestLbugDB but was running in
the default vitest project with parallel forks, causing LadybugDB
file-lock conflicts on Windows CI. Move it to the lbug-db project
(sequential execution) and exclude from default.

Follows up on abhigyanpatwari#501.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants