Skip to content

Commit d7fcddf

Browse files
committed
앱 문서 계약을 손실 없이 보존한다
상황: Percent 앱 문서는 title 외의 entry, layout, 코드 표시, 상태 정책을 저장하지 않아 다시 열면 공개 화면 구성이 유실됐고 자동화 녹화기도 구형 헤더를 새로 생성했다. 변경: AppSpec과 ExecutableUnitSpec 닫힌 schema 및 Python·TypeScript 생성 계약을 추가하고, codaro-app TOML metadata의 엄격한 읽기·쓰기·legacy 이관·entry 검증을 구현했다. 앱 설정을 프런트 정규화 경계까지 연결하고 완료된 mainPlan leaf를 삭제했다. 전체 검증에서 드러난 Windows 임시 디렉터리 잠금은 content-addressed 학습 아카이브 공개 경계의 제한 재시도와 부정 테스트로 보강했다. 영향: 같은 Percent 파일이 일반 Python으로 실행되면서 앱 projection을 보존하고, 알 수 없는 schema나 사라진 entry는 원본을 덮어쓰기 전에 실패한다. 기존 codaro:app 파일은 읽을 수 있지만 새 저장과 녹화 recipe는 canonical metadata만 쓴다. 검증: 생성 계약 check, 문서·계약·커리큘럼·자동화 회귀 66건, 서버 API 58건, 학습 아카이브 14건, TypeScript check, mainPlan 정책 6건을 통과했다. 최종 preflight는 root-clean, docs, backend 3/3 게이트를 1323343ms에 통과했고 git diff --check도 통과했다.
1 parent 31a472b commit d7fcddf

32 files changed

Lines changed: 1209 additions & 95 deletions

File tree

contracts/appSpec.schema.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://codaro.dev/contracts/appSpec.schema.json",
4+
"title": "Codaro AppSpec",
5+
"type": "object",
6+
"additionalProperties": false,
7+
"required": [
8+
"schemaVersion",
9+
"title",
10+
"layout",
11+
"hideCode",
12+
"entryBlockIds",
13+
"statePolicy"
14+
],
15+
"properties": {
16+
"schemaVersion": { "const": 1 },
17+
"title": { "type": "string", "minLength": 1, "maxLength": 200 },
18+
"layout": {
19+
"type": "string",
20+
"enum": ["notebook", "learning", "stack", "grid"]
21+
},
22+
"hideCode": { "type": "boolean" },
23+
"entryBlockIds": {
24+
"type": "array",
25+
"uniqueItems": true,
26+
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
27+
},
28+
"statePolicy": {
29+
"type": "string",
30+
"enum": ["none", "perSession", "shared"]
31+
}
32+
}
33+
}

