Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ tests/fixture/target/
coverage/
.serena/
shrimp/
experiments/routes-oracle/target/
34 changes: 33 additions & 1 deletion HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,34 @@

세션을 이어받는 에이전트가 먼저 읽는 문서입니다.

## 진행 중 — feature/schema-usr (2026-09-30, API 영향 프로그램 Phase 7c)
## 진행 중 — feature/server-routes (2026-09-30, API 영향 프로그램 Phase 7 후속)

`rustograph routes --role server`(isthmus http `route-decl` 생산자)와 수확 이름 해석 결함 수정.

- **routes** — `src/source/routes.rs`(조립·자체 계약 검사) + `routes/{axum,actix,common,pattern,template,validate}.rs`.
axum 0.7·0.8(`specificity`, 버전은 resolve의 패키지 버전으로), actix-web 4(`registration-order`, App마다 group·리소스마다
index). 규칙과 소스 근거(axum 0.7.9/0.8.9·matchit 0.7.3/0.8.4·actix-web 4.15.0·actix-router 0.5.4·codegen 4.4.0·
tower-http 0.6.11 줄 번호)는 `docs/HTTP-ROUTES.md`. usr는 `harvest_parts`(같은 syn 수확의 트리·아레나)로 해석한 정점 ID라
`reach --roots-from routes.json`이 그대로 받는다(verify-cli-contract가 확인).
- **오라클** — `experiments/routes-oracle/`(독립 워크스페이스, `[lib] path`가 fixture lib.rs). 세 fixture 정밀도·재현율·
음성·끝 슬래시 요청 전부 100%, 기록을 `tests/routes.rs`가 오프라인 대조. 오라클이 잡아 고친 것: matchit 중간 파라미터·0.8
접두 파라미터의 빈 값 매칭(빈 값 변형), axum이 원문 경로를 비교해 리터럴 중괄호 경로에 인코딩 요청이 안 닿음, actix Trim
아래 빈 꼬리 변형이 안 닿음. 재기록은 `run_all.sh`.
- **공유 벡터** — isthmus `76b6141`에서 `conformance/`+`conformance.lock` 벤더링. template.grammar·normalize·dispatch.validate·
scope.validate 60건 통과, 나머지는 분류(새 ruleId면 테스트가 실패).
- **수확 수정(bea5155)** — 지역 묶음(let·매개변수·클로저·match 팔·if/while let·for) 스코프 스택(`harvest::locals`), 값 자리의
모듈 해석 폐기, `self` 수신자. 자기 분석 가짜 간선 109개 제거(모듈 references 100 + 지역명과 같은 fn 9), tests/fixture 8개.
type 레벨 cycles: 수정 커밋에서 13 → 8, 이 브랜치 끝에서 12(새 routes 모듈의 메서드 → 모듈 함수 투영 4개 — 게이트 아님).
- **e2e(scratch, isthmus 76b6141 무패치 + schemagraph 703a21f)** — 합성 axum+sqlx 백엔드: route 선택 trace 4 chain 모두 route →
핸들러 → relation-use → 테이블. 경로 호출 hop은 `direct`, 메서드 호출 hop은 `candidate`(syn 이름 팬아웃 — 수확 수정과 무관,
`--semantic`이 필요). 수정 전 바이너리로 같은 입력을 돌리면 지역 `repo`가 모듈 `crate::repo`로 읽혀 checkout·get_order가
`audit_log`에 **direct**로 닿는 거짓 hop 2개가 생겼고, 수정 후 사라졌다.
- 남은 것 / 알려진 근사(전부 거짓 match 쪽): axum 경로 우선 405 vs isthmus method 우선, actix 라우트 수준 method 가드(405)·
스코프 포획(뒤 서비스로 안 넘어감)·`web::get()`의 HEAD 미수용, 정규화 미들웨어가 닿지 않게 만든 선언을 strict로 냄. actix
매크로의 리소스 수준 method 가드에 소비자 `route-decl-path-shadowed` 경고가 날 수 있다(isthmus check로 확인, warning).
impl 메서드 안에서 만든 Router·App은 평가하지 않고 `route-coverage:`로 센다.

