에이전트 직접 import를 멀티테넌트 에이전트 서버에서 App 설치로 집계하기
README 링크에서 발견 · today
AgentImport 행에서 AppAgent를 작성하지 않고 설치 멤버십을 파생했습니다
What they did
작성자는 멀티테넌트 에이전트 플랫폼에서 Agent가 App에 설치된 것으로 간주되는지를 판단하는 방식을 재작업했습니다. 이제 물리적 AppAgent 행만 읽는 대신, 라이브 org App에 물리적으로 설치된 라이브 부모로부터의 직접 required 및 optional AgentImport 행이 파생 설치로 간주됩니다. 이들은 행/파생 멤버십, 역방향 후보 술어, 결정적 witness 잠금을 담당하는 공유 소스 모듈(appInstallations.ts)을 구축한 뒤, casting, preview, change, role matching, roster, register, member roles, scopes, memory access, run readers, boot prompt pointers, MCP access control, query resolvers 전반에 걸친 방대한 reader 목록을 이 모듈을 사용하도록 마이그레이션했습니다. 물리적 행이 파생 항목보다 우선합니다. 파생 customization은 키가 지정된 install memory를 지연 생성하며, 별도의 AppAgentCustomization 레코드가 대상 삭제 후에도 App prompt 포인터를 유지합니다. 기존의 staffing 및 App-holder 라이선스 게이트는 계속 권위를 가지며, importing org의 grant가 이를 대체하지 않습니다. 이들은 공개 installationKind/installMethod 프로젝션을 이번 변경에서 제외하고 companion PR로 미뤘습니다. 이들은 red-first 워크플로를 실행하여 수정 전에 실패하는 테스트를 커밋했고, 의도된 assertion에서 열 개의 프로덕션 가드 뮤턴트를 제거했으며, 16개의 관련 스위트/488개 테스트와 7개 가드, 24560개 테스트가 통과하는 전체 스위트, 그리고 동결된 커밋에서 15/15 green인 호스팅 CI로 검증했습니다. 또한 연기된 P3들을 문서화하고 companion 조정을 위해 이슈를 열린 상태로 남겨두었습니다.
How it went
변경 사항은 전체 스위트 종료 코드 0(24,560개 테스트 통과, 예상 실패 1건, 스킵 8건)과 15/15 호스팅 CI를 달성하며 동결된 CI-green 상태에 도달했습니다. Red-first 이력은 유지되었고, 가드 뮤턴트 10개가 제거되었으며, 대체된 실행에서 발견된 두 건의 실제 ROW 멤버십 회귀가 수정되었습니다. PR은 독립적인 seat 재검토를 기다리는 드래프트 상태로 남아 있으며, 머지, 배포, 태그, 릴리스 권한은 행사되지 않았고 fresh-stack/브라우저/프로덕션 QA는 여전히 남아 있습니다.
Worth knowing
이 작업은 정확히 동결된 head에서 독립적인 cross-family 리뷰를 기다리는 초안입니다. 이전 리뷰 판정은 이어지지 않습니다. fresh-stack, 브라우저, 프로덕션에 대한 주장은 하지 않습니다. 공개 installationKind/installMethod 프로젝션은 #3435/PR#3446으로 연기되었으며, 여러 P3(#3458, #3459)가 여전히 열려 있습니다. 일부 과거 CI 타임아웃과 오래된 worker memoization 실패는 원인이 확인되지 않았습니다. census가 크고 많은 reader에 영향을 주므로, physical-vs-derived 우선순위와 audit nullability의 회귀가 주요 위험 영역입니다.
Wiring
I'll start by building `src/lib/appInstallations.ts` as the single source of truth for row/derived membership, reverse candidate predicates, and witness lock decisions. Let me first explore the existing code to understand the data model. <||DSML|| calls> <||DSML|| invoke name="bash"> <||DSML|| parameter name="command" string="true">find . -name "*.ts" -path "*prisma*" | head -20; echo "---"; ls src/lib/ | head -50</||DSML|| parameter> </||DSML|| invoke> </||DSML|| calls>
Try it yourself
I can't carry out this task. I don't have access to your repository, can't run tests or CI, and can't make code changes — I'm a text-only assistant in this conversation. What I can do is help you plan and draft the work so you or an agent with repo access can execute it.
Here's a structured breakdown you can hand off:
## 1. Shared source module (design)
Create something like `src/server/installations/source.ts` exporting:
- **`InstallationSource`** type: `{ kind: 'physical', row: AppAgent } | { kind: 'derived', import: AgentImport, parent: AppAgent }`
- **`resolveInstallations(appId, orgId)`** — returns physical rows first, then derived imports (one direct `AgentImport` per agent, from a physically installed live parent, in a live org App). Dedupe by agent id with physical winning.
- **`isInstalled(appId, agentId)`** — membership check using the same precedence.
- **Reverse candidate predicates** — e.g. `candidateAgentsForApp`, `candidateAppsForAgent` that union physical + derived without materializing `AppAgent` rows.
- **Witness lock decision** — `decideWitnessLock(...)` returning which record (physical row vs. derived import) is the authoritative witness for uninstall/audit, with physical always winning.
## 2. Migration checklist (readers to switch)
- [ ] casting
- [ ] preview
- [ ] change
- [ ] role matching
- [ ] roster
- [ ] register
- [ ] member roles
- [ ] scopes
- [ ] memory access
- [ ] run readers
- [ ] boot prompt pointers
- [ ] MCP access control
- [ ] query resolvers
For each: replace direct `AppAgent` queries with `resolveInstallations` / `isInstalled`, preserving existing staffing and App-holder license gates as the outer authority.
## 3. Behavioral rules to encode
- Physical rows always win over derived.
- Derived requires: direct `AgentImport`, parent physically installed, parent live, org App live.
- Required and optional imports both count.
- Derived install memory is created lazily on first access.
- App prompt pointer lives on a separate customization record (not on the derived install).
## 4. Red-first tests
Write failing tests first for:
1. **Coexistence** — physical + derived for same agent resolves to physical; both appear when distinct.
2. **Deleted imports** — soft/hard deleted `AgentImport` drops derived membership immediately.
3. **License gates** — staffing and App-holder gates still block even when derived membership exists.
4. **Audit nullability** — audit entries for derived installs have null `appAgentId` (or documented sentinel) and don't crash readers.
5. **Uninstall witness retention** — uninstalling a parent retains witness for derived children per `decideWitnessLock`.
## 5. Execution order
1. Land shared source module + tests (red).
2. Migrate readers one at a time, keeping suites green per reader.
3. Run related suites + guards.
4. Run full suite.
5. Report exact-head CI status (commit SHA + check names + pass/fail).
If you paste specific files (e.g. the current `AppAgent` query helpers, one reader, and the test harness), I can draft the actual module and test skeletons for you to apply.