Skip to content

Commit cec11f7

Browse files
Merge pull request #14 from officialCodeWork/build/phase-2/step-2.2-prop-flow
feat: prop-flow — per-instance data attribution (C1, the headline case)
2 parents ce7a3bc + 2582283 commit cec11f7

13 files changed

Lines changed: 345 additions & 11 deletions

File tree

TRACKER.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
## Status
66

77
- **Current phase:** 2 — Instance graph & cross-file data flow
8-
- **Next step:** 2.2Prop-flow: data attribution per instance
9-
- **Done:** 0.1–0.4, 1.1–1.6, 2.1
8+
- **Next step:** 2.3Handler resolution through props
9+
- **Done:** 0.1–0.4, 1.1–1.6, 2.1, 2.2 (headline: per-instance attribution green)
1010
- **Gates passed:** Gate 0 (CI + red-path, PRs #5/#6) · Gate 1 (precision 1.000 ≥ 0.90, recall 0.895 ≥ 0.80 across C2/C3/C5/A2/A7/A8/D4, zero forbidden hits)
1111

1212
## What CodeRadar is
@@ -148,7 +148,7 @@ The heart of the project. C1 and B1 live here.
148148
- Design-system components (imported from `node_modules` or a configured `designSystemPackages` list): instances are still created, flagged `external-definition` — the instance is ours even when the definition isn't.
149149
**Accept:** fixture `a5-design-system` green (match resolves to the usage site); instance counts asserted in c1 golden; barrel-file resolution unit-tested.
150150

151-
### [ ] 2.2 Prop-flow: data attribution per instance
151+
### [x] 2.2 Prop-flow: data attribution per instance
152152
**Failure modes:** C1 (the headline)
153153
**Build:**
154154
- For each instance, connect prop values to their origins in the parent scope: identifier props trace back through variable declarations to hook results / fetch results / store reads within the parent.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { useMembers } from "./hooks/useMembers";
2+
import { Table } from "./Table";
3+
4+
export function HookPage() {
5+
const { members } = useMembers();
6+
7+
return (
8+
<main>
9+
<h1>Member rows</h1>
10+
<Table rows={members} />
11+
</main>
12+
);
13+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { useQuery } from "@tanstack/react-query";
2+
3+
import { fetchBilling } from "./api/billing";
4+
import { Table } from "./Table";
5+
6+
export function QueryPage() {
7+
const { data } = useQuery({ queryKey: ["billing"], queryFn: fetchBilling });
8+
9+
return (
10+
<main>
11+
<h1>Billing rows</h1>
12+
<Table rows={data ?? []} />
13+
</main>
14+
);
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function Table({ rows }: { rows: string[] }) {
2+
if (rows.length === 0) return <p>Nothing to show</p>;
3+
return (
4+
<ul>
5+
{rows.map((r) => (
6+
<li key={r}>{r}</li>
7+
))}
8+
</ul>
9+
);
10+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export async function fetchBilling() {
2+
const res = await fetch("/api/billing");
3+
return res.json();
4+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useEffect, useState } from "react";
2+
3+
export function useMembers() {
4+
const [members, setMembers] = useState<string[]>([]);
5+
useEffect(() => {
6+
fetch("/api/members")
7+
.then((res) => res.json())
8+
.then(setMembers);
9+
}, []);
10+
return { members };
11+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"failureMode": "C1",
3+
"note": "Prop-origin variants beyond the useState/useEffect pattern: a react-query result prop (with ?? [] derivation) and a custom-hook result prop. The same Table component must carry a different API per page.",
4+
"expect": {
5+
"components": [{ "name": "Table", "instances": 2 }],
6+
"attributions": [
7+
{
8+
"component": "Table",
9+
"instanceAt": "QueryPage.tsx",
10+
"endpoints": ["/api/billing"]
11+
},
12+
{
13+
"component": "Table",
14+
"instanceAt": "HookPage.tsx",
15+
"endpoints": ["/api/members"]
16+
}
17+
],
18+
"forbidden": [
19+
{
20+
"component": "Table",
21+
"instanceAt": "QueryPage.tsx",
22+
"endpoint": "/api/members",
23+
"note": "poison: hook-page API attributed to the query-page table"
24+
},
25+
{
26+
"component": "Table",
27+
"instanceAt": "HookPage.tsx",
28+
"endpoint": "/api/billing",
29+
"note": "poison: query-page API attributed to the hook-page table"
30+
}
31+
],
32+
"queries": [
33+
{ "terms": ["Billing rows"], "status": "ok", "top": "QueryPage" },
34+
{ "terms": ["Member rows"], "status": "ok", "top": "HookPage" }
35+
]
36+
}
37+
}

eval/fixtures/c1-shared-datatable/golden.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@
1111
{
1212
"component": "DataTable",
1313
"instanceAt": "pages/UsersPage.tsx",
14-
"endpoints": ["/api/users"],
15-
"expectedFail": "phase-2: per-instance attribution requires prop-flow (step 2.2)"
14+
"endpoints": ["/api/users"]
1615
},
1716
{
1817
"component": "DataTable",
1918
"instanceAt": "pages/InvoicesPage.tsx",
20-
"endpoints": ["/api/invoices"],
21-
"expectedFail": "phase-2: per-instance attribution requires prop-flow (step 2.2)"
19+
"endpoints": ["/api/invoices"]
2220
},
2321
{
2422
"component": "UsersPage",

eval/history.jsonl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
{"generatedAt":"2026-07-13T10:09:02.527Z","commitSha":"4b4fd9e72204c47fa8ad523ff9b68fee41fc3a26","pass":77,"fail":0,"xfail":2,"unexpectedPass":0,"lineagePrecision":1,"lineageRecall":0.889,"matchAccuracy":1}
77
{"generatedAt":"2026-07-13T11:04:05.130Z","commitSha":"d13b90dd99c993889f57218997984e3e2e601cfd","pass":91,"fail":0,"xfail":2,"unexpectedPass":0,"lineagePrecision":1,"lineageRecall":0.895,"matchAccuracy":1}
88
{"generatedAt":"2026-07-13T11:10:56.348Z","commitSha":"b628c816231c4896f030ebc68a6621d0963d183c","pass":99,"fail":0,"xfail":2,"unexpectedPass":0,"lineagePrecision":1,"lineageRecall":0.895,"matchAccuracy":1}
9+
{"generatedAt":"2026-07-13T11:16:56.457Z","commitSha":"ce7a3bcbf95481114cd60ef62f8e840874ef7453","pass":108,"fail":0,"xfail":0,"unexpectedPass":0,"lineagePrecision":1,"lineageRecall":1,"matchAccuracy":1}

eval/thresholds.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"maxFail": 0,
33
"maxUnexpectedPass": 0,
44
"minMatchAccuracy": 1,
5-
"minLineagePrecision": 0.9,
6-
"minLineageRecall": 0.88
5+
"minLineagePrecision": 0.95,
6+
"minLineageRecall": 0.95
77
}

0 commit comments

Comments
 (0)