@pie-players/pie-assessment-toolkit 0.3.73 → 0.3.75
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 +469 -318
- package/dist/attempt/AssessmentSession.d.ts +1 -5
- package/dist/attempt/AssessmentSession.js +0 -29
- package/dist/attempt/TestSession.d.ts +1 -20
- package/dist/attempt/TestSession.js +8 -99
- package/dist/components/ItemScope.custom-element.d.ts +1 -0
- package/dist/components/ItemScope.custom-element.js +1 -0
- package/dist/components/ItemToolBar.custom-element.d.ts +1 -0
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.d.ts +1 -0
- package/dist/components/PieAssessmentToolkit.custom-element.js +13 -13
- package/dist/components/SectionToolBar.custom-element.d.ts +1 -0
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
- package/dist/components/chunks/ItemToolBar-97hx60z4.js +2 -0
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +2 -0
- package/dist/components/chunks/ItemToolBar-jx38w99s.js +2 -0
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +40 -0
- package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
- package/dist/components/chunks/sre-engine-jd8cc08x.js +1 -0
- package/dist/components/item-scope-element.d.ts +2 -0
- package/dist/components/item-scope-element.js +2 -0
- package/dist/context/assessment-toolkit-context.d.ts +32 -6
- package/dist/index.d.ts +23 -48
- package/dist/index.js +12 -37
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +85 -34
- package/dist/policy/core/ToolPolicyEngine.js +148 -46
- package/dist/policy/core/compose-decision.d.ts +28 -7
- package/dist/policy/core/compose-decision.js +75 -54
- package/dist/policy/core/decision-types.d.ts +65 -34
- package/dist/policy/core/feature-decision.d.ts +16 -9
- package/dist/policy/core/feature-decision.js +14 -8
- package/dist/policy/core/pnp-policy-inputs.d.ts +24 -33
- package/dist/policy/core/pnp-policy-inputs.js +28 -56
- package/dist/policy/core/provenance.d.ts +9 -4
- package/dist/policy/core/provenance.js +1 -1
- package/dist/policy/engine.d.ts +7 -23
- package/dist/policy/engine.js +5 -20
- package/dist/policy/sources/PnpPolicySource.d.ts +44 -61
- package/dist/policy/sources/PnpPolicySource.js +117 -118
- package/dist/runtime/SectionControllerBinding.d.ts +279 -0
- package/dist/runtime/SectionControllerBinding.js +450 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
- package/dist/runtime/SectionRuntimeEngine.js +30 -372
- package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
- package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
- package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
- package/dist/runtime/adapter/dom-event-bridge.js +17 -44
- package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -2
- package/dist/runtime/adapter/subscriber-fanout.js +1 -2
- package/dist/runtime/catalog-context.d.ts +19 -0
- package/dist/runtime/catalog-context.js +28 -0
- package/dist/runtime/composition-emit-scheduler.d.ts +9 -15
- package/dist/runtime/composition-emit-scheduler.js +9 -15
- package/dist/runtime/content-language.d.ts +32 -0
- package/dist/runtime/content-language.js +46 -0
- package/dist/runtime/content-region.d.ts +17 -0
- package/dist/runtime/content-region.js +29 -0
- package/dist/runtime/content-registration.d.ts +13 -0
- package/dist/runtime/content-registration.js +25 -0
- package/dist/runtime/core/SectionEngineCore.d.ts +2 -2
- package/dist/runtime/core/SectionEngineCore.js +2 -2
- package/dist/runtime/core/cohort.d.ts +1 -1
- package/dist/runtime/core/cohort.js +1 -1
- package/dist/runtime/core/engine-input.d.ts +18 -30
- package/dist/runtime/core/engine-input.js +11 -12
- package/dist/runtime/core/engine-output.d.ts +16 -40
- package/dist/runtime/core/engine-output.js +9 -21
- package/dist/runtime/core/engine-readiness.d.ts +5 -37
- package/dist/runtime/core/engine-readiness.js +8 -41
- package/dist/runtime/core/engine-resolver.d.ts +46 -74
- package/dist/runtime/core/engine-resolver.js +18 -43
- package/dist/runtime/core/engine-state.d.ts +28 -36
- package/dist/runtime/core/engine-state.js +18 -21
- package/dist/runtime/core/engine-transition.d.ts +14 -19
- package/dist/runtime/core/engine-transition.js +71 -51
- package/dist/runtime/engine.d.ts +16 -19
- package/dist/runtime/engine.js +12 -19
- package/dist/runtime/page-warnings.d.ts +13 -0
- package/dist/runtime/page-warnings.js +22 -0
- package/dist/runtime/policy-input-forwarding.d.ts +25 -0
- package/dist/runtime/policy-input-forwarding.js +25 -0
- package/dist/runtime/registration-events.d.ts +14 -0
- package/dist/runtime/runtime-event-claim.d.ts +8 -0
- package/dist/runtime/runtime-event-claim.js +15 -0
- package/dist/runtime/shell-event-bridge.d.ts +45 -0
- package/dist/runtime/shell-event-bridge.js +127 -0
- package/dist/runtime/shell-registration.d.ts +73 -0
- package/dist/runtime/shell-registration.js +95 -0
- package/dist/runtime/shell-scope.d.ts +68 -0
- package/dist/runtime/shell-scope.js +188 -0
- package/dist/runtime/tool-host-contract.d.ts +28 -10
- package/dist/runtime/tool-host-contract.js +31 -10
- package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
- package/dist/runtime/unclaimed-registration-watch.js +23 -0
- package/dist/services/ElementToolStateStore.d.ts +14 -10
- package/dist/services/ElementToolStateStore.js +37 -13
- package/dist/services/HighlightCoordinator.d.ts +22 -28
- package/dist/services/HighlightCoordinator.js +431 -327
- package/dist/services/RangeSerializer.d.ts +10 -1
- package/dist/services/RangeSerializer.js +87 -14
- package/dist/services/TTSService.d.ts +130 -69
- package/dist/services/TTSService.js +713 -570
- package/dist/services/ToolCoordinator.d.ts +43 -66
- package/dist/services/ToolCoordinator.js +164 -208
- package/dist/services/ToolRegistry.d.ts +78 -54
- package/dist/services/ToolRegistry.js +107 -105
- package/dist/services/ToolkitCoordinator.d.ts +261 -175
- package/dist/services/ToolkitCoordinator.js +667 -433
- package/dist/services/audio-handoff.d.ts +6 -7
- package/dist/services/audio-handoff.js +20 -14
- package/dist/services/catalog-owner.d.ts +11 -1
- package/dist/services/catalog-owner.js +25 -0
- package/dist/services/create-tools-config.d.ts +2 -2
- package/dist/services/framework-error-bus.d.ts +3 -6
- package/dist/services/framework-error-bus.js +3 -6
- package/dist/services/framework-error.d.ts +30 -8
- package/dist/services/framework-error.js +9 -7
- package/dist/services/interfaces.d.ts +158 -129
- package/dist/services/section-controller-types.d.ts +15 -0
- package/dist/services/section-session-assignment.d.ts +21 -0
- package/dist/services/section-session-assignment.js +82 -0
- package/dist/services/spoken-audio-cards.d.ts +0 -2
- package/dist/services/spoken-audio-cards.js +1 -3
- package/dist/services/tool-config-defaults.d.ts +3 -3
- package/dist/services/tool-config-defaults.js +3 -3
- package/dist/services/tool-config-validation.d.ts +14 -4
- package/dist/services/tool-config-validation.js +63 -71
- package/dist/services/tool-context.d.ts +0 -8
- package/dist/services/tool-context.js +29 -25
- package/dist/services/tool-icons.d.ts +4 -3
- package/dist/services/tool-icons.js +4 -3
- package/dist/services/tool-instance-id.d.ts +0 -1
- package/dist/services/tool-instance-id.js +0 -6
- package/dist/services/tool-providers/TTSToolProvider.d.ts +41 -80
- package/dist/services/tool-providers/TTSToolProvider.js +81 -40
- package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +32 -28
- package/dist/services/tool-providers/ToolProviderRegistry.js +121 -107
- package/dist/services/tool-providers/index.d.ts +0 -9
- package/dist/services/tool-providers/index.js +2 -4
- package/dist/services/tool-request.d.ts +27 -12
- package/dist/services/tool-request.js +24 -14
- package/dist/services/toolbar-decided-tools.d.ts +15 -0
- package/dist/services/toolbar-decided-tools.js +28 -0
- package/dist/services/tools-config-normalizer.d.ts +37 -23
- package/dist/services/tools-config-normalizer.js +2 -10
- package/dist/services/tts/browser-provider.d.ts +38 -2
- package/dist/services/tts/browser-provider.js +276 -140
- package/dist/services/tts/catalog-span-alignment.d.ts +2 -17
- package/dist/services/tts/catalog-span-alignment.js +17 -142
- package/dist/services/tts/flat-tree.d.ts +71 -0
- package/dist/services/tts/flat-tree.js +269 -0
- package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
- package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
- package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
- package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
- package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
- package/dist/services/tts/generated-speech/types.d.ts +0 -12
- package/dist/services/tts/highlight-pipeline/boundary-normalizer.js +12 -62
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +38 -5
- package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js +3 -6
- package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
- package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
- package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
- package/dist/services/tts/math-alignment/index.d.ts +0 -5
- package/dist/services/tts/math-alignment/index.js +5 -25
- package/dist/services/tts/math-alignment/speech-tokenizer.d.ts +9 -1
- package/dist/services/tts/math-alignment/speech-tokenizer.js +38 -36
- package/dist/services/tts/math-alignment/types.d.ts +4 -2
- package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
- package/dist/services/tts/math-aware-text-processing.js +74 -18
- package/dist/services/tts/math-control-names.d.ts +21 -0
- package/dist/services/tts/math-control-names.js +142 -0
- package/dist/services/tts/math-speech.d.ts +16 -1
- package/dist/services/tts/math-speech.js +55 -19
- package/dist/services/tts/provider-options.d.ts +41 -0
- package/dist/services/tts/provider-options.js +1 -0
- package/dist/services/tts/sre-engine.d.ts +7 -0
- package/dist/services/tts/sre-engine.js +11 -0
- package/dist/services/tts/sre-locales.d.ts +14 -0
- package/dist/services/tts/sre-locales.js +57 -0
- package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
- package/dist/services/tts/ssml/spoken-text.js +29 -0
- package/dist/services/tts/start-failure.d.ts +11 -0
- package/dist/services/tts/start-failure.js +19 -0
- package/dist/services/tts/text-processing.d.ts +9 -1
- package/dist/services/tts/text-processing.js +46 -34
- package/dist/services/tts/text-segmentation.d.ts +7 -0
- package/dist/services/tts/text-segmentation.js +47 -0
- package/dist/services/tts-runtime-config.d.ts +44 -18
- package/dist/services/tts-runtime-config.js +22 -93
- package/dist/tools/content-capability-resolution.d.ts +7 -9
- package/dist/tools/content-capability-resolution.js +8 -45
- package/dist/tools/registration.d.ts +58 -0
- package/dist/tools/registration.js +54 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +2 -2
- package/dist/tools/tool-surface-host.d.ts +6 -10
- package/dist/tools/tool-surface-host.js +44 -42
- package/dist/tools/tool-tag-map.d.ts +5 -15
- package/dist/tools/tool-tag-map.js +6 -20
- package/dist/utils/structural-equality.d.ts +11 -0
- package/dist/utils/structural-equality.js +47 -0
- package/package.json +24 -59
- package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
- package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
- package/dist/components/chunks/ItemToolBar-byq80z42.js +0 -40
- package/dist/components/chunks/ItemToolBar-d36g3aw4.js +0 -49
- package/dist/context/runtime-context-consumer.d.ts +0 -13
- package/dist/context/runtime-context-consumer.js +0 -51
- package/dist/item-loader.d.ts +0 -44
- package/dist/item-loader.js +0 -61
- package/dist/policy/core/engine-context.d.ts +0 -29
- package/dist/policy/core/engine-context.js +0 -27
- package/dist/policy/core/policy-source-tag.d.ts +0 -31
- package/dist/policy/core/policy-source-tag.js +0 -28
- package/dist/policy/internal.d.ts +0 -25
- package/dist/policy/internal.js +0 -25
- package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
- package/dist/runtime/adapter/coordinator-bridge.js +0 -126
- package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
- package/dist/runtime/adapter/framework-error-bridge.js +0 -46
- package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
- package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
- package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
- package/dist/runtime/core/engine-stage-derivation.js +0 -29
- package/dist/runtime/engine-context.d.ts +0 -39
- package/dist/runtime/engine-context.js +0 -31
- package/dist/runtime/internal.d.ts +0 -43
- package/dist/runtime/internal.js +0 -45
- package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -80
- package/dist/runtime/section-runtime-engine-host-context.js +0 -95
- package/dist/runtime/stage-emit-gate.d.ts +0 -92
- package/dist/runtime/stage-emit-gate.js +0 -82
- package/dist/services/I18nService.d.ts +0 -47
- package/dist/services/I18nService.js +0 -84
- package/dist/services/ThemeProvider.d.ts +0 -95
- package/dist/services/ThemeProvider.js +0 -334
- package/dist/services/ToolConfigResolver.d.ts +0 -161
- package/dist/services/ToolConfigResolver.js +0 -229
- package/dist/services/catalog-media.d.ts +0 -56
- package/dist/services/catalog-media.js +0 -190
- package/dist/services/createDefaultToolRegistry.d.ts +0 -53
- package/dist/services/createDefaultToolRegistry.js +0 -45
- package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
- package/dist/services/defaultPersonalNeedsProfile.js +0 -26
- package/dist/services/pnp-standard-features.d.ts +0 -238
- package/dist/services/pnp-standard-features.js +0 -338
- package/dist/services/tool-providers/CortexToolProvider.d.ts +0 -13
- package/dist/services/tool-providers/CortexToolProvider.js +0 -32
- package/dist/services/tool-providers/DesmosToolProvider.d.ts +0 -14
- package/dist/services/tool-providers/DesmosToolProvider.js +0 -32
- package/dist/services/tool-providers/GeoGebraToolProvider.d.ts +0 -16
- package/dist/services/tool-providers/GeoGebraToolProvider.js +0 -32
- package/dist/services/tool-providers/LazyCalculatorToolProvider.d.ts +0 -35
- package/dist/services/tool-providers/LazyCalculatorToolProvider.js +0 -95
- package/dist/services/tts/visual-line-ranges.d.ts +0 -18
- package/dist/services/tts/visual-line-ranges.js +0 -226
- package/dist/tools/client.d.ts +0 -12
- package/dist/tools/client.js +0 -14
- package/dist/tools/index.d.ts +0 -8
- package/dist/tools/index.js +0 -10
- package/dist/tools/internal.d.ts +0 -43
- package/dist/tools/internal.js +0 -41
- package/dist/tools/response-discovery.d.ts +0 -61
- package/dist/tools/response-discovery.js +0 -113
- package/dist/tools/types.d.ts +0 -337
- package/dist/tools/types.js +0 -12
- package/dist/tools/variant-resolver.d.ts +0 -41
- package/dist/tools/variant-resolver.js +0 -207
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* `tests/policy/compose-decision.test.ts` lock the orchestration in.
|
|
13
13
|
*/
|
|
14
14
|
import { normalizeToolList, } from "../../services/tools-config-normalizer.js";
|
|
15
|
-
import { ToolPolicyProvenanceBuilder } from "./provenance.js";
|
|
15
|
+
import { ToolPolicyProvenanceBuilder, } from "./provenance.js";
|
|
16
16
|
export function composeDecision(inputs) {
|
|
17
17
|
const { request, tools, pnpPolicy, customSources, contextId } = inputs;
|
|
18
18
|
const builder = new ToolPolicyProvenanceBuilder(contextId);
|
|
@@ -103,23 +103,16 @@ export function composeDecision(inputs) {
|
|
|
103
103
|
});
|
|
104
104
|
// Step 5 — PNP/profile policy gates.
|
|
105
105
|
const diagnostics = [];
|
|
106
|
-
|
|
107
|
-
for
|
|
108
|
-
sourcesByTool.set(toolId, ["placement"]);
|
|
109
|
-
}
|
|
110
|
-
// Snapshot the post-host candidate set so step 5b can distinguish
|
|
111
|
-
// "host removed a required tool" (requiredToolBlocked fires)
|
|
112
|
-
// from "profile policy's own precedence removed a required tool" (fix
|
|
113
|
-
// per M8 PR 1 R1 S1 — multi-rule conflict on the same tool must
|
|
114
|
-
// not blame the host).
|
|
106
|
+
// Snapshot the post-host candidate set so step 5b reports
|
|
107
|
+
// requiredToolBlocked only for a mandated tool the host removed.
|
|
115
108
|
const postHostCandidates = new Set(candidates);
|
|
116
109
|
let pnpPolicyResult = null;
|
|
117
110
|
if (pnpPolicy.enforcement === "on" &&
|
|
118
111
|
pnpPolicy.source &&
|
|
119
|
-
(pnpPolicy.assessment || pnpPolicy.
|
|
112
|
+
(pnpPolicy.assessment || pnpPolicy.item)) {
|
|
120
113
|
pnpPolicyResult = pnpPolicy.source.apply({
|
|
121
114
|
assessment: pnpPolicy.assessment,
|
|
122
|
-
|
|
115
|
+
item: pnpPolicy.item,
|
|
123
116
|
});
|
|
124
117
|
if (pnpPolicyResult.sources.assessment) {
|
|
125
118
|
builder.addSource("assessment", pnpPolicyResult.sources.assessment);
|
|
@@ -141,29 +134,19 @@ export function composeDecision(inputs) {
|
|
|
141
134
|
value: decision.value,
|
|
142
135
|
});
|
|
143
136
|
}
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
level: request.level,
|
|
153
|
-
toolId: supportId,
|
|
154
|
-
message: `No registered tool claims PNP support id "${supportId}"; it was carried through as a feature id and matched nothing. Expected an AfA 3.0 / QTI 3.0 access feature id.`,
|
|
155
|
-
source: "pnp.pnp-support",
|
|
156
|
-
});
|
|
137
|
+
// An id no tool is registered under matches nothing placed, so whatever it
|
|
138
|
+
// names is absent with no trace of why. Reported per decision because the
|
|
139
|
+
// ids arrive with the profile and settings, after the tools config.
|
|
140
|
+
for (const [supportId, origins] of pnpPolicyResult.unmappedSupportIds) {
|
|
141
|
+
diagnostics.push(unknownSupportIdDiagnostic(supportId, origins, request.level));
|
|
142
|
+
}
|
|
143
|
+
for (const [toolId, rule] of pnpPolicyResult.blockedOverrides) {
|
|
144
|
+
diagnostics.push(overrideBlockedDiagnostic(toolId, rule, request.level));
|
|
157
145
|
}
|
|
158
146
|
// 5a — remove PNP/profile-blocked tools from the candidate set.
|
|
159
147
|
candidates = candidates.filter((toolId) => {
|
|
160
148
|
return !pnpPolicyResult.blockedToolIds.has(toolId);
|
|
161
149
|
});
|
|
162
|
-
for (const toolId of Array.from(sourcesByTool.keys())) {
|
|
163
|
-
if (pnpPolicyResult.blockedToolIds.has(toolId)) {
|
|
164
|
-
sourcesByTool.delete(toolId);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
150
|
// 5b — surface requiredToolBlocked diagnostics ONLY for
|
|
168
151
|
// PNP/profile-mandated tools that the host removed (i.e., the tool was
|
|
169
152
|
// NOT in `postHostCandidates`). Mandated tools removed by
|
|
@@ -211,15 +194,6 @@ export function composeDecision(inputs) {
|
|
|
211
194
|
value: details,
|
|
212
195
|
});
|
|
213
196
|
}
|
|
214
|
-
// 5c — attach PNP policy source tags to surviving entries.
|
|
215
|
-
for (const toolId of candidates) {
|
|
216
|
-
const flag = pnpPolicyResult.perToolFlags.get(toolId);
|
|
217
|
-
if (flag) {
|
|
218
|
-
const tags = sourcesByTool.get(toolId) ?? [];
|
|
219
|
-
tags.push(`pnp.${flag.rule}`);
|
|
220
|
-
sourcesByTool.set(toolId, tags);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
197
|
}
|
|
224
198
|
// Step 6 — Custom PolicySources.
|
|
225
199
|
for (let i = 0; i < customSources.length; i++) {
|
|
@@ -238,7 +212,7 @@ export function composeDecision(inputs) {
|
|
|
238
212
|
level: request.level,
|
|
239
213
|
toolId,
|
|
240
214
|
message: `Custom source "${source.id}" tried to add tool "${toolId}" that was not in candidates; ignored.`,
|
|
241
|
-
|
|
215
|
+
details: { customSourceId: source.id },
|
|
242
216
|
});
|
|
243
217
|
refinedSet.delete(toolId);
|
|
244
218
|
}
|
|
@@ -250,7 +224,7 @@ export function composeDecision(inputs) {
|
|
|
250
224
|
// this auto-log, the provenance trail for a silently-removed
|
|
251
225
|
// tool would show only the prior `enable` decisions and the
|
|
252
226
|
// final-state reconciliation would have no evidence to mark it
|
|
253
|
-
// `blocked
|
|
227
|
+
// `blocked`.
|
|
254
228
|
const explicitBlocks = new Set();
|
|
255
229
|
if (result.decisions) {
|
|
256
230
|
for (const event of result.decisions) {
|
|
@@ -284,18 +258,27 @@ export function composeDecision(inputs) {
|
|
|
284
258
|
value: { customSourceId: source.id },
|
|
285
259
|
});
|
|
286
260
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
261
|
+
}
|
|
262
|
+
// Step 7 — item settings a shared toolbar does not apply. Placement is the
|
|
263
|
+
// host's section-wide choice, so the tool stays; the diagnostic says where to
|
|
264
|
+
// place it for the item setting to hold.
|
|
265
|
+
for (const toolId of candidates) {
|
|
266
|
+
for (const item of inputs.unappliedItems ?? []) {
|
|
267
|
+
const settings = ["restrictedTools", "requiredTools"].filter((key) => item.settings[key]?.includes(toolId) === true);
|
|
268
|
+
if (settings.length === 0)
|
|
269
|
+
continue;
|
|
270
|
+
const details = {
|
|
271
|
+
itemId: item.id,
|
|
272
|
+
settings,
|
|
273
|
+
toolbarLevel: request.scope.level,
|
|
274
|
+
};
|
|
275
|
+
diagnostics.push({
|
|
276
|
+
code: "tool-policy.itemSettingNotApplied",
|
|
277
|
+
level: request.level,
|
|
278
|
+
toolId,
|
|
279
|
+
message: `Item "${item.id}" names "${toolId}" in ${settings.join(" and ")}, but "${toolId}" is on the ${request.scope.level}-level toolbar, which item settings do not reach. Place "${toolId}" at item level to enforce the setting per item.`,
|
|
280
|
+
details,
|
|
281
|
+
});
|
|
299
282
|
}
|
|
300
283
|
}
|
|
301
284
|
const survivingIds = new Set(candidates);
|
|
@@ -306,7 +289,6 @@ export function composeDecision(inputs) {
|
|
|
306
289
|
required: flag?.required ?? false,
|
|
307
290
|
alwaysAvailable: flag?.alwaysAvailable ?? false,
|
|
308
291
|
settings: flag?.settings,
|
|
309
|
-
sources: sourcesByTool.get(toolId) ?? ["placement"],
|
|
310
292
|
};
|
|
311
293
|
});
|
|
312
294
|
builder.reconcileFinalStates(survivingIds);
|
|
@@ -346,3 +328,42 @@ function detectHostRemovalGate(toolId, args) {
|
|
|
346
328
|
// pipeline has a bug; surface a best-effort rather than throwing.
|
|
347
329
|
return { hostRule: "placement-missing", hostValue: args.placement };
|
|
348
330
|
}
|
|
331
|
+
/** Where each PNP/profile rule's ids are authored. */
|
|
332
|
+
const PNP_RULE_FIELDS = {
|
|
333
|
+
"district-block": "settings.districtPolicy.blockedTools",
|
|
334
|
+
"test-admin-override": "settings.testAdministration.toolOverrides",
|
|
335
|
+
"item-restriction": "item settings.restrictedTools",
|
|
336
|
+
"pnp-prohibited": "personalNeedsProfile.prohibitedSupports",
|
|
337
|
+
"item-requirement": "item settings.requiredTools",
|
|
338
|
+
"district-requirement": "settings.districtPolicy.requiredTools",
|
|
339
|
+
"pnp-support": "personalNeedsProfile.supports",
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
342
|
+
* A `tool-policy.overrideBlocked` diagnostic for a tool a `true` test
|
|
343
|
+
* administration override grants and `rule` withdraws. `level` is absent on a
|
|
344
|
+
* feature decision, which has no toolbar level.
|
|
345
|
+
*/
|
|
346
|
+
export function overrideBlockedDiagnostic(toolId, rule, level) {
|
|
347
|
+
return {
|
|
348
|
+
code: "tool-policy.overrideBlocked",
|
|
349
|
+
...(level ? { level } : {}),
|
|
350
|
+
toolId,
|
|
351
|
+
message: `settings.testAdministration.toolOverrides grants "${toolId}", but ${PNP_RULE_FIELDS[rule]} withdraws it and outranks a granting override.`,
|
|
352
|
+
details: { rule },
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* A `tool-policy.unknownSupportId` diagnostic for an id the registry lacks,
|
|
357
|
+
* attributed to the highest-precedence rule naming it. `level` is absent on a
|
|
358
|
+
* feature decision, which has no toolbar level.
|
|
359
|
+
*/
|
|
360
|
+
export function unknownSupportIdDiagnostic(supportId, origins, level) {
|
|
361
|
+
const fields = origins.map((rule) => PNP_RULE_FIELDS[rule]).join(", ");
|
|
362
|
+
return {
|
|
363
|
+
code: "tool-policy.unknownSupportId",
|
|
364
|
+
...(level ? { level } : {}),
|
|
365
|
+
toolId: supportId,
|
|
366
|
+
message: `No tool is registered under "${supportId}", named in ${fields}, so it matches nothing. These lists name tools by tool id.`,
|
|
367
|
+
details: { origins: [...origins] },
|
|
368
|
+
};
|
|
369
|
+
}
|
|
@@ -11,16 +11,15 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { ToolPlacementLevel } from "../../services/tools-config-normalizer.js";
|
|
13
13
|
import type { ToolContext, ToolLevel } from "../../services/tool-context.js";
|
|
14
|
-
import type {
|
|
15
|
-
import type { ToolPolicyProvenance } from "./provenance.js";
|
|
14
|
+
import type { PnpPolicySourceRule, ToolPolicyProvenance } from "./provenance.js";
|
|
16
15
|
/**
|
|
17
16
|
* Scope identifier for a `decide(...)` request. The engine uses
|
|
18
17
|
* `level` to pick which placement bucket to read; `scopeId` is opaque
|
|
19
18
|
* to the engine (it is round-tripped into provenance for human-readable
|
|
20
19
|
* trails) and is typically the section-id, item-id, or passage-id of
|
|
21
20
|
* the surface asking the question. `contentKind` mirrors the
|
|
22
|
-
* `ToolbarContext.scope.contentKind` field
|
|
23
|
-
*
|
|
21
|
+
* `ToolbarContext.scope.contentKind` field `<pie-item-toolbar>` reads for
|
|
22
|
+
* content relevance.
|
|
24
23
|
*/
|
|
25
24
|
export interface ToolScope {
|
|
26
25
|
level: ToolLevel;
|
|
@@ -41,29 +40,44 @@ export interface ToolPolicyDecisionRequest {
|
|
|
41
40
|
level: ToolPlacementLevel;
|
|
42
41
|
scope: ToolScope;
|
|
43
42
|
/**
|
|
44
|
-
* Optional
|
|
45
|
-
* `isVisibleInContext(...)
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* `PolicySource` instances so they can refine the candidate set
|
|
49
|
-
* if they need to.
|
|
43
|
+
* Optional tool context. The engine does not call
|
|
44
|
+
* `isVisibleInContext(...)`: content relevance is applied at the toolbar
|
|
45
|
+
* boundary. The context is forwarded to custom `PolicySource` instances so
|
|
46
|
+
* they can refine the candidate set.
|
|
50
47
|
*/
|
|
51
48
|
context?: ToolContext;
|
|
52
49
|
}
|
|
53
50
|
/**
|
|
54
|
-
* Diagnostic codes the engine may emit alongside a decision.
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* `district.requiredTools` mandates.
|
|
51
|
+
* Diagnostic codes the engine may emit alongside a decision.
|
|
52
|
+
* `tool-policy.requiredToolBlocked` fires when a host policy gate
|
|
53
|
+
* (`policy.blocked`, missing-from-`placement`, provider veto) removed a tool
|
|
54
|
+
* that item or district `requiredTools` mandates.
|
|
59
55
|
*
|
|
60
56
|
* `tool-policy.placementMissing` fires when a custom `PolicySource`
|
|
61
57
|
* references a tool ID that is not present in `tools.placement[level]`
|
|
62
|
-
* for the resolved level.
|
|
58
|
+
* for the resolved level. `details` is {@link PlacementMissingDetails}.
|
|
59
|
+
* The host-side `ToolConfigDiagnostic` channel
|
|
63
60
|
* (already used by `tool-config-validation.ts`) covers config-time
|
|
64
61
|
* misconfiguration; this channel covers per-decision conflicts.
|
|
62
|
+
*
|
|
63
|
+
* `tool-policy.unknownSupportId` fires for each id a profile, district
|
|
64
|
+
* policy, test administration or item names that no tool is registered under.
|
|
65
|
+
* `details` is {@link UnknownSupportIdDetails}.
|
|
66
|
+
*
|
|
67
|
+
* `tool-policy.itemSettingNotApplied` fires on a section-, assessment- or
|
|
68
|
+
* passage-level decision for each tool on that toolbar a mounted item's
|
|
69
|
+
* `restrictedTools` or `requiredTools` names, once per tool and item: item
|
|
70
|
+
* settings govern only the item's own toolbar. `details` is
|
|
71
|
+
* {@link ItemSettingNotAppliedDetails}.
|
|
72
|
+
*
|
|
73
|
+
* `tool-policy.overrideBlocked` fires for each tool a `true`
|
|
74
|
+
* `settings.testAdministration.toolOverrides` entry grants that an item's
|
|
75
|
+
* `restrictedTools` or the profile's `prohibitedSupports` withdraws instead.
|
|
76
|
+
* `details` is {@link OverrideBlockedDetails}.
|
|
77
|
+
*
|
|
78
|
+
* The toolkit coordinator logs each diagnostic once per code, tool and item.
|
|
65
79
|
*/
|
|
66
|
-
export type ToolPolicyDiagnosticCode = "tool-policy.requiredToolBlocked" | "tool-policy.placementMissing" | "tool-policy.unknownSupportId";
|
|
80
|
+
export type ToolPolicyDiagnosticCode = "tool-policy.requiredToolBlocked" | "tool-policy.placementMissing" | "tool-policy.unknownSupportId" | "tool-policy.itemSettingNotApplied" | "tool-policy.overrideBlocked";
|
|
67
81
|
/**
|
|
68
82
|
* Which host gate removed a profile-mandated tool. Surfaced inside
|
|
69
83
|
* `ToolPolicyDiagnostic.details` for `tool-policy.requiredToolBlocked`
|
|
@@ -94,29 +108,53 @@ export interface RequiredToolBlockedDetails extends Record<string, unknown> {
|
|
|
94
108
|
/** The host configuration value that triggered the gate (best-effort, may be omitted). */
|
|
95
109
|
hostValue?: unknown;
|
|
96
110
|
}
|
|
111
|
+
/** Payload of a `tool-policy.unknownSupportId` diagnostic. */
|
|
112
|
+
export interface UnknownSupportIdDetails extends Record<string, unknown> {
|
|
113
|
+
/** The rules whose lists name the id, in precedence order. */
|
|
114
|
+
origins: PnpPolicySourceRule[];
|
|
115
|
+
}
|
|
116
|
+
/** Payload of a `tool-policy.placementMissing` diagnostic. */
|
|
117
|
+
export interface PlacementMissingDetails extends Record<string, unknown> {
|
|
118
|
+
/** The custom `PolicySource` that named the tool. */
|
|
119
|
+
customSourceId: string;
|
|
120
|
+
}
|
|
121
|
+
/** Payload of a `tool-policy.overrideBlocked` diagnostic. */
|
|
122
|
+
export interface OverrideBlockedDetails extends Record<string, unknown> {
|
|
123
|
+
/** The rule that withdrew the granted tool. */
|
|
124
|
+
rule: "item-restriction" | "pnp-prohibited";
|
|
125
|
+
}
|
|
126
|
+
/** Payload of a `tool-policy.itemSettingNotApplied` diagnostic. */
|
|
127
|
+
export interface ItemSettingNotAppliedDetails extends Record<string, unknown> {
|
|
128
|
+
/** Canonical id of the item whose setting names the tool. */
|
|
129
|
+
itemId: string;
|
|
130
|
+
/** The item settings that name it. */
|
|
131
|
+
settings: Array<"restrictedTools" | "requiredTools">;
|
|
132
|
+
/** The level of the toolbar the tool is on. */
|
|
133
|
+
toolbarLevel: ToolLevel;
|
|
134
|
+
}
|
|
97
135
|
export interface ToolPolicyDiagnostic {
|
|
98
136
|
code: ToolPolicyDiagnosticCode;
|
|
99
|
-
level
|
|
137
|
+
/** The toolbar level decided; absent on a feature decision. */
|
|
138
|
+
level?: ToolPlacementLevel;
|
|
100
139
|
toolId: string;
|
|
101
140
|
message: string;
|
|
102
|
-
source?: PolicySourceTag;
|
|
103
141
|
details?: Record<string, unknown>;
|
|
104
142
|
}
|
|
105
143
|
export interface ToolPolicyEntry {
|
|
106
144
|
toolId: string;
|
|
107
145
|
/**
|
|
108
146
|
* `true` when PNP/profile policy mandates this tool (item or district
|
|
109
|
-
* `requiredTools
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* those should listen on the diagnostic channel.
|
|
147
|
+
* `requiredTools`). Advisory mandates that the host blocked do *not*
|
|
148
|
+
* surface here — they appear in `diagnostics` instead. Hosts that need
|
|
149
|
+
* to know about those should listen on the diagnostic channel.
|
|
113
150
|
*/
|
|
114
151
|
required: boolean;
|
|
115
152
|
/**
|
|
116
|
-
* `true` for PNP `supports`
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
153
|
+
* `true` for a tool the student's PNP `supports` or a
|
|
154
|
+
* `testAdministration.toolOverrides` entry grants — UI-level signal that
|
|
155
|
+
* the host cannot toggle this tool off in user preferences. Does NOT
|
|
156
|
+
* override host blocks (they would have removed the entry before this
|
|
157
|
+
* flag is read).
|
|
120
158
|
*/
|
|
121
159
|
alwaysAvailable: boolean;
|
|
122
160
|
/**
|
|
@@ -126,13 +164,6 @@ export interface ToolPolicyEntry {
|
|
|
126
164
|
* the assessment entity from above the engine.
|
|
127
165
|
*/
|
|
128
166
|
settings?: unknown;
|
|
129
|
-
/**
|
|
130
|
-
* Every contributor that helped this entry survive the
|
|
131
|
-
* composition pipeline. Always non-empty — at minimum
|
|
132
|
-
* `["placement"]` for any entry that came from
|
|
133
|
-
* `tools.placement[level]`.
|
|
134
|
-
*/
|
|
135
|
-
sources: PolicySourceTag[];
|
|
136
167
|
}
|
|
137
168
|
export interface ToolPolicyDecision {
|
|
138
169
|
visibleTools: ToolPolicyEntry[];
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
* reasons, and only the second is a defect.
|
|
22
22
|
*/
|
|
23
23
|
import type { PnpPolicyResult } from "../sources/PnpPolicySource.js";
|
|
24
|
-
import type {
|
|
25
|
-
import type { ToolPolicyResolutionDecision, ToolPolicySourceType } from "./provenance.js";
|
|
24
|
+
import type { ToolPolicyDiagnostic } from "./decision-types.js";
|
|
25
|
+
import type { PnpPolicySourceRule, ToolPolicyResolutionDecision, ToolPolicySourceType } from "./provenance.js";
|
|
26
26
|
/**
|
|
27
|
-
* A feature verdict comes from one of the
|
|
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
30
|
* on the placement-scoped path.
|
|
@@ -34,7 +34,7 @@ export interface FeaturePolicyDecision {
|
|
|
34
34
|
/** The PNP/AfA support id that was evaluated (e.g. `"signLanguage"`). */
|
|
35
35
|
featureId: string;
|
|
36
36
|
/**
|
|
37
|
-
* `true` only when policy explicitly granted the feature at one of the
|
|
37
|
+
* `true` only when policy explicitly granted the feature at one of the eight
|
|
38
38
|
* precedence levels. A feature nobody configured is **not** available —
|
|
39
39
|
* accommodations require a documented need, so silence means no.
|
|
40
40
|
*/
|
|
@@ -42,7 +42,7 @@ export interface FeaturePolicyDecision {
|
|
|
42
42
|
action: ToolPolicyResolutionDecision["action"];
|
|
43
43
|
/** Which precedence rule produced the verdict. */
|
|
44
44
|
rule: FeaturePolicyRule;
|
|
45
|
-
precedence: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
45
|
+
precedence: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
|
46
46
|
sourceType: ToolPolicySourceType;
|
|
47
47
|
/** Human-readable explanation, suitable for a policy debugger. */
|
|
48
48
|
reason: string;
|
|
@@ -51,9 +51,10 @@ export interface FeaturePolicyDecision {
|
|
|
51
51
|
*
|
|
52
52
|
* `false` makes a *denial* a wiring gap rather than a verdict: no profile,
|
|
53
53
|
* district policy or test administration could be consulted, because there was
|
|
54
|
-
* no assessment to read them from. It is not itself a denial — an item
|
|
55
|
-
* carrying `requiredTools`
|
|
56
|
-
* assessment bound — so read it alongside `granted` rather than
|
|
54
|
+
* no assessment to read them from. It is not itself a denial — an item's
|
|
55
|
+
* registered settings carrying `requiredTools` mandate a feature at precedence
|
|
56
|
+
* 6 with no assessment bound — so read it alongside `granted` rather than
|
|
57
|
+
* instead of it.
|
|
57
58
|
*
|
|
58
59
|
* Granting is unaffected either way: an unbound host with no item mandate still
|
|
59
60
|
* gets `granted: false`, since an accommodation requires a documented need and
|
|
@@ -66,7 +67,7 @@ export interface FeaturePolicyDecision {
|
|
|
66
67
|
assessmentBound: boolean;
|
|
67
68
|
/**
|
|
68
69
|
* `true` when the grant is a mandate (item or district `requiredTools`)
|
|
69
|
-
* rather than a student-profile support.
|
|
70
|
+
* rather than a student-profile support or a test-administration override.
|
|
70
71
|
*/
|
|
71
72
|
required: boolean;
|
|
72
73
|
/**
|
|
@@ -75,6 +76,12 @@ export interface FeaturePolicyDecision {
|
|
|
75
76
|
* presentation would hang on; no vocabulary is defined yet.
|
|
76
77
|
*/
|
|
77
78
|
parameters?: unknown;
|
|
79
|
+
/**
|
|
80
|
+
* Conflicts found while deciding: a `tool-policy.unknownSupportId` for each
|
|
81
|
+
* id the bound inputs name that no tool is registered under. Empty on a host
|
|
82
|
+
* denial, which consults no policy source.
|
|
83
|
+
*/
|
|
84
|
+
diagnostics: ToolPolicyDiagnostic[];
|
|
78
85
|
}
|
|
79
86
|
/** What the engine knows that a single support-id resolution does not. */
|
|
80
87
|
export interface FeatureDecisionContext {
|
|
@@ -20,13 +20,14 @@
|
|
|
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, unknownSupportIdDiagnostic, } from "./compose-decision.js";
|
|
23
24
|
/**
|
|
24
25
|
* Reason text for a denial that had no assessment to decide against.
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
-
* true but reads as a completed evaluation. `rule` and `precedence`
|
|
28
|
-
* source reported them: nothing fired, so naming a
|
|
29
|
-
* a precedence level that does not exist.
|
|
27
|
+
* Used in place of the `pnp-support` skip's "not configured at any level",
|
|
28
|
+
* which is true but reads as a completed evaluation. `rule` and `precedence`
|
|
29
|
+
* stay as the source reported them: nothing fired, so naming a ninth rule
|
|
30
|
+
* would describe a precedence level that does not exist.
|
|
30
31
|
*/
|
|
31
32
|
const unboundAssessmentReason = (featureId) => `No assessment is bound, so no policy source could grant "${featureId}"`;
|
|
32
33
|
/**
|
|
@@ -51,6 +52,7 @@ export function hostFeatureDenial(featureId, rule, hostValue, context) {
|
|
|
51
52
|
: `Not listed in tools.policy.allowed (${hostValue.join(", ")})`,
|
|
52
53
|
required: false,
|
|
53
54
|
assessmentBound: context.assessmentBound,
|
|
55
|
+
diagnostics: [],
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
58
|
/**
|
|
@@ -81,17 +83,21 @@ export function interpretFeatureResult(featureId, result, context) {
|
|
|
81
83
|
granted,
|
|
82
84
|
action: decision?.action ?? "skip",
|
|
83
85
|
rule: decision?.rule ?? "pnp-support",
|
|
84
|
-
precedence: decision?.precedence ??
|
|
86
|
+
precedence: decision?.precedence ?? 8,
|
|
85
87
|
sourceType: decision?.sourceType ?? "system",
|
|
86
88
|
// Only a denial is re-worded. An unbound host can still be granted the
|
|
87
|
-
// feature — an item
|
|
88
|
-
// with no assessment in sight — and there the source's
|
|
89
|
-
// one.
|
|
89
|
+
// feature — an item's registered settings carrying `requiredTools` mandate
|
|
90
|
+
// it at precedence 6 with no assessment in sight — and there the source's
|
|
91
|
+
// reason is the true one.
|
|
90
92
|
reason: context.assessmentBound || granted
|
|
91
93
|
? reason
|
|
92
94
|
: unboundAssessmentReason(featureId),
|
|
93
95
|
required: Boolean(flags?.required),
|
|
94
96
|
parameters: flags?.settings,
|
|
95
97
|
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
|
+
],
|
|
96
102
|
};
|
|
97
103
|
}
|
|
@@ -2,64 +2,55 @@
|
|
|
2
2
|
* PNP/profile policy input detection. See
|
|
3
3
|
* `docs/tools-and-accomodations/architecture.md`.
|
|
4
4
|
*
|
|
5
|
-
* Pure helpers that decide whether
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* `pnpEnforcement` when the host did not pass an explicit `"on"` /
|
|
10
|
-
* `"off"`.
|
|
11
|
-
* - {@link ToolkitCoordinator.resolveEffectivePnpEnforcement} as the
|
|
12
|
-
* auto-mode rule. PR 2 used a coarse "any non-null assessment → on"
|
|
13
|
-
* placeholder; PR 4 narrows it to "assessment OR currentItemRef
|
|
14
|
-
* carries profile policy material."
|
|
5
|
+
* Pure helpers that decide whether policy inputs carry PNP/profile policy
|
|
6
|
+
* material, which is what auto-mode `pnpEnforcement` turns on for. The engine
|
|
7
|
+
* resolves auto-mode per decision: the bound assessment for every decision, and
|
|
8
|
+
* for a decision scoped to an item, that item's settings as well.
|
|
15
9
|
*
|
|
16
10
|
* The rule is intentionally narrow. Hosts that bind a bare assessment
|
|
17
11
|
* record (only `id` / `name`, no PNP and no settings) do not engage
|
|
18
12
|
* PNP/profile gates. The flip happens the moment the assessment carries any of:
|
|
19
13
|
*
|
|
20
|
-
* - `personalNeedsProfile` (any `supports
|
|
21
|
-
*
|
|
22
|
-
* - `settings.
|
|
23
|
-
*
|
|
24
|
-
* - `settings.testAdministration` (any populated key — `mode`,
|
|
25
|
-
* `toolOverrides`, etc.),
|
|
26
|
-
* - or the bound `currentItemRef.settings` carries
|
|
14
|
+
* - `personalNeedsProfile` (any `supports` or `prohibitedSupports`),
|
|
15
|
+
* - `settings.districtPolicy` (any `blockedTools` or `requiredTools`),
|
|
16
|
+
* - `settings.testAdministration` (any `toolOverrides` entry),
|
|
17
|
+
* - or, for an item-scoped decision, the item's settings carry
|
|
27
18
|
* `requiredTools` / `restrictedTools` / `toolParameters`.
|
|
28
19
|
*
|
|
29
20
|
* Hosts opt out of the auto-on behavior by passing
|
|
30
21
|
* `pnpEnforcement: "off"` explicitly (engine input or
|
|
31
22
|
* `ToolkitCoordinator.setPnpEnforcement("off")`).
|
|
32
23
|
*/
|
|
33
|
-
import type { AssessmentEntity,
|
|
24
|
+
import type { AssessmentEntity, ItemSettings } from "@pie-players/pie-players-shared/types";
|
|
34
25
|
/**
|
|
35
26
|
* Return `true` when the assessment carries any PNP/profile policy
|
|
36
27
|
* material that the engine's `PnpPolicySource` would consume.
|
|
37
28
|
*
|
|
38
|
-
* The check is structural —
|
|
39
|
-
*
|
|
40
|
-
* have to validate against any specific rule.
|
|
29
|
+
* The check is structural — a non-empty field the source reads is enough;
|
|
30
|
+
* the content does not have to validate against any specific rule.
|
|
41
31
|
*/
|
|
42
32
|
export declare function assessmentHasPnpPolicyInputs(assessment: AssessmentEntity | null | undefined): boolean;
|
|
43
33
|
/**
|
|
44
|
-
* Return `true` when
|
|
34
|
+
* Return `true` when an item's settings carry item-level profile policy
|
|
45
35
|
* material (`requiredTools`, `restrictedTools`, or `toolParameters`).
|
|
46
36
|
*
|
|
47
|
-
* Used in addition to {@link assessmentHasPnpPolicyInputs}
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
37
|
+
* Used in addition to {@link assessmentHasPnpPolicyInputs} for a decision scoped
|
|
38
|
+
* to the item, so an item with profile-relevant settings engages PNP/profile
|
|
39
|
+
* gates on its own toolbar without a parent assessment carrying a
|
|
40
|
+
* PNP/district/test-admin block.
|
|
51
41
|
*/
|
|
52
|
-
export declare function
|
|
42
|
+
export declare function itemSettingsHavePnpPolicyInputs(settings: ItemSettings | null | undefined): boolean;
|
|
53
43
|
/**
|
|
54
|
-
* Resolve the
|
|
44
|
+
* Resolve the auto-mode `pnpEnforcement` for one decision.
|
|
55
45
|
*
|
|
56
|
-
* Returns `"on"` when {@link assessmentHasPnpPolicyInputs}
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* `
|
|
46
|
+
* Returns `"on"` when {@link assessmentHasPnpPolicyInputs} reports profile
|
|
47
|
+
* policy material, or when `itemSettings` (the settings of the item a decision
|
|
48
|
+
* is scoped to) do per {@link itemSettingsHavePnpPolicyInputs}; otherwise
|
|
49
|
+
* `"off"`. Hosts override the default by passing an explicit `pnpEnforcement`
|
|
50
|
+
* value (engine input) or by calling
|
|
60
51
|
* `ToolkitCoordinator.setPnpEnforcement("on" | "off")`.
|
|
61
52
|
*/
|
|
62
53
|
export declare function resolveDefaultPnpEnforcement(args: {
|
|
63
54
|
assessment?: AssessmentEntity | null;
|
|
64
|
-
|
|
55
|
+
itemSettings?: ItemSettings | null;
|
|
65
56
|
}): "on" | "off";
|