kibi-core 0.8.1 → 0.9.1
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.
- package/package.json +1 -1
- package/schema/entities.pl +17 -1
- package/schema/validation.pl +2 -0
- package/src/checks.pl +144 -34
- package/src/discovery.pl +88 -18
- package/src/kb.pl +256 -19
- package/src/requirement_proof.pl +837 -0
package/src/kb.pl
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
with_kb_mutex/1,
|
|
8
8
|
kb_assert_entity/2,
|
|
9
9
|
kb_assert_entity_no_audit/2,
|
|
10
|
+
kb_commit_upsert/5,
|
|
10
11
|
kb_log_entity_upsert/3,
|
|
11
12
|
kb_retract_entity/1,
|
|
12
13
|
kb_retract_entity/3,
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
predicate_schema/6,
|
|
44
45
|
predicate_fact/5,
|
|
45
46
|
contradicting_reqs/3,
|
|
47
|
+
req_conflict_witness/3,
|
|
46
48
|
check_req_contradiction/1,
|
|
47
49
|
normalize_term_atom/2,
|
|
48
50
|
normalize_term_atom_list/2,
|
|
@@ -111,7 +113,10 @@ kb_attach(Directory) :-
|
|
|
111
113
|
atom_concat(Directory, '/audit.log', AuditLog),
|
|
112
114
|
( db_attached(AuditLog)
|
|
113
115
|
-> true % Already attached
|
|
114
|
-
;
|
|
116
|
+
; % Close the journal stream after each write. The default `flush`
|
|
117
|
+
% mode retains an exclusive write lock for the lifetime of a
|
|
118
|
+
% long-running MCP process and blocks writers in other runtimes.
|
|
119
|
+
db_attach(AuditLog, [sync(close)])
|
|
115
120
|
),
|
|
116
121
|
% Track attachment state
|
|
117
122
|
assert(kb_attached(Directory)),
|
|
@@ -171,12 +176,18 @@ kb_save_locked(Directory) :-
|
|
|
171
176
|
catch(
|
|
172
177
|
(
|
|
173
178
|
ensure_snapshot_current(DataFile),
|
|
179
|
+
kb_stage(snapshot_save),
|
|
174
180
|
save_rdf_snapshot(TempFile),
|
|
181
|
+
kb_stage(audit_sync),
|
|
182
|
+
sync_audit_log,
|
|
183
|
+
% Keep the durable RDF rename after audit synchronization. The
|
|
184
|
+
% temporary snapshot can be discarded if an audit-stage failure
|
|
185
|
+
% occurs, so a failed commit cannot publish new RDF state.
|
|
186
|
+
kb_stage(snapshot_save),
|
|
175
187
|
rename_file(TempFile, DataFile),
|
|
176
188
|
current_data_stamp(DataFile, UpdatedStamp),
|
|
177
189
|
retractall(kb_attached_snapshot(_)),
|
|
178
|
-
assert(kb_attached_snapshot(UpdatedStamp))
|
|
179
|
-
sync_audit_log
|
|
190
|
+
assert(kb_attached_snapshot(UpdatedStamp))
|
|
180
191
|
),
|
|
181
192
|
Error,
|
|
182
193
|
(
|
|
@@ -304,6 +315,109 @@ kb_assert_entity_no_audit(Type, Props) :-
|
|
|
304
315
|
)
|
|
305
316
|
)).
|
|
306
317
|
|
|
318
|
+
%% kb_commit_upsert(+Type, +Properties, +Relationships, +SkipContradiction, -ChangeKind)
|
|
319
|
+
% Commit an entity upsert, its relationships, audit entries, and RDF snapshot
|
|
320
|
+
% as one bounded operation. The branch lock is held before any RDF mutation,
|
|
321
|
+
% so concurrent runtimes cannot observe or publish an intermediate upsert.
|
|
322
|
+
% Relationships use rel(Type, FromId, ToId, Metadata) terms. Metadata is
|
|
323
|
+
% retained for the caller's serialization contract; the audit schema records
|
|
324
|
+
% only the relationship endpoints and type, as before.
|
|
325
|
+
kb_commit_upsert(Type, Props, Relationships, SkipContradiction, ChangeKind) :-
|
|
326
|
+
memberchk(id=Id, Props),
|
|
327
|
+
memberchk(SkipContradiction, [true, false]),
|
|
328
|
+
kb_attached(Directory),
|
|
329
|
+
atom_concat(Directory, '/kb.rdf', DataFile),
|
|
330
|
+
kb_stage(runtime),
|
|
331
|
+
kb_runtime_diagnostic,
|
|
332
|
+
% Emit the lock marker before waiting so a timeout identifies a branch
|
|
333
|
+
% lock held by another runtime instead of reporting only the prior stage.
|
|
334
|
+
kb_stage(lock),
|
|
335
|
+
with_kb_file_lock(Directory, (
|
|
336
|
+
audit_store_writable,
|
|
337
|
+
ensure_snapshot_current(DataFile),
|
|
338
|
+
upsert_change_kind(Id, ChangeKind),
|
|
339
|
+
rdf_transaction((
|
|
340
|
+
kb_stage(rdf_mutation),
|
|
341
|
+
kb_assert_entity_no_audit(Type, Props),
|
|
342
|
+
kb_commit_relationships_no_audit(Relationships),
|
|
343
|
+
kb_maybe_check_req_contradiction(Type, Id, SkipContradiction),
|
|
344
|
+
kb_stage(entity_audit),
|
|
345
|
+
kb_log_entity_upsert(ChangeKind, Type, Props),
|
|
346
|
+
kb_stage(relationship_audit),
|
|
347
|
+
kb_commit_relationship_audits(Relationships),
|
|
348
|
+
kb_save_locked(Directory)
|
|
349
|
+
))
|
|
350
|
+
)).
|
|
351
|
+
|
|
352
|
+
upsert_change_kind(Id, updated) :-
|
|
353
|
+
once(kb_entity(Id, _, _)),
|
|
354
|
+
!.
|
|
355
|
+
upsert_change_kind(_, created).
|
|
356
|
+
|
|
357
|
+
kb_commit_relationships_no_audit([]).
|
|
358
|
+
kb_commit_relationships_no_audit([
|
|
359
|
+
rel(RelType, FromId, ToId, Metadata)|Rest
|
|
360
|
+
]) :-
|
|
361
|
+
kb_assert_relationship_no_audit(RelType, FromId, ToId, Metadata),
|
|
362
|
+
kb_commit_relationships_no_audit(Rest).
|
|
363
|
+
|
|
364
|
+
kb_maybe_check_req_contradiction(req, Id, false) :-
|
|
365
|
+
!,
|
|
366
|
+
kb_stage(contradiction_check),
|
|
367
|
+
check_req_contradiction(Id).
|
|
368
|
+
kb_maybe_check_req_contradiction(_, _, _).
|
|
369
|
+
|
|
370
|
+
kb_commit_relationship_audits([]).
|
|
371
|
+
kb_commit_relationship_audits([
|
|
372
|
+
rel(RelType, FromId, ToId, _Metadata)|Rest
|
|
373
|
+
]) :-
|
|
374
|
+
kb_log_relationship_upsert(RelType, FromId, ToId, []),
|
|
375
|
+
kb_commit_relationship_audits(Rest).
|
|
376
|
+
|
|
377
|
+
% Probe the existing journal without waiting. A process running code from
|
|
378
|
+
% before the sync(close) fix may still retain the journal's write lock; fail
|
|
379
|
+
% before touching RDF so callers receive a safe, retryable diagnostic.
|
|
380
|
+
audit_store_writable :-
|
|
381
|
+
kb_audit_db(AuditLog),
|
|
382
|
+
( exists_file(AuditLog)
|
|
383
|
+
-> catch(
|
|
384
|
+
setup_call_cleanup(
|
|
385
|
+
open(AuditLog, append, Stream,
|
|
386
|
+
[lock(write), wait(false), encoding(utf8)]),
|
|
387
|
+
true,
|
|
388
|
+
close(Stream)
|
|
389
|
+
),
|
|
390
|
+
Error,
|
|
391
|
+
throw(error(permission_error(lock, audit_log, AuditLog),
|
|
392
|
+
context(kb_commit_upsert/5, Error)))
|
|
393
|
+
)
|
|
394
|
+
; true
|
|
395
|
+
).
|
|
396
|
+
|
|
397
|
+
% Reserved stderr markers are consumed by PrologProcess diagnostics and never
|
|
398
|
+
% form part of the JSON result. They make timeout errors stage-specific even
|
|
399
|
+
% when the child is blocked inside a filesystem primitive.
|
|
400
|
+
kb_stage(Stage) :-
|
|
401
|
+
format(user_error, '__KIBI_STAGE__:~w~n', [Stage]),
|
|
402
|
+
flush_output(user_error).
|
|
403
|
+
|
|
404
|
+
kb_runtime_diagnostic :-
|
|
405
|
+
( current_prolog_flag(pid, Pid) -> true ; Pid = unknown ),
|
|
406
|
+
( kb_audit_db(AuditLog) -> true ; AuditLog = unknown ),
|
|
407
|
+
kb_environment_value('KIBI_RUNTIME_NAME', RuntimeName),
|
|
408
|
+
kb_environment_value('KIBI_RUNTIME_VERSION', RuntimeVersion),
|
|
409
|
+
kb_environment_value('KIBI_PACKAGE_VERSIONS', PackageVersions),
|
|
410
|
+
format(user_error,
|
|
411
|
+
'__KIBI_RUNTIME__:pid=~w;audit=~w;runtime=~w@~w;packages=~w~n',
|
|
412
|
+
[Pid, AuditLog, RuntimeName, RuntimeVersion, PackageVersions]),
|
|
413
|
+
flush_output(user_error).
|
|
414
|
+
|
|
415
|
+
kb_environment_value(Name, Value) :-
|
|
416
|
+
( getenv(Name, Value)
|
|
417
|
+
-> true
|
|
418
|
+
; Value = unknown
|
|
419
|
+
).
|
|
420
|
+
|
|
307
421
|
%% kb_retract_entity_relationships(+Id)
|
|
308
422
|
% Remove all relationship triples for an entity, preserving property triples.
|
|
309
423
|
% Used by projectStagedEntities to clear stale relationships before re-asserting.
|
|
@@ -358,7 +472,7 @@ kb_retract_entity(Id, Type, AuditProps) :-
|
|
|
358
472
|
|
|
359
473
|
entity_delete_audit_props(Id, Props, AuditProps) :-
|
|
360
474
|
findall(Key=Value,
|
|
361
|
-
( member(Key, [title, source, text_ref]),
|
|
475
|
+
( member(Key, [title, source, text_ref, semantic_text]),
|
|
362
476
|
memberchk(Key=RawValue, Props),
|
|
363
477
|
audit_property_value(RawValue, Value)
|
|
364
478
|
),
|
|
@@ -398,7 +512,7 @@ kb_entity(Id, Type, Props) :-
|
|
|
398
512
|
atom_concat(BaseURI, type, TypeURI),
|
|
399
513
|
PropURI \= TypeURI,
|
|
400
514
|
uri_to_key(PropURI, Key),
|
|
401
|
-
literal_to_value(ValueLiteral, Value)
|
|
515
|
+
literal_to_value(Key, ValueLiteral, Value)
|
|
402
516
|
), Props).
|
|
403
517
|
|
|
404
518
|
% Fallback: read from legacy entity/4 facts loaded from .pl files
|
|
@@ -625,7 +739,7 @@ store_property(EntityURI, Key, Value, Graph) :-
|
|
|
625
739
|
% Key-aware: typed fact fields get specific XSD datatypes.
|
|
626
740
|
value_to_literal(Key, Value, Literal) :-
|
|
627
741
|
% Typed fact fields with specific XSD datatypes
|
|
628
|
-
( Key
|
|
742
|
+
( integer_property_key(Key), integer(Value)
|
|
629
743
|
-> Literal = Value^^'http://www.w3.org/2001/XMLSchema#integer'
|
|
630
744
|
; Key == value_number, number(Value)
|
|
631
745
|
-> Literal = Value^^'http://www.w3.org/2001/XMLSchema#decimal'
|
|
@@ -643,9 +757,29 @@ value_to_literal(Key, Value, Literal) :-
|
|
|
643
757
|
Literal = Str^^'http://www.w3.org/2001/XMLSchema#string'
|
|
644
758
|
).
|
|
645
759
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
760
|
+
integer_property_key(Key) :-
|
|
761
|
+
memberchk(Key, [
|
|
762
|
+
value_int,
|
|
763
|
+
predicate_arity,
|
|
764
|
+
claim_span_start,
|
|
765
|
+
claim_span_end,
|
|
766
|
+
sourceLine,
|
|
767
|
+
sourceColumn,
|
|
768
|
+
sourceEndLine,
|
|
769
|
+
sourceEndColumn
|
|
770
|
+
]).
|
|
771
|
+
|
|
772
|
+
%% literal_to_value(+Key, +Literal, -Value)
|
|
773
|
+
% Extract a property value from an RDF literal. JSON-backed fields must remain
|
|
774
|
+
% intact: JSON arrays are also valid Prolog list syntax, but parsing them as
|
|
775
|
+
% Prolog terms corrupts their object entries before the JSON decoder sees them.
|
|
776
|
+
literal_to_value(semantic_inventory, Literal, Value) :-
|
|
777
|
+
!,
|
|
778
|
+
structured_literal_value(Literal, Value).
|
|
779
|
+
literal_to_value(verification_receipts, Literal, Value) :-
|
|
780
|
+
!,
|
|
781
|
+
structured_literal_value(Literal, Value).
|
|
782
|
+
literal_to_value(_Key, Literal, Value) :-
|
|
649
783
|
( % Handle ^^/2 functor (RDF typed literal shorthand)
|
|
650
784
|
Literal = ^^(StrVal, 'http://www.w3.org/2001/XMLSchema#string')
|
|
651
785
|
-> ( % Preserve RDF typed literal functor for string values so callers
|
|
@@ -678,6 +812,12 @@ literal_to_value(Literal, Value) :-
|
|
|
678
812
|
; Value = Literal
|
|
679
813
|
).
|
|
680
814
|
|
|
815
|
+
structured_literal_value(^^(Value, _), Value) :- !.
|
|
816
|
+
structured_literal_value(literal(type(_, Value)), Value) :- !.
|
|
817
|
+
structured_literal_value(literal(lang(_, Value)), Value) :- !.
|
|
818
|
+
structured_literal_value(literal(Value), Value) :- !.
|
|
819
|
+
structured_literal_value(Value, Value).
|
|
820
|
+
|
|
681
821
|
%% literal_to_atom(+Literal, -Atom)
|
|
682
822
|
% Convert RDF literal to atom (for type field).
|
|
683
823
|
literal_to_atom(Literal, Atom) :-
|
|
@@ -979,19 +1119,21 @@ current_req(Id) :-
|
|
|
979
1119
|
% semantic conflicts (same subject/property but incompatible values or polarities).
|
|
980
1120
|
% Checks in order of specificity: polarity conflicts, then value conflicts.
|
|
981
1121
|
contradicting_reqs(ReqA, ReqB, Reason) :-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
ReqA @< ReqB,
|
|
985
|
-
req_conflict(ReqA, ReqB, Reason).
|
|
1122
|
+
req_conflict_witness(ReqA, ReqB, Witness),
|
|
1123
|
+
Reason = Witness.reason.
|
|
986
1124
|
|
|
987
1125
|
%% ------------------------------------------------------------------
|
|
988
1126
|
%% Semantic Contradiction Helpers (Task 4)
|
|
989
1127
|
%% ------------------------------------------------------------------
|
|
990
1128
|
|
|
991
|
-
%%
|
|
992
|
-
%
|
|
993
|
-
%
|
|
994
|
-
|
|
1129
|
+
%% req_conflict_witness(+ReqA, +ReqB, -Witness)
|
|
1130
|
+
% Return exact, source-bound evidence for one proven strict or predicate
|
|
1131
|
+
% contradiction. This remains deliberately syntactic: differently shaped
|
|
1132
|
+
% terms are never treated as equivalent merely because their prose is similar.
|
|
1133
|
+
req_conflict_witness(ReqA, ReqB, Witness) :-
|
|
1134
|
+
current_req(ReqA),
|
|
1135
|
+
current_req(ReqB),
|
|
1136
|
+
ReqA @< ReqB,
|
|
995
1137
|
kb_relationship(constrains, ReqA, SubjectFactA),
|
|
996
1138
|
kb_relationship(constrains, ReqB, SubjectFactB),
|
|
997
1139
|
fact_subject_key(SubjectFactA, SubjectKey),
|
|
@@ -1005,8 +1147,23 @@ req_conflict(ReqA, ReqB, Reason) :-
|
|
|
1005
1147
|
OpB, ValTypeB, ValB, UnitB, ScopeB, PolarityB, Reason)
|
|
1006
1148
|
; property_conflict(SubjectKey, PropertyKey, OpA, ValTypeA, ValA, UnitA, PolarityA,
|
|
1007
1149
|
OpB, ValTypeB, ValB, UnitB, PolarityB, Reason)
|
|
1008
|
-
)
|
|
1009
|
-
|
|
1150
|
+
),
|
|
1151
|
+
property_conflict_side(ReqA, FactA, SubjectKey, PropertyKey, OpA, ValTypeA, ValA, UnitA, ScopeA, PolarityA, ValidFromA, ValidToA, Left),
|
|
1152
|
+
property_conflict_side(ReqB, FactB, SubjectKey, PropertyKey, OpB, ValTypeB, ValB, UnitB, ScopeB, PolarityB, ValidFromB, ValidToB, Right),
|
|
1153
|
+
Witness = _{
|
|
1154
|
+
kind: strict_property,
|
|
1155
|
+
status: contradiction,
|
|
1156
|
+
requirements: [ReqA, ReqB],
|
|
1157
|
+
reason: Reason,
|
|
1158
|
+
subjectKey: SubjectKey,
|
|
1159
|
+
propertyKey: PropertyKey,
|
|
1160
|
+
left: Left,
|
|
1161
|
+
right: Right
|
|
1162
|
+
}.
|
|
1163
|
+
req_conflict_witness(ReqA, ReqB, Witness) :-
|
|
1164
|
+
current_req(ReqA),
|
|
1165
|
+
current_req(ReqB),
|
|
1166
|
+
ReqA @< ReqB,
|
|
1010
1167
|
effective_req_predicate(ReqA, FactA, Namespace, Name, Args, PolarityA),
|
|
1011
1168
|
effective_req_predicate(ReqB, FactB, Namespace, Name, Args, PolarityB),
|
|
1012
1169
|
FactA \= FactB,
|
|
@@ -1016,6 +1173,86 @@ req_conflict(ReqA, ReqB, Reason) :-
|
|
|
1016
1173
|
string(Reason),
|
|
1017
1174
|
"Predicate conflict on ~w:~w(~w): ~w asserts ~w while ~w asserts ~w",
|
|
1018
1175
|
[Namespace, Name, ArgsText, ReqA, PolarityA, ReqB, PolarityB]
|
|
1176
|
+
),
|
|
1177
|
+
predicate_conflict_side(ReqA, FactA, Namespace, Name, Args, PolarityA, Left),
|
|
1178
|
+
predicate_conflict_side(ReqB, FactB, Namespace, Name, Args, PolarityB, Right),
|
|
1179
|
+
length(Args, Arity),
|
|
1180
|
+
findall(SchemaId, predicate_schema(SchemaId, Namespace, Name, Arity, _ArgumentNames, _ArgumentTypes), SchemaIds0),
|
|
1181
|
+
sort(SchemaIds0, SchemaIds),
|
|
1182
|
+
Witness = _{
|
|
1183
|
+
kind: predicate,
|
|
1184
|
+
status: contradiction,
|
|
1185
|
+
requirements: [ReqA, ReqB],
|
|
1186
|
+
reason: Reason,
|
|
1187
|
+
predicateNamespace: Namespace,
|
|
1188
|
+
predicateName: Name,
|
|
1189
|
+
predicateArgs: Args,
|
|
1190
|
+
schemaIds: SchemaIds,
|
|
1191
|
+
left: Left,
|
|
1192
|
+
right: Right
|
|
1193
|
+
}.
|
|
1194
|
+
|
|
1195
|
+
property_conflict_side(ReqId, FactId, SubjectKey, PropertyKey, Operator, ValueType, Value, Unit, Scope, Polarity, ValidFrom, ValidTo, Side) :-
|
|
1196
|
+
entity_evidence_source(ReqId, req, RequirementSource),
|
|
1197
|
+
fact_evidence_fields(FactId, FactSource, ClaimKey, ClaimText, _CanonicalKey),
|
|
1198
|
+
Side = _{
|
|
1199
|
+
requirementId: ReqId,
|
|
1200
|
+
requirementSource: RequirementSource,
|
|
1201
|
+
factId: FactId,
|
|
1202
|
+
factSource: FactSource,
|
|
1203
|
+
claimKey: ClaimKey,
|
|
1204
|
+
claimText: ClaimText,
|
|
1205
|
+
term: _{
|
|
1206
|
+
subjectKey: SubjectKey,
|
|
1207
|
+
propertyKey: PropertyKey,
|
|
1208
|
+
operator: Operator,
|
|
1209
|
+
valueType: ValueType,
|
|
1210
|
+
value: Value,
|
|
1211
|
+
unit: Unit,
|
|
1212
|
+
scope: Scope,
|
|
1213
|
+
polarity: Polarity,
|
|
1214
|
+
validFrom: ValidFrom,
|
|
1215
|
+
validTo: ValidTo
|
|
1216
|
+
}
|
|
1217
|
+
}.
|
|
1218
|
+
|
|
1219
|
+
predicate_conflict_side(ReqId, FactId, Namespace, Name, Args, Polarity, Side) :-
|
|
1220
|
+
entity_evidence_source(ReqId, req, RequirementSource),
|
|
1221
|
+
fact_evidence_fields(FactId, FactSource, ClaimKey, ClaimText, CanonicalKey),
|
|
1222
|
+
Side = _{
|
|
1223
|
+
requirementId: ReqId,
|
|
1224
|
+
requirementSource: RequirementSource,
|
|
1225
|
+
factId: FactId,
|
|
1226
|
+
factSource: FactSource,
|
|
1227
|
+
claimKey: ClaimKey,
|
|
1228
|
+
claimText: ClaimText,
|
|
1229
|
+
term: _{
|
|
1230
|
+
namespace: Namespace,
|
|
1231
|
+
name: Name,
|
|
1232
|
+
args: Args,
|
|
1233
|
+
polarity: Polarity,
|
|
1234
|
+
canonicalKey: CanonicalKey
|
|
1235
|
+
}
|
|
1236
|
+
}.
|
|
1237
|
+
|
|
1238
|
+
entity_evidence_source(EntityId, Type, Source) :-
|
|
1239
|
+
kb_entity(EntityId, Type, Props),
|
|
1240
|
+
(memberchk(source=RawSource, Props) -> evidence_term_atom(RawSource, Source) ; Source = '').
|
|
1241
|
+
|
|
1242
|
+
fact_evidence_fields(FactId, Source, ClaimKey, ClaimText, CanonicalKey) :-
|
|
1243
|
+
kb_entity(FactId, fact, Props),
|
|
1244
|
+
(memberchk(source=RawSource, Props) -> evidence_term_atom(RawSource, Source) ; Source = ''),
|
|
1245
|
+
(memberchk(claim_key=RawClaimKey, Props) -> evidence_term_atom(RawClaimKey, ClaimKey) ; ClaimKey = ''),
|
|
1246
|
+
(memberchk(claim_text=RawClaimText, Props) -> evidence_term_atom(RawClaimText, ClaimText) ; ClaimText = ''),
|
|
1247
|
+
(memberchk(canonical_key=RawCanonicalKey, Props) -> evidence_term_atom(RawCanonicalKey, CanonicalKey) ; CanonicalKey = '').
|
|
1248
|
+
|
|
1249
|
+
evidence_term_atom(Raw, Atom) :-
|
|
1250
|
+
unwrap_rdf_value(Raw, Value),
|
|
1251
|
+
( atom(Value)
|
|
1252
|
+
-> Atom = Value
|
|
1253
|
+
; string(Value)
|
|
1254
|
+
-> atom_string(Atom, Value)
|
|
1255
|
+
; term_string(Value, String), atom_string(Atom, String)
|
|
1019
1256
|
).
|
|
1020
1257
|
|
|
1021
1258
|
%% effective_req_predicate(+ReqId, -FactId, -Namespace, -Name, -Args, -Polarity)
|