@pie-players/pie-assessment-toolkit 0.3.75 → 1.0.0-beta.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/README.md +451 -541
- package/custom-elements.json +1315 -0
- package/dist/attempt/TestSession.d.ts +0 -1
- package/dist/attempt/TestSession.js +10 -5
- package/dist/components/ItemScope.custom-element.js +1 -1
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +8 -8
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/{ItemToolBar-7tt7v2xp.js → ItemToolBar-3zrc4p3d.js} +4 -4
- package/dist/components/chunks/{ItemToolBar-jx38w99s.js → ItemToolBar-66hcwmfw.js} +2 -2
- package/dist/components/chunks/ItemToolBar-asenkvx6.js +40 -0
- package/dist/components/chunks/ItemToolBar-hzc5wyjp.js +2 -0
- package/dist/components/chunks/{ItemToolBar-97hx60z4.js → ItemToolBar-kkj69ptr.js} +1 -1
- package/dist/components/chunks/sre-engine-bj997w4b.js +1 -0
- package/dist/context/assessment-toolkit-context.d.ts +6 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +4 -10
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +46 -7
- package/dist/policy/core/ToolPolicyEngine.js +73 -16
- package/dist/policy/core/compose-decision.d.ts +3 -3
- package/dist/policy/core/compose-decision.js +32 -30
- package/dist/policy/core/decision-types.d.ts +51 -34
- package/dist/policy/core/feature-decision.d.ts +17 -15
- package/dist/policy/core/feature-decision.js +11 -13
- package/dist/policy/core/pnp-policy-inputs.d.ts +7 -3
- package/dist/policy/core/pnp-policy-inputs.js +17 -33
- package/dist/policy/core/provenance.d.ts +2 -2
- package/dist/policy/core/tool-parameters.d.ts +12 -0
- package/dist/policy/core/tool-parameters.js +27 -0
- package/dist/policy/engine.d.ts +1 -1
- package/dist/policy/sources/PnpPolicySource.d.ts +18 -24
- package/dist/policy/sources/PnpPolicySource.js +57 -29
- package/dist/runtime/SectionControllerBinding.d.ts +6 -2
- package/dist/runtime/SectionControllerBinding.js +21 -15
- package/dist/runtime/adapter/subscriber-fanout.d.ts +0 -1
- package/dist/runtime/adapter/subscriber-fanout.js +1 -4
- package/dist/runtime/composition-emit-scheduler.d.ts +3 -3
- package/dist/runtime/composition-emit-scheduler.js +1 -1
- package/dist/runtime/content-region.d.ts +0 -4
- package/dist/runtime/content-region.js +2 -2
- package/dist/runtime/core/SectionEngineCore.d.ts +0 -2
- package/dist/runtime/core/SectionEngineCore.js +0 -4
- package/dist/runtime/core/cohort.d.ts +0 -5
- package/dist/runtime/core/cohort.js +0 -9
- package/dist/runtime/core/engine-output.d.ts +3 -2
- package/dist/runtime/core/engine-transition.js +3 -2
- package/dist/runtime/registration-events.d.ts +11 -14
- package/dist/runtime/runtime-id.d.ts +1 -1
- package/dist/runtime/runtime-id.js +1 -1
- package/dist/runtime/shell-scope.d.ts +4 -4
- package/dist/runtime/shell-scope.js +15 -9
- package/dist/runtime/tool-host-contract.d.ts +0 -4
- package/dist/runtime/tool-host-contract.js +1 -1
- package/dist/services/AccessibilityCatalogResolver.d.ts +21 -31
- package/dist/services/AccessibilityCatalogResolver.js +29 -42
- package/dist/services/ElementToolStateStore.d.ts +32 -61
- package/dist/services/ElementToolStateStore.js +37 -67
- package/dist/services/HighlightCoordinator.d.ts +9 -21
- package/dist/services/HighlightCoordinator.js +52 -80
- package/dist/services/RangeSerializer.d.ts +4 -35
- package/dist/services/RangeSerializer.js +4 -48
- package/dist/services/SSMLExtractor.d.ts +8 -31
- package/dist/services/SSMLExtractor.js +18 -40
- package/dist/services/TTSService.d.ts +51 -57
- package/dist/services/TTSService.js +323 -284
- package/dist/services/ToolCoordinator.d.ts +6 -49
- package/dist/services/ToolCoordinator.js +25 -61
- package/dist/services/ToolRegistry.d.ts +83 -80
- package/dist/services/ToolRegistry.js +91 -67
- package/dist/services/ToolkitCoordinator.d.ts +83 -81
- package/dist/services/ToolkitCoordinator.js +186 -174
- package/dist/services/framework-error.d.ts +30 -7
- package/dist/services/framework-error.js +10 -13
- package/dist/services/interfaces.d.ts +51 -71
- package/dist/services/section-controller-types.d.ts +7 -7
- package/dist/services/section-session-assignment.js +6 -8
- package/dist/services/spoken-audio-cards.d.ts +2 -4
- package/dist/services/spoken-audio-cards.js +2 -4
- package/dist/services/tool-config-validation.d.ts +5 -7
- package/dist/services/tool-config-validation.js +11 -26
- package/dist/services/tool-context.d.ts +39 -24
- package/dist/services/tool-context.js +158 -92
- package/dist/services/tool-failure.d.ts +30 -0
- package/dist/services/tool-failure.js +11 -0
- package/dist/services/tool-icons.d.ts +1 -2
- package/dist/services/tool-icons.js +2 -2
- package/dist/services/tool-instance-id.d.ts +8 -6
- package/dist/services/tool-instance-id.js +12 -18
- package/dist/services/tool-providers/TTSToolProvider.d.ts +6 -43
- package/dist/services/tool-providers/TTSToolProvider.js +7 -63
- package/dist/services/tool-providers/ToolProviderApi.d.ts +0 -7
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +7 -42
- package/dist/services/tool-providers/ToolProviderRegistry.js +21 -63
- package/dist/services/tool-request.d.ts +4 -0
- package/dist/services/tool-request.js +7 -2
- package/dist/services/toolbar-decided-tools.d.ts +2 -0
- package/dist/services/toolbar-decided-tools.js +2 -0
- package/dist/services/toolbar-items.js +2 -5
- package/dist/services/tools-config-normalizer.d.ts +18 -9
- package/dist/services/tools-config-normalizer.js +25 -19
- package/dist/services/tts/browser-provider.d.ts +2 -5
- package/dist/services/tts/browser-provider.js +13 -22
- package/dist/services/tts/catalog-span-alignment.js +14 -7
- package/dist/services/tts/flat-tree.d.ts +0 -7
- package/dist/services/tts/flat-tree.js +2 -2
- package/dist/services/tts/generated-speech/dom/to-chunk-inputs.d.ts +2 -2
- package/dist/services/tts/generated-speech/index.d.ts +1 -1
- package/dist/services/tts/generated-speech/index.js +1 -1
- package/dist/services/tts/generated-speech/types.d.ts +1 -1
- package/dist/services/tts/generated-speech/types.js +1 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +10 -12
- package/dist/services/tts/highlight-target-resolver.d.ts +12 -0
- package/dist/services/tts/math-aware-text-processing.js +10 -29
- package/dist/services/tts/math-speech.d.ts +1 -1
- package/dist/services/tts/math-speech.js +3 -0
- package/dist/services/tts/mathml-sanitization.d.ts +7 -0
- package/dist/services/tts/mathml-sanitization.js +9 -1
- package/dist/services/tts/provider-options.d.ts +12 -1
- package/dist/services/tts/ssml/spoken-text.js +1 -1
- package/dist/services/tts/start-failure.d.ts +0 -7
- package/dist/services/tts/start-failure.js +1 -1
- package/dist/services/tts/text-segmentation.d.ts +5 -0
- package/dist/services/tts/text-segmentation.js +13 -10
- package/dist/services/tts-runtime-config.d.ts +32 -12
- package/dist/services/tts-runtime-config.js +14 -20
- package/dist/tools/content-capability-resolution.d.ts +2 -2
- package/dist/tools/registration.d.ts +7 -6
- package/dist/tools/registration.js +10 -9
- package/dist/tools/registrations/toolbar-registration-helpers.d.ts +6 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +6 -0
- package/dist/tools/tool-surface-host.js +1 -8
- package/package.json +8 -6
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +0 -2
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +0 -40
- package/dist/components/chunks/sre-engine-jd8cc08x.js +0 -1
- package/dist/services/ContextVariableStore.d.ts +0 -113
- package/dist/services/ContextVariableStore.js +0 -206
- package/dist/services/tts-control-events.d.ts +0 -13
- package/dist/services/tts-control-events.js +0 -7
- package/dist/utils/logger.d.ts +0 -6
- package/dist/utils/logger.js +0 -10
|
@@ -50,8 +50,10 @@ export interface ToolPolicyDecisionRequest {
|
|
|
50
50
|
/**
|
|
51
51
|
* Diagnostic codes the engine may emit alongside a decision.
|
|
52
52
|
* `tool-policy.requiredToolBlocked` fires when a host policy gate
|
|
53
|
-
* (`policy.blocked`,
|
|
54
|
-
* that item or district `requiredTools` mandates.
|
|
53
|
+
* (`policy.blocked`, the allowlist, a provider veto, or placement at no level)
|
|
54
|
+
* removed a tool that item or district `requiredTools` mandates. A tool placed
|
|
55
|
+
* at another level is served there, so its absence from this level's placement
|
|
56
|
+
* is no conflict. `details` is {@link RequiredToolBlockedDetails}.
|
|
55
57
|
*
|
|
56
58
|
* `tool-policy.placementMissing` fires when a custom `PolicySource`
|
|
57
59
|
* references a tool ID that is not present in `tools.placement[level]`
|
|
@@ -62,7 +64,9 @@ export interface ToolPolicyDecisionRequest {
|
|
|
62
64
|
*
|
|
63
65
|
* `tool-policy.unknownSupportId` fires for each id a profile, district
|
|
64
66
|
* policy, test administration or item names that no tool is registered under.
|
|
65
|
-
*
|
|
67
|
+
* It describes the inputs, so the engine reports it on its resolved inputs'
|
|
68
|
+
* `diagnostics` rather than on a decision. `details` is
|
|
69
|
+
* {@link UnknownSupportIdDetails}.
|
|
66
70
|
*
|
|
67
71
|
* `tool-policy.itemSettingNotApplied` fires on a section-, assessment- or
|
|
68
72
|
* passage-level decision for each tool on that toolbar a mounted item's
|
|
@@ -75,9 +79,10 @@ export interface ToolPolicyDecisionRequest {
|
|
|
75
79
|
* `restrictedTools` or the profile's `prohibitedSupports` withdraws instead.
|
|
76
80
|
* `details` is {@link OverrideBlockedDetails}.
|
|
77
81
|
*
|
|
78
|
-
* The toolkit coordinator logs each diagnostic once per code, tool and item
|
|
82
|
+
* The toolkit coordinator logs each diagnostic once per code, tool and item,
|
|
83
|
+
* and hands the same ones to its `onPolicyDiagnostic` listeners.
|
|
79
84
|
*/
|
|
80
|
-
export type ToolPolicyDiagnosticCode =
|
|
85
|
+
export type ToolPolicyDiagnosticCode = keyof ToolPolicyDiagnosticDetails;
|
|
81
86
|
/**
|
|
82
87
|
* Which host gate removed a profile-mandated tool. Surfaced inside
|
|
83
88
|
* `ToolPolicyDiagnostic.details` for `tool-policy.requiredToolBlocked`
|
|
@@ -87,44 +92,38 @@ export type ToolPolicyDiagnosticCode = "tool-policy.requiredToolBlocked" | "tool
|
|
|
87
92
|
* `provenance.features[toolId].allDecisions`.
|
|
88
93
|
*
|
|
89
94
|
* The four values mirror steps 1–4 of `composeDecision`:
|
|
90
|
-
* - `placement-missing` —
|
|
95
|
+
* - `placement-missing` — no level of `tools.placement` lists the tool
|
|
91
96
|
* - `provider-disabled` — `tools.providers[id].enabled === false`
|
|
92
97
|
* - `host-allowlist` — non-empty `tools.policy.allowed` excludes the id
|
|
93
98
|
* - `host-blocked` — `tools.policy.blocked` lists the id
|
|
94
99
|
*/
|
|
95
100
|
export type ToolPolicyHostGate = "placement-missing" | "provider-disabled" | "host-allowlist" | "host-blocked";
|
|
96
|
-
/**
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
* always populate this exact shape today and consumers can safely
|
|
101
|
-
* cast.
|
|
102
|
-
*/
|
|
103
|
-
export interface RequiredToolBlockedDetails extends Record<string, unknown> {
|
|
104
|
-
/** The profile policy rule that mandated the tool (e.g. `district-requirement`). */
|
|
105
|
-
rule: string;
|
|
101
|
+
/** Payload of a `tool-policy.requiredToolBlocked` diagnostic. */
|
|
102
|
+
export interface RequiredToolBlockedDetails {
|
|
103
|
+
/** The requirement that mandates the tool. */
|
|
104
|
+
rule: "item-requirement" | "district-requirement";
|
|
106
105
|
/** Which host gate removed the tool. */
|
|
107
106
|
hostRule: ToolPolicyHostGate;
|
|
108
107
|
/** The host configuration value that triggered the gate (best-effort, may be omitted). */
|
|
109
108
|
hostValue?: unknown;
|
|
110
109
|
}
|
|
111
110
|
/** Payload of a `tool-policy.unknownSupportId` diagnostic. */
|
|
112
|
-
export interface UnknownSupportIdDetails
|
|
111
|
+
export interface UnknownSupportIdDetails {
|
|
113
112
|
/** The rules whose lists name the id, in precedence order. */
|
|
114
113
|
origins: PnpPolicySourceRule[];
|
|
115
114
|
}
|
|
116
115
|
/** Payload of a `tool-policy.placementMissing` diagnostic. */
|
|
117
|
-
export interface PlacementMissingDetails
|
|
116
|
+
export interface PlacementMissingDetails {
|
|
118
117
|
/** The custom `PolicySource` that named the tool. */
|
|
119
118
|
customSourceId: string;
|
|
120
119
|
}
|
|
121
120
|
/** Payload of a `tool-policy.overrideBlocked` diagnostic. */
|
|
122
|
-
export interface OverrideBlockedDetails
|
|
121
|
+
export interface OverrideBlockedDetails {
|
|
123
122
|
/** The rule that withdrew the granted tool. */
|
|
124
123
|
rule: "item-restriction" | "pnp-prohibited";
|
|
125
124
|
}
|
|
126
125
|
/** Payload of a `tool-policy.itemSettingNotApplied` diagnostic. */
|
|
127
|
-
export interface ItemSettingNotAppliedDetails
|
|
126
|
+
export interface ItemSettingNotAppliedDetails {
|
|
128
127
|
/** Canonical id of the item whose setting names the tool. */
|
|
129
128
|
itemId: string;
|
|
130
129
|
/** The item settings that name it. */
|
|
@@ -132,14 +131,28 @@ export interface ItemSettingNotAppliedDetails extends Record<string, unknown> {
|
|
|
132
131
|
/** The level of the toolbar the tool is on. */
|
|
133
132
|
toolbarLevel: ToolLevel;
|
|
134
133
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
/** The payload each diagnostic code carries. */
|
|
135
|
+
export interface ToolPolicyDiagnosticDetails {
|
|
136
|
+
"tool-policy.requiredToolBlocked": RequiredToolBlockedDetails;
|
|
137
|
+
"tool-policy.placementMissing": PlacementMissingDetails;
|
|
138
|
+
"tool-policy.unknownSupportId": UnknownSupportIdDetails;
|
|
139
|
+
"tool-policy.itemSettingNotApplied": ItemSettingNotAppliedDetails;
|
|
140
|
+
"tool-policy.overrideBlocked": OverrideBlockedDetails;
|
|
142
141
|
}
|
|
142
|
+
/** A policy diagnostic, its `details` typed by its `code`. */
|
|
143
|
+
export type ToolPolicyDiagnostic = {
|
|
144
|
+
[C in ToolPolicyDiagnosticCode]: {
|
|
145
|
+
code: C;
|
|
146
|
+
/**
|
|
147
|
+
* The toolbar level decided; absent on a feature decision and on an input
|
|
148
|
+
* diagnostic.
|
|
149
|
+
*/
|
|
150
|
+
level?: ToolPlacementLevel;
|
|
151
|
+
toolId: string;
|
|
152
|
+
message: string;
|
|
153
|
+
details: ToolPolicyDiagnosticDetails[C];
|
|
154
|
+
};
|
|
155
|
+
}[ToolPolicyDiagnosticCode];
|
|
143
156
|
export interface ToolPolicyEntry {
|
|
144
157
|
toolId: string;
|
|
145
158
|
/**
|
|
@@ -150,20 +163,24 @@ export interface ToolPolicyEntry {
|
|
|
150
163
|
*/
|
|
151
164
|
required: boolean;
|
|
152
165
|
/**
|
|
153
|
-
* `true` for a tool the student's PNP `supports` or a
|
|
154
|
-
* `testAdministration.toolOverrides` entry grants — UI-level signal that
|
|
166
|
+
* `true` for a tool the student's PNP `supports` or `activateAtInit`, or a
|
|
167
|
+
* `testAdministration.toolOverrides` entry, grants — UI-level signal that
|
|
155
168
|
* the host cannot toggle this tool off in user preferences. Does NOT
|
|
156
169
|
* override host blocks (they would have removed the entry before this
|
|
157
170
|
* flag is read).
|
|
158
171
|
*/
|
|
159
172
|
alwaysAvailable: boolean;
|
|
160
173
|
/**
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
|
|
164
|
-
|
|
174
|
+
* `true` for a tool the student's PNP `activateAtInit` lists that policy
|
|
175
|
+
* admits: the toolbar turns it on when it first shows it.
|
|
176
|
+
*/
|
|
177
|
+
activateAtInit: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* The tool's parameters: the profile's, assessment's and, on the item's own
|
|
180
|
+
* toolbar, item's `toolParameters` entries merged key by key, later ones
|
|
181
|
+
* winning. Set whether or not a grant admitted the tool.
|
|
165
182
|
*/
|
|
166
|
-
|
|
183
|
+
parameters?: Record<string, unknown>;
|
|
167
184
|
}
|
|
168
185
|
export interface ToolPolicyDecision {
|
|
169
186
|
visibleTools: ToolPolicyEntry[];
|
|
@@ -27,10 +27,10 @@ import type { PnpPolicySourceRule, ToolPolicyResolutionDecision, ToolPolicySourc
|
|
|
27
27
|
* A feature verdict comes from one of the eight PNP precedence levels, or from a
|
|
28
28
|
* host gate that never reaches them: `tools.policy.blocked` and a non-empty
|
|
29
29
|
* `tools.policy.allowed` are absolute for the id they name, exactly as they are
|
|
30
|
-
* on the placement-scoped path.
|
|
30
|
+
* on the placement-scoped path. `"none"` is a feature no rule names.
|
|
31
31
|
*/
|
|
32
|
-
export type FeaturePolicyRule = PnpPolicySourceRule | "host-allowlist" | "host-blocked";
|
|
33
|
-
export interface FeaturePolicyDecision {
|
|
32
|
+
export type FeaturePolicyRule = PnpPolicySourceRule | "host-allowlist" | "host-blocked" | "none";
|
|
33
|
+
export interface FeaturePolicyDecision<P = Record<string, unknown>> {
|
|
34
34
|
/** The PNP/AfA support id that was evaluated (e.g. `"signLanguage"`). */
|
|
35
35
|
featureId: string;
|
|
36
36
|
/**
|
|
@@ -42,7 +42,8 @@ export interface FeaturePolicyDecision {
|
|
|
42
42
|
action: ToolPolicyResolutionDecision["action"];
|
|
43
43
|
/** Which precedence rule produced the verdict. */
|
|
44
44
|
rule: FeaturePolicyRule;
|
|
45
|
-
|
|
45
|
+
/** The rule's precedence level; `null` for `rule: "none"`. */
|
|
46
|
+
precedence: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | null;
|
|
46
47
|
sourceType: ToolPolicySourceType;
|
|
47
48
|
/** Human-readable explanation, suitable for a policy debugger. */
|
|
48
49
|
reason: string;
|
|
@@ -66,20 +67,21 @@ export interface FeaturePolicyDecision {
|
|
|
66
67
|
*/
|
|
67
68
|
assessmentBound: boolean;
|
|
68
69
|
/**
|
|
69
|
-
* `true` when
|
|
70
|
-
*
|
|
70
|
+
* `true` when item or district `requiredTools` mandates the feature, including
|
|
71
|
+
* under a `true` test-administration override.
|
|
71
72
|
*/
|
|
72
73
|
required: boolean;
|
|
73
74
|
/**
|
|
74
|
-
*
|
|
75
|
-
* `
|
|
76
|
-
*
|
|
75
|
+
* The feature's parameters: the profile's, assessment's and, for an item's
|
|
76
|
+
* scope, item's `toolParameters` entries for the feature id, merged key by key,
|
|
77
|
+
* later ones winning. Set on a denial too; a host denial leaves it out.
|
|
77
78
|
*/
|
|
78
|
-
parameters?:
|
|
79
|
+
parameters?: P;
|
|
79
80
|
/**
|
|
80
|
-
* Conflicts found while deciding: a `tool-policy.
|
|
81
|
-
*
|
|
82
|
-
*
|
|
81
|
+
* Conflicts found while deciding: a `tool-policy.overrideBlocked` for a
|
|
82
|
+
* granting override the decision withdrew. Empty on a host denial, which
|
|
83
|
+
* consults no policy source. An id no tool is registered under describes the
|
|
84
|
+
* inputs, so it is reported on the engine inputs' `diagnostics`.
|
|
83
85
|
*/
|
|
84
86
|
diagnostics: ToolPolicyDiagnostic[];
|
|
85
87
|
}
|
|
@@ -97,7 +99,7 @@ export interface FeatureDecisionContext {
|
|
|
97
99
|
* blocklist is a verdict whether or not an assessment was bound, and the flag
|
|
98
100
|
* only ever qualifies a *policy* denial.
|
|
99
101
|
*/
|
|
100
|
-
export declare function hostFeatureDenial(featureId: string, rule: "host-allowlist" | "host-blocked", hostValue: readonly string[], context: FeatureDecisionContext): FeaturePolicyDecision
|
|
102
|
+
export declare function hostFeatureDenial(featureId: string, rule: "host-allowlist" | "host-blocked", hostValue: readonly string[], context: FeatureDecisionContext): FeaturePolicyDecision<never>;
|
|
101
103
|
/**
|
|
102
104
|
* Whether a host gate produced the verdict, rather than a policy source.
|
|
103
105
|
*
|
|
@@ -114,4 +116,4 @@ export declare function isHostDeniedFeature(decision: Pick<FeaturePolicyDecision
|
|
|
114
116
|
* exactly one decision and at most one flags entry — no mapped-tool-id
|
|
115
117
|
* bookkeeping is needed to read it back out.
|
|
116
118
|
*/
|
|
117
|
-
export declare function interpretFeatureResult(featureId: string, result: PnpPolicyResult, context: FeatureDecisionContext): FeaturePolicyDecision
|
|
119
|
+
export declare function interpretFeatureResult<P>(featureId: string, result: PnpPolicyResult, context: FeatureDecisionContext, parameters: P | undefined): FeaturePolicyDecision<P>;
|
|
@@ -20,14 +20,12 @@
|
|
|
20
20
|
* "nothing was bound to ask against" are the same verdict for different
|
|
21
21
|
* reasons, and only the second is a defect.
|
|
22
22
|
*/
|
|
23
|
-
import { overrideBlockedDiagnostic
|
|
23
|
+
import { overrideBlockedDiagnostic } from "./compose-decision.js";
|
|
24
24
|
/**
|
|
25
25
|
* Reason text for a denial that had no assessment to decide against.
|
|
26
26
|
*
|
|
27
|
-
* Used in place of
|
|
28
|
-
*
|
|
29
|
-
* stay as the source reported them: nothing fired, so naming a ninth rule
|
|
30
|
-
* would describe a precedence level that does not exist.
|
|
27
|
+
* Used in place of "not configured", which is true but reads as a completed
|
|
28
|
+
* evaluation.
|
|
31
29
|
*/
|
|
32
30
|
const unboundAssessmentReason = (featureId) => `No assessment is bound, so no policy source could grant "${featureId}"`;
|
|
33
31
|
/**
|
|
@@ -73,17 +71,20 @@ export function isHostDeniedFeature(decision) {
|
|
|
73
71
|
* exactly one decision and at most one flags entry — no mapped-tool-id
|
|
74
72
|
* bookkeeping is needed to read it back out.
|
|
75
73
|
*/
|
|
76
|
-
export function interpretFeatureResult(featureId, result, context) {
|
|
74
|
+
export function interpretFeatureResult(featureId, result, context, parameters) {
|
|
77
75
|
const decision = result.decisions[0];
|
|
78
76
|
const flags = Array.from(result.perToolFlags.values())[0];
|
|
79
77
|
const granted = decision?.action === "enable";
|
|
80
78
|
const reason = decision?.reason ?? `Feature "${featureId}" not configured`;
|
|
79
|
+
// The source logs "no rule fired" as a skip at the last level so the trail
|
|
80
|
+
// stays ordered; the verdict names no rule for it.
|
|
81
|
+
const fired = decision !== undefined && decision.action !== "skip";
|
|
81
82
|
return {
|
|
82
83
|
featureId,
|
|
83
84
|
granted,
|
|
84
85
|
action: decision?.action ?? "skip",
|
|
85
|
-
rule: decision
|
|
86
|
-
precedence: decision
|
|
86
|
+
rule: fired ? decision.rule : "none",
|
|
87
|
+
precedence: fired ? decision.precedence : null,
|
|
87
88
|
sourceType: decision?.sourceType ?? "system",
|
|
88
89
|
// Only a denial is re-worded. An unbound host can still be granted the
|
|
89
90
|
// feature — an item's registered settings carrying `requiredTools` mandate
|
|
@@ -93,11 +94,8 @@ export function interpretFeatureResult(featureId, result, context) {
|
|
|
93
94
|
? reason
|
|
94
95
|
: unboundAssessmentReason(featureId),
|
|
95
96
|
required: Boolean(flags?.required),
|
|
96
|
-
parameters
|
|
97
|
+
parameters,
|
|
97
98
|
assessmentBound: context.assessmentBound,
|
|
98
|
-
diagnostics: [
|
|
99
|
-
...Array.from(result.unmappedSupportIds, ([supportId, origins]) => unknownSupportIdDiagnostic(supportId, origins)),
|
|
100
|
-
...Array.from(result.blockedOverrides, ([toolId, rule]) => overrideBlockedDiagnostic(toolId, rule)),
|
|
101
|
-
],
|
|
99
|
+
diagnostics: Array.from(result.blockedOverrides, ([toolId, rule]) => overrideBlockedDiagnostic(toolId, rule)),
|
|
102
100
|
};
|
|
103
101
|
}
|
|
@@ -11,11 +11,15 @@
|
|
|
11
11
|
* record (only `id` / `name`, no PNP and no settings) do not engage
|
|
12
12
|
* PNP/profile gates. The flip happens the moment the assessment carries any of:
|
|
13
13
|
*
|
|
14
|
-
* - `personalNeedsProfile` (any `supports
|
|
14
|
+
* - `personalNeedsProfile` (any `supports`, `prohibitedSupports` or
|
|
15
|
+
* `activateAtInit`),
|
|
15
16
|
* - `settings.districtPolicy` (any `blockedTools` or `requiredTools`),
|
|
16
17
|
* - `settings.testAdministration` (any `toolOverrides` entry),
|
|
17
18
|
* - or, for an item-scoped decision, the item's settings carry
|
|
18
|
-
* `requiredTools` / `restrictedTools
|
|
19
|
+
* `requiredTools` / `restrictedTools`.
|
|
20
|
+
*
|
|
21
|
+
* Tool parameters are no policy material: the engine resolves them whatever the
|
|
22
|
+
* enforcement state.
|
|
19
23
|
*
|
|
20
24
|
* Hosts opt out of the auto-on behavior by passing
|
|
21
25
|
* `pnpEnforcement: "off"` explicitly (engine input or
|
|
@@ -32,7 +36,7 @@ import type { AssessmentEntity, ItemSettings } from "@pie-players/pie-players-sh
|
|
|
32
36
|
export declare function assessmentHasPnpPolicyInputs(assessment: AssessmentEntity | null | undefined): boolean;
|
|
33
37
|
/**
|
|
34
38
|
* Return `true` when an item's settings carry item-level profile policy
|
|
35
|
-
* material (`requiredTools
|
|
39
|
+
* material (`requiredTools` or `restrictedTools`).
|
|
36
40
|
*
|
|
37
41
|
* Used in addition to {@link assessmentHasPnpPolicyInputs} for a decision scoped
|
|
38
42
|
* to the item, so an item with profile-relevant settings engages PNP/profile
|
|
@@ -11,16 +11,21 @@
|
|
|
11
11
|
* record (only `id` / `name`, no PNP and no settings) do not engage
|
|
12
12
|
* PNP/profile gates. The flip happens the moment the assessment carries any of:
|
|
13
13
|
*
|
|
14
|
-
* - `personalNeedsProfile` (any `supports
|
|
14
|
+
* - `personalNeedsProfile` (any `supports`, `prohibitedSupports` or
|
|
15
|
+
* `activateAtInit`),
|
|
15
16
|
* - `settings.districtPolicy` (any `blockedTools` or `requiredTools`),
|
|
16
17
|
* - `settings.testAdministration` (any `toolOverrides` entry),
|
|
17
18
|
* - or, for an item-scoped decision, the item's settings carry
|
|
18
|
-
* `requiredTools` / `restrictedTools
|
|
19
|
+
* `requiredTools` / `restrictedTools`.
|
|
20
|
+
*
|
|
21
|
+
* Tool parameters are no policy material: the engine resolves them whatever the
|
|
22
|
+
* enforcement state.
|
|
19
23
|
*
|
|
20
24
|
* Hosts opt out of the auto-on behavior by passing
|
|
21
25
|
* `pnpEnforcement: "off"` explicitly (engine input or
|
|
22
26
|
* `ToolkitCoordinator.setPnpEnforcement("off")`).
|
|
23
27
|
*/
|
|
28
|
+
const hasEntries = (value) => Array.isArray(value) && value.length > 0;
|
|
24
29
|
/**
|
|
25
30
|
* Return `true` when the assessment carries any PNP/profile policy
|
|
26
31
|
* material that the engine's `PnpPolicySource` would consume.
|
|
@@ -32,26 +37,18 @@ export function assessmentHasPnpPolicyInputs(assessment) {
|
|
|
32
37
|
if (!assessment)
|
|
33
38
|
return false;
|
|
34
39
|
const pnp = assessment.personalNeedsProfile;
|
|
35
|
-
if (pnp
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
40
|
+
if (pnp &&
|
|
41
|
+
(hasEntries(pnp.supports) ||
|
|
42
|
+
hasEntries(pnp.prohibitedSupports) ||
|
|
43
|
+
hasEntries(pnp.activateAtInit))) {
|
|
44
|
+
return true;
|
|
42
45
|
}
|
|
43
46
|
const settings = assessment.settings;
|
|
44
47
|
if (settings) {
|
|
45
48
|
const district = settings.districtPolicy;
|
|
46
|
-
if (district
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
if (Array.isArray(district.requiredTools) &&
|
|
52
|
-
district.requiredTools.length > 0) {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
49
|
+
if (district &&
|
|
50
|
+
(hasEntries(district.blockedTools) || hasEntries(district.requiredTools))) {
|
|
51
|
+
return true;
|
|
55
52
|
}
|
|
56
53
|
const overrides = settings.testAdministration?.toolOverrides;
|
|
57
54
|
if (overrides &&
|
|
@@ -64,7 +61,7 @@ export function assessmentHasPnpPolicyInputs(assessment) {
|
|
|
64
61
|
}
|
|
65
62
|
/**
|
|
66
63
|
* Return `true` when an item's settings carry item-level profile policy
|
|
67
|
-
* material (`requiredTools
|
|
64
|
+
* material (`requiredTools` or `restrictedTools`).
|
|
68
65
|
*
|
|
69
66
|
* Used in addition to {@link assessmentHasPnpPolicyInputs} for a decision scoped
|
|
70
67
|
* to the item, so an item with profile-relevant settings engages PNP/profile
|
|
@@ -74,20 +71,7 @@ export function assessmentHasPnpPolicyInputs(assessment) {
|
|
|
74
71
|
export function itemSettingsHavePnpPolicyInputs(settings) {
|
|
75
72
|
if (!settings)
|
|
76
73
|
return false;
|
|
77
|
-
|
|
78
|
-
settings.requiredTools.length > 0) {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
if (Array.isArray(settings.restrictedTools) &&
|
|
82
|
-
settings.restrictedTools.length > 0) {
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
if (settings.toolParameters &&
|
|
86
|
-
typeof settings.toolParameters === "object" &&
|
|
87
|
-
Object.keys(settings.toolParameters).length > 0) {
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
return false;
|
|
74
|
+
return hasEntries(settings.requiredTools) || hasEntries(settings.restrictedTools);
|
|
91
75
|
}
|
|
92
76
|
/**
|
|
93
77
|
* Resolve the auto-mode `pnpEnforcement` for one decision.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* provider veto, PNP/profile gates, and custom policy sources.
|
|
9
9
|
*/
|
|
10
10
|
/** The PNP/profile precedence rules, highest first. */
|
|
11
|
-
export type PnpPolicySourceRule = "district-block" | "test-admin-override" | "item-restriction" | "pnp-prohibited" | "item-requirement" | "district-requirement" | "pnp-support";
|
|
11
|
+
export type PnpPolicySourceRule = "district-block" | "test-admin-override" | "item-restriction" | "pnp-prohibited" | "item-requirement" | "district-requirement" | "pnp-support" | "pnp-activate-at-init";
|
|
12
12
|
/**
|
|
13
13
|
* Rule vocabulary for tool policy decisions. A decision's `rule` is the one
|
|
14
14
|
* attribution channel: it names the step that enabled, blocked or advised on a
|
|
@@ -20,7 +20,7 @@ export interface ToolPolicyResolutionDecision {
|
|
|
20
20
|
/** Monotonic step index across the entire decision log. */
|
|
21
21
|
step: number;
|
|
22
22
|
/**
|
|
23
|
-
* Precedence level. PNP/profile rules use `1`–`
|
|
23
|
+
* Precedence level. PNP/profile rules use `1`–`8`; non-profile rules use `0`
|
|
24
24
|
* for host-side gates, and a custom source, which runs after PNP/profile
|
|
25
25
|
* policy, uses its own or `100 + i` for the `i`th registered source.
|
|
26
26
|
*/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AssessmentEntity, ToolParametersFor } from "@pie-players/pie-players-shared/types";
|
|
2
|
+
import type { PnpPolicyItem } from "../sources/PnpPolicySource.js";
|
|
3
|
+
/**
|
|
4
|
+
* A tool's parameters for one decision, merged key by key: the profile's
|
|
5
|
+
* `toolParameters` entry, overridden by the assessment's, overridden by the
|
|
6
|
+
* item's.
|
|
7
|
+
*
|
|
8
|
+
* Parameters say how a tool behaves wherever policy shows it, so they reach a
|
|
9
|
+
* tool placed without a grant, and PNP enforcement does not gate them. `item` is
|
|
10
|
+
* set only for a decision about the item's own toolbar or content.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveToolParameters<K extends string>(toolId: K, assessment: AssessmentEntity | null | undefined, item: PnpPolicyItem | undefined): ToolParametersFor<K> | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function asParameters(value) {
|
|
2
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
3
|
+
? value
|
|
4
|
+
: undefined;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A tool's parameters for one decision, merged key by key: the profile's
|
|
8
|
+
* `toolParameters` entry, overridden by the assessment's, overridden by the
|
|
9
|
+
* item's.
|
|
10
|
+
*
|
|
11
|
+
* Parameters say how a tool behaves wherever policy shows it, so they reach a
|
|
12
|
+
* tool placed without a grant, and PNP enforcement does not gate them. `item` is
|
|
13
|
+
* set only for a decision about the item's own toolbar or content.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveToolParameters(toolId, assessment, item) {
|
|
16
|
+
const settings = assessment?.settings;
|
|
17
|
+
const layers = [
|
|
18
|
+
assessment?.personalNeedsProfile?.toolParameters?.[toolId],
|
|
19
|
+
settings?.toolParameters?.[toolId],
|
|
20
|
+
item?.settings.toolParameters?.[toolId],
|
|
21
|
+
]
|
|
22
|
+
.map(asParameters)
|
|
23
|
+
.filter((layer) => layer !== undefined);
|
|
24
|
+
return layers.length > 0
|
|
25
|
+
? Object.assign({}, ...layers)
|
|
26
|
+
: undefined;
|
|
27
|
+
}
|
package/dist/policy/engine.d.ts
CHANGED
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export { ToolPolicyEngine, type PnpEnforcementMode, type ResolvedEngineInputs, type ToolPolicyChangeEvent, type ToolPolicyChangeListener, type ToolPolicyEngineArgs, type ToolPolicyEngineInputs, } from "./core/ToolPolicyEngine.js";
|
|
9
9
|
export { isHostDeniedFeature, type FeaturePolicyDecision, type FeaturePolicyRule, } from "./core/feature-decision.js";
|
|
10
|
-
export type { ItemSettingNotAppliedDetails, OverrideBlockedDetails, PlacementMissingDetails, RequiredToolBlockedDetails, ToolPolicyDecision, ToolPolicyDecisionRequest, ToolPolicyDiagnostic, ToolPolicyDiagnosticCode, ToolPolicyEntry, ToolPolicyHostGate, ToolScope, UnknownSupportIdDetails, } from "./core/decision-types.js";
|
|
10
|
+
export type { ItemSettingNotAppliedDetails, OverrideBlockedDetails, PlacementMissingDetails, RequiredToolBlockedDetails, ToolPolicyDecision, ToolPolicyDecisionRequest, ToolPolicyDiagnostic, ToolPolicyDiagnosticCode, ToolPolicyDiagnosticDetails, ToolPolicyEntry, ToolPolicyHostGate, ToolScope, UnknownSupportIdDetails, } from "./core/decision-types.js";
|
|
11
11
|
export type { PolicySource, PolicySourceDecisionContext, PolicySourceProvenanceEntry, PolicySourceResult, } from "./core/PolicySource.js";
|
|
12
12
|
export type { PnpPolicySourceRule, ToolPolicyDecisionRule, ToolPolicyFeatureTrail, ToolPolicyProvenance, ToolPolicyResolutionDecision, ToolPolicySourceType, } from "./core/provenance.js";
|
|
@@ -16,12 +16,12 @@ export interface PnpPolicyToolFlags {
|
|
|
16
16
|
/** PNP/profile policy mandates this tool (item or district `requiredTools`). */
|
|
17
17
|
required: boolean;
|
|
18
18
|
/**
|
|
19
|
-
* The student's profile supports this tool, or a
|
|
20
|
-
* override grants it (host UI cannot toggle off).
|
|
19
|
+
* The student's profile supports this tool or activates it at start, or a
|
|
20
|
+
* test-administration override grants it (host UI cannot toggle off).
|
|
21
21
|
*/
|
|
22
22
|
alwaysAvailable: boolean;
|
|
23
|
-
/**
|
|
24
|
-
|
|
23
|
+
/** The student's profile lists this tool in `activateAtInit`. */
|
|
24
|
+
activateAtInit: boolean;
|
|
25
25
|
/** Which PNP/profile rule contributed the surviving verdict. */
|
|
26
26
|
rule: PnpPolicySourceRule;
|
|
27
27
|
}
|
|
@@ -60,11 +60,12 @@ export interface PnpPolicyResult {
|
|
|
60
60
|
*/
|
|
61
61
|
blockedToolIds: Set<string>;
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
63
|
+
* Tools PNP/profile policy mandates (item or district `requiredTools`), each
|
|
64
|
+
* with the requirement that names it, including a tool a `true` override
|
|
65
|
+
* decides. Used by the engine to detect `tool-policy.requiredToolBlocked`
|
|
65
66
|
* diagnostics for tools removed by host policy.
|
|
66
67
|
*/
|
|
67
|
-
|
|
68
|
+
mandates: Map<string, "item-requirement" | "district-requirement">;
|
|
68
69
|
/**
|
|
69
70
|
* Per-tool flags merged into surviving `ToolPolicyEntry`s.
|
|
70
71
|
*/
|
|
@@ -75,15 +76,6 @@ export interface PnpPolicyResult {
|
|
|
75
76
|
* support id).
|
|
76
77
|
*/
|
|
77
78
|
decisions: PnpPolicyDecisionEvent[];
|
|
78
|
-
/**
|
|
79
|
-
* Ids named by a profile, district policy, test administration or item that
|
|
80
|
-
* no tool is registered under, each with the rules whose lists name it, in
|
|
81
|
-
* precedence order. Nothing resolves them; the engine turns each into a
|
|
82
|
-
* `tool-policy.unknownSupportId` diagnostic. Empty when the registry is: an
|
|
83
|
-
* empty registry has nothing to check an id against, and
|
|
84
|
-
* `tool-config-validation` already reports it once.
|
|
85
|
-
*/
|
|
86
|
-
unmappedSupportIds: Map<string, PnpPolicySourceRule[]>;
|
|
87
79
|
/**
|
|
88
80
|
* Ids a `true` test-administration override names that an item restriction
|
|
89
81
|
* or a PNP prohibition withdrew instead, each with the rule that did. The
|
|
@@ -125,8 +117,8 @@ export declare class PnpPolicySource {
|
|
|
125
117
|
* feature: the returned result carries exactly one decision, and
|
|
126
118
|
* `decisions[0].action` is the verdict.
|
|
127
119
|
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
120
|
+
* It reuses `resolveSupport(...)` because a second copy of the eight levels
|
|
121
|
+
* would drift.
|
|
130
122
|
*/
|
|
131
123
|
resolveFeature(featureId: string, args: PnpPolicyApplyArgs): PnpPolicyResult;
|
|
132
124
|
/**
|
|
@@ -136,11 +128,13 @@ export declare class PnpPolicySource {
|
|
|
136
128
|
private prepare;
|
|
137
129
|
private resolveSupport;
|
|
138
130
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
131
|
+
* Ids the assessment or any of `items` names that no tool is registered
|
|
132
|
+
* under, each with the rules whose lists name it, in precedence order. A
|
|
133
|
+
* support id is the id of the tool it grants, so an id missing from the
|
|
134
|
+
* registry matches nothing placed; the engine turns each into a
|
|
135
|
+
* `tool-policy.unknownSupportId` diagnostic. Empty when the registry is: an
|
|
136
|
+
* empty registry has nothing to check an id against, and
|
|
137
|
+
* `tool-config-validation` already reports it once.
|
|
142
138
|
*/
|
|
143
|
-
|
|
144
|
-
/** Tool parameters: the item's entry, else the assessment's. */
|
|
145
|
-
private resolveToolSettings;
|
|
139
|
+
unknownSupportIds(assessment: AssessmentEntity | null | undefined, items: readonly ItemSettings[]): Map<string, PnpPolicySourceRule[]>;
|
|
146
140
|
}
|