@shuji-bonji/pdf-constraints 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,253 @@
1
+ {
2
+ "$schema": "./schema.json",
3
+ "name": "document-metadata",
4
+ "version": "1",
5
+ "description": "第 2 ドメイン: 文書メタデータ(ISO 32000-2 §14.3 + §7.9.4)。語彙収束の計測が目的。フォントと違い appliesTo が document スコープで、条文の主語が processor(書き込み行為)のものを含む — ファイル状態から観測できるのは『違反の痕跡』まで(subjectNote 参照)。",
6
+ "sourceSpec": {
7
+ "spec": "pdf20",
8
+ "retrievedWith": "pdf-spec-mcp get_requirements / get_tables",
9
+ "sections": [
10
+ "14.3.2",
11
+ "14.3.3",
12
+ "14.3.4",
13
+ "7.9.4"
14
+ ],
15
+ "specVersionAtMapping": "0.4.5"
16
+ },
17
+ "issue": "https://github.com/shuji-bonji/pdf-spec-mcp/issues/12",
18
+ "factVocabulary": {
19
+ "doc.xmp.exists": "catalog /Metadata がストリームとして存在するか",
20
+ "doc.xmp.dict.Type": "メタデータストリーム辞書の /Type(name)",
21
+ "doc.xmp.dict.Subtype": "同 /Subtype(name)",
22
+ "doc.xmp.hasXmpEnvelope": "復号後テキストが xpacket + x:xmpmeta の外形を持つか(ISO 16684-1 の完全文法検査ではない)",
23
+ "doc.xmp.CreateDate": "xmp:CreateDate の文字列(ISO 8601)| absent",
24
+ "doc.xmp.ModifyDate": "xmp:ModifyDate の文字列(ISO 8601)| absent",
25
+ "doc.info.CreationDate": "Info /CreationDate の生文字列 | absent",
26
+ "doc.info.ModDate": "Info /ModDate の生文字列 | absent",
27
+ "doc.info.TrappedKind": "Info /Trapped の種別: name:True / name:False / name:Unknown / boolean / other / absent"
28
+ },
29
+ "newPredicates": [
30
+ "dateEquiv(PDF 日付文字列 ↔ ISO 8601 を同一時点として比較。§7.9.4 の既定値規則で正規化)"
31
+ ],
32
+ "constraints": [
33
+ {
34
+ "id": "CT-META-1",
35
+ "title": "メタデータストリーム辞書は /Type /Metadata・/Subtype /XML を持つこと",
36
+ "clauses": [
37
+ "R-14.3.2-6",
38
+ "R-14.3.2-7"
39
+ ],
40
+ "source": {
41
+ "spec": "pdf20",
42
+ "section": "14.3.2",
43
+ "table": "Table 347"
44
+ },
45
+ "level": "shall",
46
+ "appliesTo": "document",
47
+ "when": [
48
+ {
49
+ "fact": "doc.xmp.exists",
50
+ "op": "eq",
51
+ "value": true
52
+ }
53
+ ],
54
+ "assert": [
55
+ {
56
+ "fact": "doc.xmp.dict.Type",
57
+ "op": "eq",
58
+ "value": "Metadata",
59
+ "onFail": "メタデータストリームの /Type が Metadata でない"
60
+ },
61
+ {
62
+ "fact": "doc.xmp.dict.Subtype",
63
+ "op": "eq",
64
+ "value": "XML",
65
+ "onFail": "メタデータストリームの /Subtype が XML でない"
66
+ }
67
+ ]
68
+ },
69
+ {
70
+ "id": "CT-META-2",
71
+ "title": "メタデータストリームの中身は XMP(XML)であること",
72
+ "clauses": [
73
+ "R-14.3.2-2"
74
+ ],
75
+ "source": {
76
+ "spec": "pdf20",
77
+ "section": "14.3.2"
78
+ },
79
+ "level": "shall",
80
+ "appliesTo": "document",
81
+ "when": [
82
+ {
83
+ "fact": "doc.xmp.exists",
84
+ "op": "eq",
85
+ "value": true
86
+ }
87
+ ],
88
+ "assert": [
89
+ {
90
+ "fact": "doc.xmp.hasXmpEnvelope",
91
+ "op": "eq",
92
+ "value": true,
93
+ "onFail": "メタデータストリームが XMP パケットの外形を持たない"
94
+ }
95
+ ],
96
+ "notMapped": "条文は『文法は ISO 16684-1 に従う shall』まで要求するが、ISO 16684-1 は corpus 外(T2 と同型の境界)。この写像は xpacket/x:xmpmeta の外形検査で近似している"
97
+ },
98
+ {
99
+ "id": "CT-META-3",
100
+ "title": "Info の日付値は §7.9.4 の日付文字列文法に従うこと",
101
+ "clauses": [
102
+ "R-7.9.4-2",
103
+ "R-7.9.4-12",
104
+ "R-7.9.4-14",
105
+ "R-7.9.4-15"
106
+ ],
107
+ "source": {
108
+ "spec": "pdf20",
109
+ "section": "7.9.4"
110
+ },
111
+ "level": "shall",
112
+ "appliesTo": "document",
113
+ "when": [],
114
+ "assert": [
115
+ {
116
+ "fact": "doc.info.CreationDate",
117
+ "op": "matches",
118
+ "value": "^D:\\d{4}(\\d{2}(\\d{2}(\\d{2}(\\d{2}(\\d{2}([Z+\\-](\\d{2}('(\\d{2})?'?)?)?)?)?)?)?)?)?$",
119
+ "onFail": "Info /CreationDate が日付文字列文法に合わない",
120
+ "onlyWhen": [
121
+ {
122
+ "fact": "doc.info.CreationDate",
123
+ "op": "exists",
124
+ "value": true
125
+ }
126
+ ]
127
+ },
128
+ {
129
+ "fact": "doc.info.ModDate",
130
+ "op": "matches",
131
+ "value": "^D:\\d{4}(\\d{2}(\\d{2}(\\d{2}(\\d{2}(\\d{2}([Z+\\-](\\d{2}('(\\d{2})?'?)?)?)?)?)?)?)?)?$",
132
+ "onFail": "Info /ModDate が日付文字列文法に合わない",
133
+ "onlyWhen": [
134
+ {
135
+ "fact": "doc.info.ModDate",
136
+ "op": "exists",
137
+ "value": true
138
+ }
139
+ ]
140
+ }
141
+ ],
142
+ "notMapped": "フィールド値域(MM 01–12 等 = R-7.9.4-4〜-8)は正規表現では桁しか見ていない。dateEquiv 側の正規化で不正値は NaN に落ちるため実質は拾えるが、単独の値域述語としては未写像"
143
+ },
144
+ {
145
+ "id": "CT-META-4",
146
+ "title": "作成日時は Info と XMP の両方に書くなら完全等価であること",
147
+ "clauses": [
148
+ "R-14.3.4-2",
149
+ "R-14.3.4-4"
150
+ ],
151
+ "source": {
152
+ "spec": "pdf20",
153
+ "section": "14.3.4"
154
+ },
155
+ "level": "shall / may(条件付き)",
156
+ "appliesTo": "document",
157
+ "subjectNote": "条文の主語は PDF processor(書き込み行為)。ファイル状態から観測できるのは『どこかの writer が等価性を破った痕跡』であり、どの writer かは特定できない。R-14.3.4-3(既存の不整合は触らず残す should)により、不整合の存在自体が直近の writer の違反とは限らない",
158
+ "when": [
159
+ {
160
+ "fact": "doc.info.CreationDate",
161
+ "op": "exists",
162
+ "value": true
163
+ },
164
+ {
165
+ "fact": "doc.xmp.CreateDate",
166
+ "op": "exists",
167
+ "value": true
168
+ }
169
+ ],
170
+ "assert": [
171
+ {
172
+ "fact": "doc.info.CreationDate",
173
+ "op": "dateEquiv",
174
+ "value": "doc.xmp.CreateDate",
175
+ "onFail": "Info /CreationDate と xmp:CreateDate が等価でない(writer の R-14.3.4-2/-4 違反の痕跡)"
176
+ }
177
+ ]
178
+ },
179
+ {
180
+ "id": "CT-META-5",
181
+ "title": "更新日時は Info と XMP の両方に書くなら完全等価であること",
182
+ "clauses": [
183
+ "R-14.3.4-5"
184
+ ],
185
+ "source": {
186
+ "spec": "pdf20",
187
+ "section": "14.3.4"
188
+ },
189
+ "level": "shall",
190
+ "appliesTo": "document",
191
+ "subjectNote": "CT-META-4 と同じく主語は processor。ファイルからは痕跡のみ",
192
+ "when": [
193
+ {
194
+ "fact": "doc.info.ModDate",
195
+ "op": "exists",
196
+ "value": true
197
+ },
198
+ {
199
+ "fact": "doc.xmp.ModifyDate",
200
+ "op": "exists",
201
+ "value": true
202
+ }
203
+ ],
204
+ "assert": [
205
+ {
206
+ "fact": "doc.info.ModDate",
207
+ "op": "dateEquiv",
208
+ "value": "doc.xmp.ModifyDate",
209
+ "onFail": "Info /ModDate と xmp:ModifyDate が等価でない(writer の R-14.3.4-5 違反の痕跡)"
210
+ }
211
+ ]
212
+ },
213
+ {
214
+ "id": "CT-META-6",
215
+ "title": "Trapped は boolean でなく name(True/False/Unknown)であること",
216
+ "clauses": [
217
+ "R-14.3.3-5",
218
+ "R-14.3.3-6"
219
+ ],
220
+ "source": {
221
+ "spec": "pdf20",
222
+ "section": "14.3.3",
223
+ "table": "Table 349",
224
+ "key": "Trapped"
225
+ },
226
+ "level": "shall",
227
+ "appliesTo": "document",
228
+ "when": [
229
+ {
230
+ "fact": "doc.info.TrappedKind",
231
+ "op": "exists",
232
+ "value": true
233
+ }
234
+ ],
235
+ "assert": [
236
+ {
237
+ "fact": "doc.info.TrappedKind",
238
+ "op": "in",
239
+ "value": [
240
+ "name:True",
241
+ "name:False",
242
+ "name:Unknown"
243
+ ],
244
+ "onFail": "Trapped が name True/False/Unknown でない(boolean は R-14.3.3-5/-6 違反)"
245
+ }
246
+ ],
247
+ "notMapped": "Table 349 で Trapped は PDF 2.0 deprecated。『deprecated を新規に書くべきでない』は要件レベルの写像対象外(should 相当の運用判断)"
248
+ }
249
+ ],
250
+ "scopeFindings": [
251
+ "Info /Title ↔ dc:title の等価は R-14.3.4 の shall の射程外(shall は time and date のみ)。B-9 の同期は良い実装だが条文義務ではない — 写像時に射程を条文で確認しないと過剰制約になる(フォント PoC の M-1 の再演)"
252
+ ]
253
+ }
@@ -0,0 +1,276 @@
1
+ {
2
+ "$schema": "./schema.json",
3
+ "name": "font-embedding",
4
+ "version": "1",
5
+ "description": "条文 → 機械検査可能条件の写像 PoC。対象は writer B-14(W-2/W-3/W-4)で正解が既知のフォント埋め込み条文。判定の実行は pdf-verify の役割であり、このテーブルは『条文を満たすとは PDF 構造上どういう状態か』の宣言だけを持つ。",
6
+ "sourceSpec": {
7
+ "spec": "pdf20",
8
+ "retrievedWith": "pdf-spec-mcp get_requirements / get_tables",
9
+ "sections": [
10
+ "9.9.1",
11
+ "9.9.2",
12
+ "9.7.4.2"
13
+ ],
14
+ "specVersionAtMapping": "0.4.5"
15
+ },
16
+ "issue": "https://github.com/shuji-bonji/pdf-spec-mcp/issues/12",
17
+ "factVocabulary": {
18
+ "descriptor.fontFileKey": "FontDescriptor が持つ埋め込みキー(FontFile / FontFile2 / FontFile3 / none)",
19
+ "stream.dict.Subtype": "フォントストリーム辞書の /Subtype(name)",
20
+ "stream.dict.Length1": "フォントストリーム辞書の /Length1(integer | absent)",
21
+ "stream.decodedLength": "フィルタ復号後のフォントプログラムのバイト長",
22
+ "program.container": "復号後バイト列の種別: truetype(0x00010000|'true') / otto('OTTO') / bareCFF(0x01 0x00) / ttc('ttcf') / unknown",
23
+ "program.sfntTables": "sfnt テーブルディレクトリの tag 一覧(container が sfnt 系のとき)",
24
+ "program.isCffBased": "container == otto || bareCFF、または sfnt に 'CFF ' テーブルを含む",
25
+ "font.subtype": "参照元フォント辞書の /Subtype(Type1 / TrueType / Type0 / CIDFontType0 / CIDFontType2)",
26
+ "font.baseFont": "フォント辞書の /BaseFont(name, 先頭 '/' なし)",
27
+ "descriptor.fontName": "FontDescriptor の /FontName(name, 先頭 '/' なし)",
28
+ "given.isSubset": "【外部事実】このフォントがサブセットか。ファイル単体からは決定不能(PoC 発見事項 F-1)。producer 文脈またはサイドカーで供給する"
29
+ },
30
+ "constraints": [
31
+ {
32
+ "id": "CT-FONT-1",
33
+ "title": "FontFile2 の中身は TrueType フォントプログラムであること",
34
+ "clauses": [
35
+ "R-9.9.1-33",
36
+ "R-9.9.1-34"
37
+ ],
38
+ "source": {
39
+ "spec": "pdf20",
40
+ "section": "9.9.1",
41
+ "table": "Table 124",
42
+ "key": "FontFile2"
43
+ },
44
+ "level": "shall",
45
+ "appliesTo": "embedded-font",
46
+ "when": [
47
+ {
48
+ "fact": "descriptor.fontFileKey",
49
+ "op": "eq",
50
+ "value": "FontFile2"
51
+ }
52
+ ],
53
+ "assert": [
54
+ {
55
+ "fact": "program.container",
56
+ "op": "in",
57
+ "value": [
58
+ "truetype"
59
+ ],
60
+ "onFail": "FontFile2 に TrueType 以外のコンテナ(OTTO=CFF 等)が入っている(W-2 の実体)"
61
+ },
62
+ {
63
+ "fact": "program.sfntTables",
64
+ "op": "superset",
65
+ "value": [
66
+ "glyf",
67
+ "head",
68
+ "hhea",
69
+ "hmtx",
70
+ "loca",
71
+ "maxp"
72
+ ],
73
+ "onFail": "R-9.9.1-34 の必須 6 テーブルが欠けている"
74
+ }
75
+ ],
76
+ "notMapped": "R-9.9.1-35(cvt/fpgm/prep は『フォント命令が要求するなら』必須)は『要求するか』の判定に TrueType 命令の解釈が必要で、この語彙では書けない(人手判断 M-2)"
77
+ },
78
+ {
79
+ "id": "CT-FONT-2",
80
+ "title": "CIDFont の CFF 系プログラムは FontFile3(CIDFontType0C | OpenType)で埋め込むこと",
81
+ "clauses": [
82
+ "R-9.7.4.2-3"
83
+ ],
84
+ "source": {
85
+ "spec": "pdf20",
86
+ "section": "9.7.4.2"
87
+ },
88
+ "level": "shall",
89
+ "appliesTo": "embedded-font",
90
+ "when": [
91
+ {
92
+ "fact": "font.subtype",
93
+ "op": "in",
94
+ "value": [
95
+ "CIDFontType0",
96
+ "CIDFontType2"
97
+ ]
98
+ },
99
+ {
100
+ "fact": "program.isCffBased",
101
+ "op": "eq",
102
+ "value": true
103
+ }
104
+ ],
105
+ "assert": [
106
+ {
107
+ "fact": "descriptor.fontFileKey",
108
+ "op": "eq",
109
+ "value": "FontFile3",
110
+ "onFail": "CFF 系プログラムが FontFile3 以外のキーで埋め込まれている"
111
+ },
112
+ {
113
+ "fact": "stream.dict.Subtype",
114
+ "op": "in",
115
+ "value": [
116
+ "CIDFontType0C",
117
+ "OpenType"
118
+ ],
119
+ "onFail": "FontFile3 の Subtype が CIDFontType0C / OpenType のどちらでもない"
120
+ }
121
+ ]
122
+ },
123
+ {
124
+ "id": "CT-FONT-3",
125
+ "title": "サブセットフォントの名前は 6 大文字タグ + '+' で始まり、同一フォントの別サブセットは別タグであること",
126
+ "clauses": [
127
+ "R-9.9.2-2",
128
+ "R-9.9.2-3"
129
+ ],
130
+ "source": {
131
+ "spec": "pdf20",
132
+ "section": "9.9.2"
133
+ },
134
+ "level": "shall",
135
+ "appliesTo": "embedded-font",
136
+ "when": [
137
+ {
138
+ "fact": "given.isSubset",
139
+ "op": "eq",
140
+ "value": true
141
+ }
142
+ ],
143
+ "assert": [
144
+ {
145
+ "fact": "font.baseFont",
146
+ "op": "matches",
147
+ "value": "^[A-Z]{6}\\+.+",
148
+ "onFail": "BaseFont にサブセットタグが無い(W-3 の実体)"
149
+ },
150
+ {
151
+ "fact": "descriptor.fontName",
152
+ "op": "matches",
153
+ "value": "^[A-Z]{6}\\+.+",
154
+ "onFail": "FontDescriptor の FontName にサブセットタグが無い"
155
+ }
156
+ ],
157
+ "documentAssert": [
158
+ {
159
+ "fact": "doc.subsetTagsPerBaseName",
160
+ "op": "allDistinct",
161
+ "value": null,
162
+ "onFail": "同一フォントの別サブセットが同じタグを共有している(R-9.9.2-3 後段)"
163
+ }
164
+ ],
165
+ "notMapped": "applicability(サブセットか否か)はファイル内に無い事実で、条文が暗黙に producer 知識を前提にしている(PoC 発見事項 F-1)。R-9.9.2-4(.notdef の定義)は CFF charset / glyf の中身の解釈が必要(M-2 相当・今回は未写像)"
166
+ },
167
+ {
168
+ "id": "CT-FONT-4",
169
+ "title": "Type1 / TrueType プログラムのストリーム辞書には Length1 があり、復号後長と一致すること",
170
+ "clauses": [
171
+ "Table 125 Length1 (Required for Type 1 and TrueType font programs)"
172
+ ],
173
+ "source": {
174
+ "spec": "pdf20",
175
+ "section": "9.9.1",
176
+ "table": "Table 125",
177
+ "key": "Length1"
178
+ },
179
+ "level": "required",
180
+ "appliesTo": "embedded-font",
181
+ "when": [
182
+ {
183
+ "fact": "descriptor.fontFileKey",
184
+ "op": "in",
185
+ "value": [
186
+ "FontFile",
187
+ "FontFile2"
188
+ ]
189
+ }
190
+ ],
191
+ "assert": [
192
+ {
193
+ "fact": "stream.dict.Length1",
194
+ "op": "exists",
195
+ "value": true,
196
+ "onFail": "Length1 が無い(W-4 の実体)"
197
+ },
198
+ {
199
+ "fact": "stream.dict.Length1",
200
+ "op": "eqFact",
201
+ "value": "stream.decodedLength",
202
+ "onFail": "Length1 が復号後のプログラム長と一致しない",
203
+ "note": "TrueType では『the entire TrueType font program』。Type 1 は clear-text 部分長なのでこの等式は TrueType(FontFile2)のみ。FontFile(Type1)に適用するなら別述語が要る(M-3)",
204
+ "onlyWhen": [
205
+ {
206
+ "fact": "descriptor.fontFileKey",
207
+ "op": "eq",
208
+ "value": "FontFile2"
209
+ }
210
+ ]
211
+ }
212
+ ]
213
+ },
214
+ {
215
+ "id": "CT-FONT-5",
216
+ "title": "CFF 表現(FontFile3)では Length1/2/3 を置かないこと・FontFile3/OpenType の CFF 系は cmap を含むこと",
217
+ "clauses": [
218
+ "R-9.9.1-12",
219
+ "R-9.9.1-42",
220
+ "R-9.9.1-47"
221
+ ],
222
+ "source": {
223
+ "spec": "pdf20",
224
+ "section": "9.9.1",
225
+ "table": "Table 124 / Table 125"
226
+ },
227
+ "level": "shall / shall not",
228
+ "appliesTo": "embedded-font",
229
+ "when": [
230
+ {
231
+ "fact": "descriptor.fontFileKey",
232
+ "op": "eq",
233
+ "value": "FontFile3"
234
+ }
235
+ ],
236
+ "assert": [
237
+ {
238
+ "fact": "stream.dict.Length1",
239
+ "op": "exists",
240
+ "value": false,
241
+ "onFail": "CFF 表現なのに Length1 がある(R-9.9.1-12 shall not)"
242
+ },
243
+ {
244
+ "fact": "stream.dict.Subtype",
245
+ "op": "in",
246
+ "value": [
247
+ "Type1C",
248
+ "CIDFontType0C",
249
+ "OpenType"
250
+ ],
251
+ "onFail": "FontFile3 の Subtype が Table 125 の許容値でない(R-9.9.1-47)"
252
+ },
253
+ {
254
+ "fact": "program.sfntTables",
255
+ "op": "superset",
256
+ "value": [
257
+ "cmap"
258
+ ],
259
+ "onFail": "OpenType(CFF) なのに cmap が無い(R-9.9.1-42)",
260
+ "onlyWhen": [
261
+ {
262
+ "fact": "stream.dict.Subtype",
263
+ "op": "eq",
264
+ "value": "OpenType"
265
+ },
266
+ {
267
+ "fact": "program.isCffBased",
268
+ "op": "eq",
269
+ "value": true
270
+ }
271
+ ]
272
+ }
273
+ ]
274
+ }
275
+ ]
276
+ }
@@ -0,0 +1,158 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://github.com/shuji-bonji/pdf-constraints/tables/schema.json",
4
+ "title": "PDF constraint table",
5
+ "description": "条文(ISO 32000)→ 機械検査可能条件の写像。テーブルは判定の素であって条文原文でも verdict でもない(specs/18 §1)。",
6
+ "type": "object",
7
+ "required": ["name", "version", "description", "sourceSpec", "factVocabulary", "constraints"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "$schema": { "type": "string" },
11
+ "name": {
12
+ "type": "string",
13
+ "pattern": "^[a-z][a-z0-9-]*$",
14
+ "description": "ドメイン名 = テーブル名。ファイル名と一致させる"
15
+ },
16
+ "version": { "type": "string", "description": "スキーマ世代(現在 \"1\")" },
17
+ "description": { "type": "string", "minLength": 1 },
18
+ "issue": { "type": "string", "format": "uri" },
19
+ "sourceSpec": {
20
+ "type": "object",
21
+ "required": ["spec", "sections"],
22
+ "additionalProperties": false,
23
+ "description": "写像の出所。pdf-spec の版が上がったときに再照合できるようにする",
24
+ "properties": {
25
+ "spec": { "type": "string", "description": "pdf-spec-mcp の spec ID(例: pdf20)" },
26
+ "retrievedWith": { "type": "string" },
27
+ "sections": {
28
+ "type": "array",
29
+ "minItems": 1,
30
+ "items": { "type": "string" }
31
+ },
32
+ "specVersionAtMapping": {
33
+ "type": "string",
34
+ "description": "写像した時点の pdf-spec-mcp の版"
35
+ }
36
+ }
37
+ },
38
+ "factVocabulary": {
39
+ "type": "object",
40
+ "minProperties": 1,
41
+ "description": "fact 名 → 意味。given.* は外部事実(ファイル単体から決定不能)",
42
+ "additionalProperties": { "type": "string" }
43
+ },
44
+ "newPredicates": {
45
+ "type": "array",
46
+ "items": { "type": "string" },
47
+ "description": "このテーブルのために追加した述語の記録(語彙の伸びを測るため)"
48
+ },
49
+ "scopeFindings": {
50
+ "type": "array",
51
+ "items": { "type": "string" },
52
+ "description": "写像時に確認した射程の記録(過剰制約を防いだ判断など)"
53
+ },
54
+ "constraints": {
55
+ "type": "array",
56
+ "minItems": 1,
57
+ "items": { "$ref": "#/definitions/constraint" }
58
+ }
59
+ },
60
+ "definitions": {
61
+ "constraint": {
62
+ "type": "object",
63
+ "required": ["id", "title", "clauses", "source", "level", "appliesTo", "when", "assert"],
64
+ "additionalProperties": false,
65
+ "properties": {
66
+ "id": {
67
+ "type": "string",
68
+ "pattern": "^CT-[A-Z0-9]+-[0-9]+$",
69
+ "description": "一度公開した ID の意味は変えない(変えるなら新 ID)"
70
+ },
71
+ "title": { "type": "string", "minLength": 1 },
72
+ "clauses": {
73
+ "type": "array",
74
+ "minItems": 1,
75
+ "items": { "type": "string" },
76
+ "description": "根拠条文の ID。原文は複製せず pdf-spec で引く"
77
+ },
78
+ "source": {
79
+ "type": "object",
80
+ "required": ["spec", "section"],
81
+ "properties": {
82
+ "spec": { "type": "string" },
83
+ "section": { "type": "string" },
84
+ "table": { "type": "string" },
85
+ "key": { "type": "string" }
86
+ }
87
+ },
88
+ "level": { "type": "string", "description": "shall / should / required など条文の要求水準" },
89
+ "appliesTo": {
90
+ "type": "string",
91
+ "enum": ["embedded-font", "document"],
92
+ "description": "評価スコープ。将来 annotation / page を追加する"
93
+ },
94
+ "subjectNote": {
95
+ "type": "string",
96
+ "description": "条文の主語が processor(書き込み行為)のとき、ファイルから観測できるのは『違反の痕跡』までであることの記録(specs/18 §1 / F-5)"
97
+ },
98
+ "notMapped": {
99
+ "type": "string",
100
+ "description": "語彙で写像できなかった条文と、その理由。沈黙して存在しないふりをしない"
101
+ },
102
+ "when": {
103
+ "type": "array",
104
+ "items": { "$ref": "#/definitions/predicate" },
105
+ "description": "適用条件。given.* が未供給なら needs_external_fact に縮退する"
106
+ },
107
+ "assert": {
108
+ "type": "array",
109
+ "minItems": 1,
110
+ "items": { "$ref": "#/definitions/assertion" }
111
+ },
112
+ "documentAssert": {
113
+ "type": "array",
114
+ "items": { "$ref": "#/definitions/assertion" },
115
+ "description": "文書横断の検査(同一フォントのタグ重複など)"
116
+ }
117
+ }
118
+ },
119
+ "predicate": {
120
+ "type": "object",
121
+ "required": ["fact", "op"],
122
+ "additionalProperties": false,
123
+ "properties": {
124
+ "fact": { "type": "string" },
125
+ "op": {
126
+ "type": "string",
127
+ "enum": ["eq", "in", "exists", "matches", "superset", "eqFact", "allDistinct", "dateEquiv"],
128
+ "description": "v1 の凍結セット。追加は minor バンプ(評価器と同梱なので版で結束する)"
129
+ },
130
+ "value": {}
131
+ }
132
+ },
133
+ "assertion": {
134
+ "type": "object",
135
+ "required": ["fact", "op", "onFail"],
136
+ "additionalProperties": false,
137
+ "properties": {
138
+ "fact": { "type": "string" },
139
+ "op": {
140
+ "type": "string",
141
+ "enum": ["eq", "in", "exists", "matches", "superset", "eqFact", "allDistinct", "dateEquiv"]
142
+ },
143
+ "value": {},
144
+ "onFail": {
145
+ "type": "string",
146
+ "minLength": 1,
147
+ "description": "違反時の説明。subjectNote を持つ制約では『違反の痕跡』と述べる"
148
+ },
149
+ "note": { "type": "string" },
150
+ "onlyWhen": {
151
+ "type": "array",
152
+ "items": { "$ref": "#/definitions/predicate" },
153
+ "description": "この assert だけに掛かる追加条件(満たさなければ検査自体を飛ばす)"
154
+ }
155
+ }
156
+ }
157
+ }
158
+ }