## 직전 — feature/schema-usr (2026-09-30, API 영향 프로그램 Phase 7c, PR #22 머지됨)

isthmus `trace`가 Rust 백엔드의 핸들러 도달을 관계 사용과 잇도록 두 가지를 더했다.

Expand Down Expand Up @@ -160,6 +187,11 @@ PR #8(의미 해석) 70ea82e · #10(의미 하드닝) 011c05b · #12(handoff)·
- `src/export.rs` — 결정적 JSON + mermaid + save/load.
- `src/sarif.rs` — SARIF 2.1.0(`rustograph/deny` 등 ruleId).
- `src/config.rs` — `.rustograph.yml` 파싱(serde_yml 격리), baseline 키.
- `src/source/routes.rs` + `routes/` — isthmus http `route-decl` 생산자(`rustograph routes --role server`).
axum(라우터 값 정적 평가·nest 결합·버전별 문법·빈 값 변형)·actix(App·Scope·Resource·매크로·configure·가드·
NormalizePath)·`pattern`(actix 패턴·정규식 분류)·`template`(정규 템플릿 문법·정규화)·`validate`(order·스코프 검사).
`source::harvest_parts`가 같은 수확의 트리·아레나를 넘긴다.
- `src/harvest/locals.rs` — 본문 지역 묶음 스코프(지역이 아이템보다 먼저).
- `src/source/schema.rs` — isthmus bridge-facts 생산자(`rustograph
schema`). SQL 문자열·sqlx·diesel table!·DSL 경로·sea_orm에서
relation-use 사실 수확, 산문 오탐 게이트·미해석/unlocated 계수.
Expand Down
31 changes: 31 additions & 0 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ rustograph dead --exclude-tests # #[cfg(test)] 서브트리 제외
rustograph graph --target x86_64-pc-windows-msvc # cfg(트리플) 평가
rustograph mcp # MCP stdio 서버 — 에이전트가 되묻는 통로
rustograph schema --dir . --out schema-facts.json # isthmus persistence 사실
rustograph routes --role server --out routes.json # isthmus http route-decl(axum·actix-web)
rustograph reach mycrate::api::list_users # isthmus language-traversal(정방향)
rustograph impact --format language-traversal --roots-from schema-facts.json # 역방향
```
Expand Down Expand Up @@ -134,6 +135,36 @@ import할 때만 인정합니다. 파싱 실패 파일·문법이 다른 `table!
스캔은 추측하지 않습니다 — 정적으로 해석할 수 없는 것은 지어내지 않고
센 것입니다.

## 서버 라우트 — `routes --role server`

`rustograph routes --role server`는 axum 0.7·0.8과 actix-web 4 서버가 선언한
(method, 정규 경로 템플릿)마다 `route-decl` 사실 하나를 담은 isthmus
`bridge-facts` v1 문서(`platform: "rust"`, `target: "http"`)를 냅니다.
핸들러 `symbol.usr`가 `reach`의 정점 ID와 같아서 `isthmus trace`가 route →
핸들러 → relation-use(`schema`) → 테이블(`schemagraph facts`)로 잇습니다.