contracts/artifactOwners.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,24 @@ artifacts:
99
- src/codaro/generatedContracts/artifactOwnership.schema.json
1010
- editor/src/lib/generatedContracts/artifactOwnership.ts
1111
- launcher/codaro-launcher/src/generated_contracts/artifact_ownership.rs
12+
- artifactId: app-spec
13+
role: source
14+
owner: product-architecture
15+
sourcePath: contracts/appSpec.schema.json
16+
surfacePaths:
17+
- src/codaro/generatedContracts/appSpec.py
18+
- src/codaro/generatedContracts/appSpec.schema.json
19+
- editor/src/lib/generatedContracts/appSpec.ts
20+
- src/codaro/document/models.py
21+
- src/codaro/document/percentFormat.py
22+
- artifactId: executable-unit
23+
role: source
24+
owner: product-architecture
25+
sourcePath: contracts/executableUnit.schema.json
26+
surfacePaths:
27+
- src/codaro/generatedContracts/executableUnit.py
28+
- src/codaro/generatedContracts/executableUnit.schema.json
29+
- editor/src/lib/generatedContracts/executableUnit.ts
1230
- artifactId: learning-artifact-descriptor
1331
role: source
1432
owner: learning-runtime
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://codaro.dev/contracts/executableUnit.schema.json",
4+
"title": "Codaro ExecutableUnitSpec",
5+
"type": "object",
6+
"additionalProperties": false,
7+
"required": [
8+
"schemaVersion",
9+
"unitId",
10+
"entryBlockId",
11+
"dependencyBlockIds",
12+
"inputSchema",
13+
"outputSchema",
14+
"effects",
15+
"statePolicy",
16+
"runtimeTarget",
17+
"sourceSpan",
18+
"sourceHash",
19+
"dependencyHash",
20+
"assetHashes",
21+
"checkScenarioIds",
22+
"evidenceReceiptIds",
23+
"diagnostics"
24+
],
25+
"properties": {
26+
"schemaVersion": { "const": 1 },
27+
"unitId": { "type": "string", "minLength": 1, "maxLength": 200 },
28+
"entryBlockId": { "type": "string", "minLength": 1, "maxLength": 200 },
29+
"dependencyBlockIds": {
30+
"type": "array",
31+
"uniqueItems": true,
32+
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
33+
},
34+
"inputSchema": { "type": "object" },
35+
"outputSchema": { "type": "object" },
36+
"effects": { "$ref": "#/$defs/EffectSpec" },
37+
"statePolicy": { "$ref": "#/$defs/StatePolicy" },
38+
"runtimeTarget": { "$ref": "#/$defs/RuntimeTarget" },
39+
"sourceSpan": { "$ref": "#/$defs/SourceSpan" },
40+
"sourceHash": { "$ref": "#/$defs/ContentHash" },
41+
"dependencyHash": { "$ref": "#/$defs/ContentHash" },
42+
"assetHashes": {
43+
"type": "object",
44+
"additionalProperties": { "$ref": "#/$defs/ContentHash" }
45+
},
46+
"checkScenarioIds": {
47+
"type": "array",
48+
"uniqueItems": true,
49+
"items": { "type": "string", "minLength": 1 }
50+
},
51+
"evidenceReceiptIds": {
52+
"type": "array",
53+
"uniqueItems": true,
54+
"items": { "type": "string", "minLength": 1 }
55+
},
56+
"diagnostics": {
57+
"type": "array",
58+
"items": { "$ref": "#/$defs/CapabilityDiagnostic" }
59+
}
60+
},
61+
"$defs": {
62+
"ContentHash": {
63+
"type": "string",
64+
"pattern": "^sha256-[0-9a-f]{64}$"
65+
},
66+
"StatePolicy": {
67+
"type": "string",
68+
"enum": ["none", "perSession", "shared"]
69+
},
70+
"RuntimeTarget": {
71+
"type": "string",
72+
"enum": ["browser", "server", "local", "blocked"]
73+
},
74+
"SourceSpan": {
75+
"type": "object",
76+
"additionalProperties": false,
77+
"required": ["path", "startLine", "endLine"],
78+
"properties": {
79+
"path": { "type": "string", "minLength": 1 },
80+
"startLine": { "type": "integer", "minimum": 1 },
81+
"endLine": { "type": "integer", "minimum": 1 }
82+
}
83+
},
84+
"EffectSpec": {
85+
"type": "object",
86+
"additionalProperties": false,
87+
"required": [
88+
"filesystemRead",
89+
"filesystemWrite",
90+
"networkOrigins",
91+
"process",
92+
"gui",
93+
"secretRefs"
94+
],
95+
"properties": {
96+
"filesystemRead": {
97+
"type": "array",
98+
"uniqueItems": true,
99+
"items": { "type": "string", "minLength": 1 }
100+
},
101+
"filesystemWrite": {
102+
"type": "array",
103+
"uniqueItems": true,
104+
"items": { "type": "string", "minLength": 1 }
105+
},
106+
"networkOrigins": {
107+
"type": "array",
108+
"uniqueItems": true,
109+
"items": { "type": "string", "minLength": 1 }
110+
},
111+
"process": { "type": "boolean" },
112+
"gui": { "type": "boolean" },
113+
"secretRefs": {
114+
"type": "array",
115+
"uniqueItems": true,
116+
"items": { "type": "string", "minLength": 1 }
117+
}
118+
}
119+
},
120+
"CapabilityDiagnostic": {
121+
"type": "object",
122+
"additionalProperties": false,
123+
"required": ["code", "message", "severity", "sourceSpan"],
124+
"properties": {
125+
"code": { "type": "string", "minLength": 1 },
126+
"message": { "type": "string", "minLength": 1 },
127+
"severity": { "type": "string", "enum": ["info", "warning", "blocked"] },
128+
"sourceSpan": { "$ref": "#/$defs/SourceSpan" }
129+
}
130+
}
131+
}
132+
}

