패키지 경계 및 코드베이스 관리 컨벤션
상태: 신규 작업과 경계 변경에 적용 범위: workspace package, example, demo, 아키텍처 근거, 문서 ownership
Context-Action 저장소에서 패키지 경계는 폴더 구분만이 아니라 ownership과 의존성 경계다. 각 패키지는 하나의 주 책임, 하나의 public contract, 하나의 명확한 검증 경로를 가져야 한다.
1. 경계 규칙
- 패키지는 하나의 응집된 책임을 소유한다. 서로 다른 책임이 필요하면 작업을 나누거나 아키텍처 decision을 먼저 기록한다.
- 다른 패키지는 선언된 package export를 통해서만 사용한다. 상대 경로,
src/,dist/, test 전용 alias로 다른 패키지를 import하지 않는다. package.json이 runtime, peer, optional, development dependency의 source of truth다. 소스 import와 dependency 선언이 불일치하면 경계 결함이다.exports가 public surface다. export되지 않은 파일은 implementation detail이며 패키지 간 연동 지점으로 사용하지 않는다.- package README는 discovery 문서다. 정식 동작·아키텍처 계약은
docs/아래 한 개의 authoritative guide가 소유하며 README에 두 번째 사양을 복제하지 않는다. dist/, API reference, LLMS artifact, coverage, generated report는 파생 결과다. 원본과 generator를 수정하고 다시 생성하며 generated 파일을 canonical implementation으로 취급하지 않는다.- 패키지 경계 변경은 dependency review, focused proof, 문서 ownership 갱신을 같은 변경에 포함한다. 파일을 옮기는 것만으로 migration이 끝난 것으로 보지 않는다.
2. 현재 패키지 맵
새 패키지는 기존 패키지가 dependency 방향이나 release 요구를 위반하지 않고 책임을 소유할 수 없을 때만 추가한다.
| 패키지 | 경계 역할 | 소유하는 것 | 소유하지 않는 것 |
|---|---|---|---|
@context-action/core | runtime foundation | action pipeline, handler execution, validation contract, core error | React, tool transport, Zod, browser UI, store |
@context-action/tool-protocol | transport contract foundation | JSON Schema, Zod action schema, MCP/provider adapter, tool call, approval queue, 호출 idempotency/provenance/observability 계약 | React rendering, action registry internals, durable persistence, architecture policy |
@context-action/tool-durable-operations | mutation safety foundation | durable operation record, side-effect runner, HTTP/queue adapter, IndexedDB/Redis/PostgreSQL reference backend | provider-neutral tool schema, React rendering, domain별 idempotency/outbox 정책 |
@context-action/mutative-core | immutable runtime foundation | 유지보수되는 Mutative 호환 draft·patch·array engine | Context-Action adapter, React, time-travel policy |
@context-action/mutative | runtime adapter | React가 사용하는 immutable update/patch utility | action orchestration, React context |
@context-action/react | framework adapter | React context, store, hook, ref, tool integration | core policy, 문서 생성, Git 분석 |
@context-action/sem-foundation-contracts | 분석 contract foundation | symbol identity, snapshot, revision, shared limit, wire contract | SEM subprocess, Git worktree, architecture policy |
@context-action/sem-foundation-repository | repository runtime foundation | Git revision, first-parent history, detached worktree | symbol semantics, architecture rule, UI behavior |
@context-action/architecture-governance | 실험적 convention control plane | Context-Action authored capability registry, policy 검증, complete snapshot/history, snapshot-backed ContextScope projection | 범용 architecture 추론, React runtime, 일반 문서 생성 |
@context-action/sem-doc | 운영용 Symbol Context plane | 독립 advisory symbol/document context, canonical operational sem-doc-context-scope.v3, binding, Git diff 연동 | architecture convention/policy와 snapshot-backed governance; @context-action/sem-foundation-* 재사용 |
@context-action/llms-generator | documentation generator | LLMS summary, priority, derived artifact | runtime behavior, architecture policy |
@context-action/typedoc-vitepress-sync | API documentation adapter | TypeDoc-to-VitePress 동기화 | handwritten guide, runtime code |
@context-action/style-testing | UI verification tool | style/browser 분석과 CLI | core state contract |
@context-action/live-code-editor | private integration | live editor 실험 | promotion 전 stable runtime contract |
@context-action/openrouter-browser-storage | private integration | OpenRouter example browser persistence | core/react용 generic storage abstraction |
example/과 demos/는 library가 아니라 integration host다. public package를 조합하고 아키텍처를 보여줄 수 있지만 재사용 구현은 다른 패키지가 import하기 전에 package로 승격한다.
@context-action/sem-doc은 기존 @tsdoc-edge/sem-doc에서 workspace identity migration을 완료했다. source 경로와 CLI binary는 유지하며, 공개 npm release는 repository publish workflow가 관리한다. 이 패키지는 운영용 Symbol Context SSOT이며 임시 staging package나 Architecture Governance adapter가 아니다. 구현 중 화면/API/ transaction grouping에는 sem-doc-context-scope.v3를 유일한 operational projection으로 사용한다. Architecture Governance의 기존 context-action/context-scope@1.0은 architecture review용 snapshot-bound artifact로 그대로 유지하며 sem-doc의 두 번째 구현 대상으로 취급하지 않는다.
기존 test-driven documentation package와 repository-owned example은 0.8/0.9 안정화 과정에서 제거했다. 공개 API 문서는 exported source와 JSDoc → TypeDoc → typedoc-vitepress-sync → VitePress라는 단일 경로를 사용한다. LLMS summary는 canonical docs/에서 파생하며 별도의 API SSOT가 아니다.
3. 의존성 방향
기본 방향은 다음과 같다.
@context-action/core ──→ @context-action/react
@context-action/tool-protocol ──→ @context-action/react
@context-action/tool-durable-operations ──→ @context-action/react
@context-action/mutative-core ──→ @context-action/mutative ──→ @context-action/react
@context-action/sem-foundation-contracts ──→ @context-action/sem-foundation-repository
├──→ @context-action/architecture-governance ← @ataraxy-labs/sem
└──→ @context-action/sem-doc (운영용 Symbol Context plane)core는react에 의존하지 않는다.tool-protocol은 framework-neutral이며core나react에 의존하지 않는다. provider/tool 경계를 소유한다.tool-durable-operations도 framework-neutral이며core,react,tool-protocol에 의존하지 않는다. durable mutation recovery와 provider side-effect adapter를 소유한다.react는core,mutative를 사용하며mutative는 하위mutative-coreruntime만 사용하고 React type을 import하지 않는다.mutative-core는 upstream 호환성을 유지하며 Context-Action adapter나 React에 의존하지 않는다.sem-foundation-repository는 contracts를 사용하고 역방향 의존성은 허용하지 않는다.architecture-governance는 foundation과 SEM을 사용한다. foundation은 capability, policy, Context-Action UI, registry를 알지 않는다.architecture-governance와sem-doc은 목적과 계약이 다른 나란한 consumer이며 서로 runtime 의존성을 추가하지 않는다. 두 책임을 동시에 건드리는 변경은 두 도구의 경계 가이드를 먼저 확인한다.- 문서 generator는 소스·문서를 읽을 수 있지만 runtime package가 generator에 의존하지 않는다.
- example과 demo는 그래프의 leaf다. 패키지가 example/demo를 import하지 않는다.
새로운 안정된 방향이 생기면 reviewer 기억에 의존하지 말고 named policy rule로 추가한다.
protocol/durable 분리는 architecture/rules/package-boundaries.json의 CA-PKG-TOOL-PROTOCOL-NO-RUNTIME-COUPLING과 CA-PKG-TOOL-DURABLE-NO-PROTOCOL-RUNTIME-COUPLING 규칙으로 강제한다. 이 규칙은 runtime·peer·optional dependency field를 검사하며, test 전용 도구가 devDependencies에 있는 것은 publish boundary를 바꾸지 않는다.
Mutative 계약 전파
immutable runtime 계약은 @context-action/mutative-core가 소유하며 @context-action/mutative는 이를 그대로 전달해야 한다.
- adapter의
freeze는 coreenableAutoFreeze로 전달하고strict와 분리한다. - patch consumer는 Set의
replacepatch를 보존하고, 문자열이 아닌 Map key나 Symbol 속성에는 array path를 사용해야 한다. - core 변경 후 adapter와 time-travel 테스트에서 이 동작을 회귀 검증한다.
정식 동작 및 동기화 기록은 Mutative Core 히스토리 및 원본 참조를 따른다.
4. 패키지 contract
각 package README와 manifest는 다음을 답해야 한다.
Package ID와 안정성: public | private | transitional | experimental
주 책임:
Public entry point와 exports:
Runtime dependency:
Peer/optional dependency:
소유 source directory:
Test/verification command:
Authoritative guide:
Architecture capability 또는 decision:
Migration/deprecation 계획:기본 디렉터리 구조는 다음과 같다.
packages/<package>/
├── package.json # dependency/export contract
├── README.md # discovery/consumer quickstart
├── src/ # canonical implementation
├── test/ 또는 __tests__/ # executable proof
├── docs/ # 필요한 경우 package 상세
├── schemas/ # versioned public schema
└── dist/ # generated output; 직접 수정하지 않음architecture/registry.json은 stable capability identity와 evidence를 기록한다. package manifest, README, public guide를 대체하지 않는다. capability anchor는 owner package 내부를 가리켜야 하며 package 경계 변경 시 관련 capability 또는 decision도 갱신한다.
5. 패키지 단위 개발 라이프사이클
1단계 — 변경 분류
| 분류 | 확인 질문 | 필요한 source of truth |
|---|---|---|
| public API | export type/entry point가 바뀌는가? | source/JSDoc, API docs, migration note |
| runtime behavior | state/action/store/tool behavior가 바뀌는가? | package spec, focused test, runnable example |
| boundary | ownership/dependency 방향이 바뀌는가? | 본 컨벤션, policy, decision |
| analysis contract | snapshot/manifest/schema/identity가 바뀌는가? | schema, parser/validator, fixture, architecture guide |
| documentation/tooling | docs flow 또는 generated output만 바뀌는가? | generator source, guide, docs gate |
2단계 — owner package 선택
첫 helper를 넣기 편한 위치가 아니라 public responsibility가 바뀌는 패키지를 owner로 선택한다. 두 package contract를 가로지르면 lower-level owner에 안정 contract를 두고 higher-level package에 최소 adapter를 둔다. 이 결정을 피하기 위해 임의의 shared package를 만들지 않는다.
3단계 — 확장 전 contract 작성
새 capability/boundary에는 stable ID, owner, scope/non-goal, dependency/export 변경, invariant 또는 schema revision, focused test, 문서 경로, migration/removal 조건을 기록한다. 이슈·decision은 스펙·이슈·문서 관리 컨벤션, symbol evidence는 아키텍처 거버넌스를 사용한다.
4단계 — package 순서로 구현·검증
Context-Action runtime 변경:
pnpm build:core
pnpm build:react
pnpm --filter example type-check
pnpm --filter example check
pnpm example:build분석·아키텍처 변경:
pnpm arch:type-check
pnpm arch:test
pnpm arch:check:registry
pnpm docs:buildpublic surface 변경이면 package export/tarball check도 추가한다.
5단계 — ownership graph 갱신
handoff 전에 package manifest/export, README/authoritative guide, test/fixture, policy 또는 registry/decision, 영·한 public page, generated artifact를 순서대로 갱신한다.
문서-심볼 binding 컨벤션
Markdown 또는 MDX 문서가 하나의 구현 심볼을 설명한다면 code-backed SSOT 문서로 취급하고 semDocumentKind: code와 다음 sem-doc frontmatter 네 필드를 요구한다.
semDocumentKind: code
semEntityId: src/auth.ts::function::authenticateUser
semEntityName: authenticateUser
semEntityType: function
semEntityFile: src/auth.ts문서에는 # [[Authentication Entry Point]]와 같은 canonical H1 checkpoint도 정확히 하나 있어야 한다. Concept·architecture·process·tooling guide는 document-only로 남을 수 있지만 resolved symbol SSOT가 아니다. external-reference 문서는 직접 dependency surface를 설명할 수 있지만 node_modules 심볼의 소유권을 주장하지 않는다. code-backed 문서의 unresolved work-context 결과는 동일 이름 fallback이 성공한 것이 아니라 문서 계약 이슈로 기록한다.
저장소의 authoritative docs root에는 strict 검증을 사용한다.
pnpm --filter @context-action/sem-doc exec node dist/cli.js docs validate-bindings <docs-root> --strict --jsonStrict 모드는 모든 문서의 semDocumentKind 선언, code 문서의 정확한 binding, non-code 문서의 binding 금지를 강제한다.
code-backed 문서를 변경할 때는 선언된 binding validator와 대표 context query를 모두 실행한다.
pnpm --filter @context-action/sem-doc exec node dist/cli.js docs validate-bindings <docs-root> --strict --json
pnpm --filter @context-action/sem-doc exec node dist/cli.js work-context <entity> --docs-root <docs-root> --json정확한 규칙은 sem-doc document entity binding 컨벤션이 소유한다.
6. 패키지 추가·병합·분리·폐기
- 추가: ID, owner, stability, 주 책임, public/private 결정, dependency graph, export, focused test, README, authoritative guide, boundary policy를 갖춘다. private/experimental이면 승격 조건을 적는다.
- 병합: release cadence, owner, dependency 방향, public contract가 같을 때만 병합한다. source/test를 함께 옮기고 stable ID를 보존하며 old export와 migration decision을 정리한다.
- 분리: independent release contract가 생기거나 upward dependency가 생기거나 runtime/analysis/docs가 섞일 때 분리한다. stable contract는 lower-level package가 소유한다.
- 폐기: README에 replacement와 removal condition을 남기고 새 cross-package consumer를 막으며 accidental import를 검증한다.
7. 코드베이스 정리 규칙
- 중복 구현은 canonical owner를 정하고 필요한 경우 re-export/migration path를 만든 뒤 제거한다.
utils는 package 내부에 둔다. versioned·policy-neutral contract인 경우에만 shared extraction을 검토한다.- 테스트는 증명하는 package와 함께 둔다. cross-package integration test는 integration host 또는 higher-level package에 둔다.
- runtime package에 architecture/documentation tooling을 넣지 않는다.
- ownership 판단에
dist나 generated API를 사용하지 말고 source package와exports를 추적한다. - package 경계를 넘는 파일 이동은 TypeScript가 통과해도 API/architecture change로 취급한다.
8. 리뷰 체크리스트
- [ ] owner package와 primary change class가 명시되어 있다.
- [ ] responsibility/non-goal이 README 또는 정식 guide에 있다.
- [ ] source import와 runtime/peer/dev dependency가 일치한다.
- [ ] package 간 import가 선언된 export만 사용한다.
- [ ] lower-level package가 adapter, example, generator를 import하지 않는다.
- [ ] test와 fixture가 contract 가까이에 있고 boundary regression이 필요한 경우 포함한다.
- [ ] registry, policy, schema, decision evidence가 갱신되었다.
- [ ] code-backed SSOT 문서가 정확한 sem entity frontmatter를 선언하고 대표 work-context에서 resolve된다.
- [ ] public behavior라면 영·한 문서와 discovery link가 정합하다.
- [ ] generated file은 source에서 재생성했다.
- [ ] 비례하는 package/repository gate 결과를 기록했다.