- **axum**(`dispatch: "specificity"`, matchit의 정적 > 파라미터 > catch-all):
`Router::new().route(..)` 체인, 메서드 라우터(`get`/`post`/…/`any`/
`on(MethodFilter)`), `nest`(axum `path_for_nested_route`와 같은 결합),
`merge`, 지역 `let`·재대입, 라우터를 돌려주는 크레이트 함수. 경로 문법은
해석된 axum 버전을 따릅니다 — 0.7은 `:id`/`*rest`, 0.8은 `{id}`/`{*rest}`/`{{`.
- **actix-web**(`dispatch: "registration-order"`, App마다 `order.group`,
리소스마다 `order.index`): `#[get("/x/{id}")]` 매크로,
`web::resource().route(web::get().to(h))`, `web::scope`, `App::route`,
`configure`, 가드(`narrowed`), `{id:\d+}` → `paramConstraints`, `{tail}*`
catch-all, `NormalizePath` 미들웨어의 `trailingSlash` 효과.
- 정적으로 확정하지 못한 것(리터럴이 아닌 경로, 모르는 함수가 만든 라우터,
fallback, tower 서비스)은 dynamic 사실이나 스코프 있는
`route-coverage:`·`framework-provided-routes:` 한계가 됩니다 — 추측한
라우트를 만들지 않습니다.

규칙마다 근거가 된 axum·matchit·actix-web 소스 줄은
[docs/HTTP-ROUTES.md](docs/HTTP-ROUTES.md)에 있습니다. 오라클
(`experiments/routes-oracle/`)이 같은 fixture 소스를 진짜 크레이트로 컴파일해
프로세스 안에서 요청을 보내 세 fixture 모두 정밀도·재현율 100%를 확인했고,
그 기록을 `cargo test`가 오프라인으로 대조합니다. isthmus 공유 벡터는
`conformance/`에 잠금 파일과 함께 벤더링했습니다.

## 순회 문서 — `reach` / `impact --format language-traversal`