docs/skills/architecture/ssot-map.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ Codaro에서 기준 파일은 아래 순서로 본다. 같은 의미의 규칙
4949
| 프론트 셀 스키마 | `editor/src/lib/cellSchema.ts` | `blockTypes`, `cellRoles`, `executionKinds`, `cellDisplayKinds` |
5050
| 백엔드 셀 스키마 | `src/codaro/document/cellSchema.py` | 같은 셀 어휘의 Python 기준 |
5151
| 문서 모델 | `src/codaro/document/models.py` | 실제 document/block 저장 모델 |
52+
| app and executable unit contracts | `contracts/appSpec.schema.json`, `contracts/executableUnit.schema.json`, `docs/skills/ops/tools/genProductContracts.py` | app projection과 기능 블록의 versioned Python, TypeScript wire type 기준 |
53+
| Percent app metadata | `src/codaro/document/percentFormat.py` | `codaro-app` TOML parse, canonical write, legacy header migration과 entry fail-closed 기준 |
5254
| 문서 블록 조작 | `src/codaro/document/blockOperations.py` | 블록 삽입/삭제/이동/수정과 실행 대상 코드 블록 검증 기준 |
5355
| 노트북 생성 | `src/codaro/document/notebookGeneration.py` | tool이 생성하거나 분리한 노트북 document와 저장 payload를 조립하는 document 경계 |
5456
| 프론트 문서 조작 | `editor/src/lib/documentModel.ts` | draft 생성, block 병합, payload 정규화 |

docs/skills/identity/percent-format.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,33 @@ whenToUse: 문서 파서/writer, ipynb 변환, 외부 에디터 호환성 다룰
1818
- VS Code, Spyder, Jupytext가 동일한 `# %%` 포맷을 인식한다.
1919
- ipynb 호환 import/export는 유지한다.
2020

21+
## AppSpec 메타데이터
22+
23+
앱 projection은 실행 코드가 아니라 주석 TOML인 `codaro-app` 블록에 저장한다. 이 블록은 title, layout, code visibility, entry block, state policy를 모두 보존하면서 `python file.py` 실행을 방해하지 않는다.
24+
25+
```python
26+
# /// codaro-app
27+
# schemaVersion = 1
28+
# title = "CSV 검증 보고서"
29+
# layout = "grid"
30+
# hideCode = true
31+
# entryBlockIds = ["report-view"]
32+
# statePolicy = "perSession"
33+
# ///
34+
35+
# %% [code] id=report-view
36+
print("ready")
37+
```
38+
39+
- `schemaVersion`은 현재 1만 허용하며 모르는 버전은 파일을 덮어쓰기 전에 거부한다.
40+
- `layout``notebook`, `learning`, `stack`, `grid` 중 하나다.
41+
- `statePolicy``none`, `perSession`, `shared` 중 하나다.
42+
- `entryBlockIds`는 실제 문서 block을 한 번씩만 참조해야 한다. 삭제되거나 중복된 entry는 조용히 제거하지 않고 load 또는 save를 차단한다.
43+
- 기존 `# codaro:app title='...'` header는 한 schema epoch 동안 읽는다. 다음 저장은 canonical `codaro-app` 블록 하나로 migration한다.
44+
- PEP 723 `# /// script`는 Python 의존성, `# /// codaro-app`은 Codaro 앱 projection을 각각 소유하며 서로 섞지 않는다.
45+
46+
공유 wire 계약의 기준은 `contracts/appSpec.schema.json`이다. 기능 블록 compiler가 소비할 실행 단위 계약은 `contracts/executableUnit.schema.json`이며 생성된 Python과 TypeScript type은 직접 수정하지 않는다.
47+
2148
## 관련
2249

2350
- [[document-model]] - 블록 중심 내부 모델

0 commit comments

Comments
 (0)