isthmus [`language-traversal` v1](https://github.com/ictechgy/isthmus/blob/main/docs/LANGUAGE-TRAVERSAL.md)
Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ rustograph mcp --graph .rustograph/graph.json
# Emit bridge-facts for isthmus' persistence join (SQL relation uses)
rustograph schema --dir . --out schema-facts.json

# Emit isthmus http route-decl facts for axum / actix-web servers
rustograph routes --role server --dir . --out routes.json
rustograph reach --roots-from routes.json # handler usrs are graph vertices

# isthmus language-traversal v1 for `isthmus trace` (many roots, one pass)
rustograph reach mycrate::api::list_users mycrate::api::create_user
rustograph impact --format language-traversal --roots-from schema-facts.json
Expand Down Expand Up @@ -229,6 +233,39 @@ and column attributes without a table binding surface as `limitations`,
not silence. The name-based scan never guesses: what cannot be resolved
statically is counted, not invented.

## Server routes — `routes --role server`

`rustograph routes --role server` emits an isthmus `bridge-facts` v1
document with `platform: "rust"`, `target: "http"` and one `route-decl`
fact per (method, canonical path template) that an axum 0.7/0.8 or
actix-web 4 server declares. `isthmus trace` joins it with client calls,
`reach` (the handler `symbol.usr` is the same vertex id), `schema` and
`schemagraph facts` to answer "which tables does this endpoint touch".

- **axum** (`dispatch: "specificity"`, matchit's static > param >
catch-all order): `Router::new().route(..)` chains, method routers
(`get`/`post`/…/`any`/`on(MethodFilter)`), `nest` (joined like axum's
`path_for_nested_route`), `merge`, local `let`/reassignment and crate
functions that return routers. The path syntax follows the resolved axum
version — `:id`/`*rest` for 0.7, `{id}`/`{*rest}`/`{{` for 0.8.
- **actix-web** (`dispatch: "registration-order"`, one `order.group` per
`App`, one `order.index` per resource): `#[get("/x/{id}")]`-style macros,
`web::resource().route(web::get().to(h))`, `web::scope`, `App::route`,
`configure`, guards (`narrowed`), `{id:\d+}` → `paramConstraints`,
`{tail}*` catch-alls, and the `NormalizePath` middleware's effect on
`trailingSlash`.
- Whatever cannot be resolved statically (non-literal paths, routers built
by unknown functions, fallbacks, tower services) becomes a dynamic fact or
a scoped `route-coverage:` / `framework-provided-routes:` limitation —
never a guessed route.

Every rule, with the axum/matchit/actix-web source lines that back it, is in
[docs/HTTP-ROUTES.md](docs/HTTP-ROUTES.md). An oracle
(`experiments/routes-oracle/`) compiles the same fixture sources against
the real crates and probes them in-process: 100% precision and recall on
all three fixtures, recorded and checked offline by `cargo test`. The
isthmus conformance vectors are vendored under `conformance/` with a lock.

## Traversal documents — `reach` / `impact --format language-traversal`

```bash
Expand Down
12 changes: 12 additions & 0 deletions conformance.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"commit": "76b6141e71c84e0ab1026ad1f18f910b9d966dc8",
"files": {
"http-dispatch.json": "efeecae0622ac8ee4185d10ea117fb9c3c2b2dc504137cae0abd1841f3414f47",
"http-limitation-scope.json": "757200f40b1fa54a30b9486ff24bf5f89c2f7bc4fac26eb9a79d62004a1c847e",
"http-template.json": "770f3a79986560579c94b2548d392eb66ef877dc95b6284211551eeb27cf53e6",
"url-compose.json": "afb689685e3dc987d37ce6b8ff32088604956a67dfe8a7e1556aa462f09a1c7a"
},
"format": "isthmus-conformance-lock",
"source": "https://github.com/ictechgy/isthmus",
"version": 1
}
19 changes: 19 additions & 0 deletions conformance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# isthmus 공유 적합성 벡터

isthmus(`76b6141e71c84e0ab1026ad1f18f910b9d966dc8`)의 `conformance/`를 그대로 가져온 사본이다. 정본은 isthmus가
소유하며, 이 디렉터리 파일을 직접 고치지 않는다. 갱신할 때는 isthmus main의 파일과 `SHA256SUMS`를 함께 다시
복사하고(새 suite 파일 포함) 저장소 루트의 `conformance.lock`에 커밋과 파일별 sha256을 적은 뒤
`cargo test --test routes`로 확인한다.

rustograph가 실행하는 사례(생산자 대상, `rustograph routes --role server`):

| suite | ruleId | 검사 |
|---|---|---|
| `http-template` | `template.grammar` | 정규 문법 검사기(`source::routes::template::template_problem`)가 소비자와 같은 판정·거부 사유를 낸다 |
| `http-template` | `template.normalize` | URI 경로 정규화(`normalize_uri_path`)가 같다 |
| `http-dispatch` | `dispatch.validate` | `order` 검증기(`source::routes::validate::order_problem`)가 소비자와 같이 판정한다. fixture 출력에도 적용한다 |
| `http-limitation-scope` | `scope.validate` | 스코프 검증기(`scope_problem`)가 소비자와 같이 판정한다(생산 문서가 거부되지 않게) |

건너뛰는 사례와 이유: 소비자 전용 사례(`match.*`, `dispatch.match`, `dispatch.shadow`, `scope.applies` — 적용 판정은
소비자가 한다), 다른 생산자의 프레임워크 변환(`framework.openapi.*`, `framework.spring.*`), `url-compose` 전체(클라이언트
`route-call` 조립 규칙이며 rustograph는 서버 선언만 낸다).
4 changes: 4 additions & 0 deletions conformance/SHA256SUMS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
efeecae0622ac8ee4185d10ea117fb9c3c2b2dc504137cae0abd1841f3414f47 http-dispatch.json
757200f40b1fa54a30b9486ff24bf5f89c2f7bc4fac26eb9a79d62004a1c847e http-limitation-scope.json
770f3a79986560579c94b2548d392eb66ef877dc95b6284211551eeb27cf53e6 http-template.json
afb689685e3dc987d37ce6b8ff32088604956a67dfe8a7e1556aa462f09a1c7a url-compose.json
Loading
Loading