@phyzess/pappra 0.1.0-beta.13 → 0.1.0-beta.18
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 +134 -15
- package/assets/integrations/skills/pappra/SKILL.md +28 -7
- package/assets/integrations/skills/pappra/references/collaboration.md +633 -0
- package/assets/integrations/skills/pappra/references/environment.md +360 -0
- package/assets/integrations/skills/pappra/references/hosts.md +20 -0
- package/assets/integrations/skills/pappra/references/operations.md +36 -5
- package/dist/adapters/pi/recovery-extension.d.ts +65 -0
- package/dist/adapters/pi/recovery-extension.js +238 -0
- package/dist/adapters/pi/session-transition-extension.d.ts +30 -0
- package/dist/adapters/pi/session-transition-extension.js +265 -0
- package/dist/app/automatic-handoff-events.d.ts +26 -0
- package/dist/app/automatic-handoff-events.js +134 -0
- package/dist/app/bounded-file.d.ts +2 -0
- package/dist/app/bounded-file.js +2 -0
- package/dist/app/capability-evidence/claude.d.ts +37 -0
- package/dist/app/capability-evidence/claude.js +206 -0
- package/dist/app/capability-evidence/codex.d.ts +35 -0
- package/dist/app/capability-evidence/codex.js +193 -0
- package/dist/app/capability-evidence/index.d.ts +33 -0
- package/dist/app/capability-evidence/index.js +117 -0
- package/dist/app/capability-evidence/pi.d.ts +73 -0
- package/dist/app/capability-evidence/pi.js +669 -0
- package/dist/app/capability-evidence/shared.d.ts +69 -0
- package/dist/app/capability-evidence/shared.js +195 -0
- package/dist/app/collab-auto-handoff.d.ts +55 -0
- package/dist/app/collab-auto-handoff.js +384 -0
- package/dist/app/collab-bindings.d.ts +57 -0
- package/dist/app/collab-bindings.js +1006 -0
- package/dist/app/collab-bootstrap-transport.d.ts +163 -0
- package/dist/app/collab-bootstrap-transport.js +769 -0
- package/dist/app/collab-bootstrap.d.ts +137 -0
- package/dist/app/collab-bootstrap.js +3455 -0
- package/dist/app/collab-handoff.d.ts +12 -0
- package/dist/app/collab-handoff.js +511 -0
- package/dist/app/collab-messages.d.ts +2 -0
- package/dist/app/collab-messages.js +2 -0
- package/dist/app/collab-notify.d.ts +156 -0
- package/dist/app/collab-notify.js +1208 -0
- package/dist/app/collab-preflight.d.ts +34 -0
- package/dist/app/collab-preflight.js +96 -0
- package/dist/app/collab-recovery-executor.d.ts +161 -0
- package/dist/app/collab-recovery-executor.js +1153 -0
- package/dist/app/collab-recovery-projection.d.ts +103 -0
- package/dist/app/collab-recovery-projection.js +659 -0
- package/dist/app/collab-recovery.d.ts +25 -0
- package/dist/app/collab-recovery.js +429 -0
- package/dist/app/collab-resources.d.ts +16 -0
- package/dist/app/collab-resources.js +278 -0
- package/dist/app/collab-role-events.d.ts +22 -0
- package/dist/app/collab-role-events.js +329 -0
- package/dist/app/collab-role-orchestration.d.ts +53 -0
- package/dist/app/collab-role-orchestration.js +601 -0
- package/dist/app/collab-role-plan.d.ts +81 -0
- package/dist/app/collab-role-plan.js +504 -0
- package/dist/app/collab-role-repair.d.ts +109 -0
- package/dist/app/collab-role-repair.js +821 -0
- package/dist/app/collab-rollover.d.ts +263 -0
- package/dist/app/collab-rollover.js +1112 -0
- package/dist/app/collab-route.d.ts +64 -0
- package/dist/app/collab-route.js +240 -0
- package/dist/app/collab-session-transition.d.ts +221 -0
- package/dist/app/collab-session-transition.js +3334 -0
- package/dist/app/collab-state.d.ts +7 -0
- package/dist/app/collab-state.js +162 -0
- package/dist/app/collab-task-store.d.ts +22 -0
- package/dist/app/collab-task-store.js +204 -0
- package/dist/app/collab-work-execution.d.ts +127 -0
- package/dist/app/collab-work-execution.js +1027 -0
- package/dist/app/collab-work-plan.d.ts +87 -0
- package/dist/app/collab-work-plan.js +437 -0
- package/dist/app/collaboration.d.ts +8 -2
- package/dist/app/collaboration.js +101 -12
- package/dist/app/doctor.js +108 -5
- package/dist/app/host-mcp.js +34 -8
- package/dist/app/host-probe.js +4 -4
- package/dist/app/init.d.ts +58 -4
- package/dist/app/init.js +768 -155
- package/dist/app/managed-pi-bootstrap-admission.d.ts +14 -0
- package/dist/app/managed-pi-bootstrap-admission.js +104 -0
- package/dist/app/managed-pi-bootstrap-refresh.d.ts +10 -0
- package/dist/app/managed-pi-bootstrap-refresh.js +78 -0
- package/dist/app/managed-pi-delivery.d.ts +8 -0
- package/dist/app/managed-pi-delivery.js +110 -0
- package/dist/app/managed-pi-handoff-receiver.d.ts +15 -0
- package/dist/app/managed-pi-handoff-receiver.js +263 -0
- package/dist/app/managed-pi-handoff-reference.d.ts +3 -0
- package/dist/app/managed-pi-handoff-reference.js +60 -0
- package/dist/app/managed-pi-herdr.d.ts +21 -0
- package/dist/app/managed-pi-herdr.js +185 -0
- package/dist/app/managed-pi-initial-admission.d.ts +28 -0
- package/dist/app/managed-pi-initial-admission.js +416 -0
- package/dist/app/managed-pi-initial-launch.d.ts +5 -0
- package/dist/app/managed-pi-initial-launch.js +61 -0
- package/dist/app/managed-pi-native-observation.d.ts +36 -0
- package/dist/app/managed-pi-native-observation.js +191 -0
- package/dist/app/managed-pi-readiness.d.ts +29 -0
- package/dist/app/managed-pi-readiness.js +288 -0
- package/dist/app/managed-pi-repair-stop.d.ts +21 -0
- package/dist/app/managed-pi-repair-stop.js +371 -0
- package/dist/app/managed-pi-resume-admission.d.ts +32 -0
- package/dist/app/managed-pi-resume-admission.js +618 -0
- package/dist/app/managed-pi-retirement.d.ts +28 -0
- package/dist/app/managed-pi-retirement.js +112 -0
- package/dist/app/managed-pi-sdk-control.d.ts +7 -0
- package/dist/app/managed-pi-sdk-control.js +169 -0
- package/dist/app/managed-pi-sdk-runtime.d.ts +3 -0
- package/dist/app/managed-pi-sdk-runtime.js +483 -0
- package/dist/app/managed-pi-source-admission.d.ts +14 -0
- package/dist/app/managed-pi-source-admission.js +323 -0
- package/dist/app/managed-pi-transition-host.d.ts +36 -0
- package/dist/app/managed-pi-transition-host.js +292 -0
- package/dist/app/managed-pi.d.ts +54 -0
- package/dist/app/managed-pi.js +248 -0
- package/dist/app/shell-readiness.d.ts +66 -0
- package/dist/app/shell-readiness.js +368 -0
- package/dist/app/task-pin.d.ts +2 -23
- package/dist/app/task-pin.js +2 -113
- package/dist/cli/commands/collaboration-binding.d.ts +13 -0
- package/dist/cli/commands/collaboration-binding.js +118 -0
- package/dist/cli/commands/collaboration-bootstrap.d.ts +10 -0
- package/dist/cli/commands/collaboration-bootstrap.js +84 -0
- package/dist/cli/commands/collaboration-capabilities.d.ts +13 -0
- package/dist/cli/commands/collaboration-capabilities.js +127 -0
- package/dist/cli/commands/collaboration-handoff.d.ts +13 -0
- package/dist/cli/commands/collaboration-handoff.js +102 -0
- package/dist/cli/commands/collaboration-message.d.ts +17 -0
- package/dist/cli/commands/collaboration-message.js +177 -0
- package/dist/cli/commands/collaboration-plan.d.ts +8 -0
- package/dist/cli/commands/collaboration-plan.js +108 -0
- package/dist/cli/commands/collaboration-preflight.d.ts +10 -0
- package/dist/cli/commands/collaboration-preflight.js +167 -0
- package/dist/cli/commands/collaboration-recovery-run.d.ts +46 -0
- package/dist/cli/commands/collaboration-recovery-run.js +224 -0
- package/dist/cli/commands/collaboration-recovery.d.ts +11 -0
- package/dist/cli/commands/collaboration-recovery.js +104 -0
- package/dist/cli/commands/collaboration-resources.d.ts +11 -0
- package/dist/cli/commands/collaboration-resources.js +96 -0
- package/dist/cli/commands/collaboration-role-plan.d.ts +9 -0
- package/dist/cli/commands/collaboration-role-plan.js +69 -0
- package/dist/cli/commands/collaboration-role-run.d.ts +11 -0
- package/dist/cli/commands/collaboration-role-run.js +128 -0
- package/dist/cli/commands/collaboration-rollover.d.ts +10 -0
- package/dist/cli/commands/collaboration-rollover.js +103 -0
- package/dist/cli/commands/collaboration-state.d.ts +10 -0
- package/dist/cli/commands/collaboration-state.js +96 -0
- package/dist/cli/commands/collaboration-transition.d.ts +10 -0
- package/dist/cli/commands/collaboration-transition.js +75 -0
- package/dist/cli/commands/collaboration-work-run.d.ts +34 -0
- package/dist/cli/commands/collaboration-work-run.js +178 -0
- package/dist/cli/commands/collaboration.d.ts +4 -0
- package/dist/cli/commands/collaboration.js +39 -4
- package/dist/cli/commands/continuity.js +2 -6
- package/dist/cli/commands/docs.d.ts +2 -0
- package/dist/cli/commands/docs.js +89 -15
- package/dist/cli/commands/host.d.ts +7 -1
- package/dist/cli/commands/host.js +122 -7
- package/dist/cli/commands/init.d.ts +20 -3
- package/dist/cli/commands/init.js +897 -232
- package/dist/cli/commands/mcp.d.ts +1 -0
- package/dist/cli/commands/mcp.js +11 -5
- package/dist/cli/commands/repair.d.ts +12 -0
- package/dist/cli/commands/repair.js +41 -0
- package/dist/cli/commands/runtime.d.ts +1 -1
- package/dist/cli/commands/runtime.js +139 -38
- package/dist/cli/commands/session.d.ts +7 -0
- package/dist/cli/commands/session.js +82 -0
- package/dist/cli/commands/task.js +19 -5
- package/dist/cli/run.js +866 -24
- package/dist/code/identity.d.ts +7 -0
- package/dist/code/identity.js +7 -3
- package/dist/code/registration.js +7 -0
- package/dist/code/service.d.ts +9 -0
- package/dist/code/service.js +16 -3
- package/dist/code/text.js +19 -7
- package/dist/collab/admission.d.ts +91 -66
- package/dist/collab/admission.js +21 -6
- package/dist/collab/canonical.d.ts +1 -1
- package/dist/collab/canonical.js +44 -3
- package/dist/collab/envelope.d.ts +2 -2
- package/dist/collab/envelope.js +12 -12
- package/dist/collab/first-work.d.ts +3 -0
- package/dist/collab/first-work.js +15 -0
- package/dist/collab/handoff.d.ts +16 -0
- package/dist/collab/handoff.js +39 -5
- package/dist/collab/index.d.ts +97 -1
- package/dist/collab/index.js +9 -1
- package/dist/collab/messages.js +126 -3
- package/dist/collab/persisted-messages.d.ts +123 -0
- package/dist/collab/persisted-messages.js +496 -0
- package/dist/collab/preflight.d.ts +1 -1
- package/dist/collab/resources.d.ts +13 -3
- package/dist/collab/resources.js +37 -6
- package/dist/collab/rollover.d.ts +311 -0
- package/dist/collab/rollover.js +1024 -0
- package/dist/collab/store.d.ts +1 -0
- package/dist/collab/store.js +1 -4
- package/dist/collab/types.d.ts +2 -354
- package/dist/collab/validation.d.ts +2 -10
- package/dist/collab/validation.js +2 -303
- package/dist/collab/work-plan.d.ts +105 -0
- package/dist/collab/work-plan.js +843 -0
- package/dist/continuity/context.d.ts +11 -2
- package/dist/continuity/context.js +100 -13
- package/dist/continuity/handoff-bundle.d.ts +296 -0
- package/dist/continuity/handoff-bundle.js +477 -0
- package/dist/continuity/index.d.ts +2 -0
- package/dist/continuity/index.js +1 -0
- package/dist/continuity/paths.js +10 -2
- package/dist/continuity/service.js +91 -15
- package/dist/continuity/task-pin.d.ts +24 -0
- package/dist/continuity/task-pin.js +590 -0
- package/dist/doctor.d.ts +1 -0
- package/dist/doctor.js +6 -0
- package/dist/experimental/index.d.ts +13 -0
- package/dist/experimental/index.js +25 -0
- package/dist/experimental/pi.d.ts +4 -0
- package/dist/experimental/pi.js +12 -0
- package/dist/hosts/claude/native.js +1 -1
- package/dist/hosts/codex/native.js +1 -1
- package/dist/hosts/codex/protocol.js +1 -1
- package/dist/hosts/integration/bootstrap-config.d.ts +58 -0
- package/dist/hosts/integration/bootstrap-config.js +254 -0
- package/dist/hosts/integration/bundle-export.d.ts +44 -0
- package/dist/hosts/integration/bundle-export.js +366 -3
- package/dist/hosts/integration/bundle.js +3 -0
- package/dist/hosts/integration/hook.js +36 -9
- package/dist/hosts/integration/pappra-bootstrap-extension.mjs +80 -0
- package/dist/hosts/integration/pappra-extension-runtime.mjs +59 -24631
- package/dist/hosts/integration/pappra-hook.mjs +61 -24749
- package/dist/hosts/integration/pappra-recovery-extension.mjs +259 -0
- package/dist/hosts/integration/pappra-session-transition-extension.mjs +276 -0
- package/dist/hosts/integration/pi-bootstrap-extension.d.ts +36 -0
- package/dist/hosts/integration/pi-bootstrap-extension.js +101 -0
- package/dist/hosts/integration/pi-bootstrap-guard.d.ts +125 -0
- package/dist/hosts/integration/pi-bootstrap-guard.js +438 -0
- package/dist/hosts/integration/pi-bootstrap-runtime.d.ts +63 -0
- package/dist/hosts/integration/pi-bootstrap-runtime.js +223 -0
- package/dist/hosts/integration/pi-native-events.d.ts +112 -0
- package/dist/hosts/integration/pi-native-events.js +348 -0
- package/dist/hosts/integration/pi-rollover-extension.d.ts +166 -0
- package/dist/hosts/integration/pi-rollover-extension.js +431 -0
- package/dist/hosts/integration/recovery-config.d.ts +48 -0
- package/dist/hosts/integration/recovery-config.js +117 -0
- package/dist/hosts/integration/service.d.ts +6 -1
- package/dist/hosts/integration/service.js +485 -35
- package/dist/hosts/integration/support.d.ts +7 -0
- package/dist/hosts/integration/support.js +9 -1
- package/dist/hosts/integration/templates.d.ts +3 -0
- package/dist/hosts/integration/templates.js +26 -3
- package/dist/hosts/pi/managed-host-identity.d.ts +2 -0
- package/dist/hosts/pi/managed-host-identity.js +40 -0
- package/dist/hosts/pi/managed-provider-diagnostics.d.ts +6 -0
- package/dist/hosts/pi/managed-provider-diagnostics.js +184 -0
- package/dist/hosts/pi/managed-sdk-session.d.ts +335 -0
- package/dist/hosts/pi/managed-sdk-session.js +1639 -0
- package/dist/hosts/pi/managed-session-extension.d.ts +20 -0
- package/dist/hosts/pi/managed-session-extension.js +84 -0
- package/dist/hosts/pi/managed-session.d.ts +177 -0
- package/dist/hosts/pi/managed-session.js +1557 -0
- package/dist/hosts/pi/protocol.js +1 -1
- package/dist/hosts/pi/query-result.js +1 -1
- package/dist/hosts/pi/resume-capability.d.ts +41 -0
- package/dist/hosts/pi/resume-capability.js +33 -0
- package/dist/hosts/pi/rpc.d.ts +182 -134
- package/dist/hosts/pi/rpc.js +230 -37
- package/dist/hosts/pilot.d.ts +97 -74
- package/dist/hosts/pilot.js +5 -1
- package/dist/hosts/version.d.ts +3 -0
- package/dist/hosts/version.js +18 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/infra/bounded-file.d.ts +19 -0
- package/dist/infra/bounded-file.js +66 -0
- package/dist/infra/fs.js +10 -2
- package/dist/infra/git.d.ts +29 -0
- package/dist/infra/git.js +45 -9
- package/dist/infra/json-property.d.ts +2 -0
- package/dist/infra/json-property.js +69 -0
- package/dist/infra/json.d.ts +4 -0
- package/dist/infra/json.js +24 -0
- package/dist/infra/owned-process-group.js +1 -1
- package/dist/infra/private-lock.d.ts +16 -0
- package/dist/infra/private-lock.js +148 -0
- package/dist/infra/private-state.d.ts +7 -0
- package/dist/infra/private-state.js +146 -0
- package/dist/infra/process-identity.d.ts +12 -0
- package/dist/infra/process-identity.js +142 -0
- package/dist/infra/validation.d.ts +5 -0
- package/dist/infra/validation.js +15 -0
- package/dist/init.d.ts +1 -0
- package/dist/init.js +6 -0
- package/dist/install/apply.d.ts +9 -1
- package/dist/install/apply.js +176 -12
- package/dist/install/dependencies.d.ts +38 -0
- package/dist/install/dependencies.js +282 -0
- package/dist/install/ownership.js +30 -1
- package/dist/install/references.d.ts +31 -0
- package/dist/install/references.js +208 -0
- package/dist/install/repair.d.ts +37 -0
- package/dist/install/repair.js +798 -0
- package/dist/install/reset-local.d.ts +16 -0
- package/dist/install/reset-local.js +304 -0
- package/dist/install/rollback.d.ts +3 -0
- package/dist/install/rollback.js +9 -3
- package/dist/install/runtime.d.ts +10 -6
- package/dist/install/runtime.js +299 -59
- package/dist/install/source-fingerprint.d.ts +2 -0
- package/dist/install/source-fingerprint.js +103 -0
- package/dist/knowledge/catalog.d.ts +1 -0
- package/dist/knowledge/catalog.js +143 -10
- package/dist/knowledge/journal.js +17 -7
- package/dist/knowledge/paths.js +2 -1
- package/dist/knowledge/refs.js +4 -0
- package/dist/knowledge/register-batch.d.ts +4 -0
- package/dist/knowledge/register-batch.js +225 -0
- package/dist/knowledge/relocate.d.ts +5 -0
- package/dist/knowledge/relocate.js +92 -0
- package/dist/knowledge/scan.js +103 -47
- package/dist/knowledge/service.d.ts +3 -0
- package/dist/knowledge/service.js +33 -1
- package/dist/knowledge/write.d.ts +4 -1
- package/dist/knowledge/write.js +1 -1
- package/dist/mcp/server.d.ts +4 -2
- package/dist/mcp/server.js +87 -136
- package/dist/schemas/collaboration-state-validation.d.ts +6 -0
- package/dist/schemas/collaboration-state-validation.js +342 -0
- package/dist/schemas/collaboration-state.d.ts +436 -0
- package/dist/schemas/collaboration-state.js +1 -0
- package/dist/schemas/collaboration.d.ts +335 -0
- package/dist/schemas/collaboration.js +272 -0
- package/dist/schemas/continuity.d.ts +8 -0
- package/dist/schemas/continuity.js +13 -3
- package/dist/schemas/doctor.d.ts +1 -0
- package/dist/schemas/doctor.js +1 -0
- package/dist/schemas/document.d.ts +61 -0
- package/dist/schemas/document.js +9 -0
- package/dist/schemas/errors.d.ts +1 -0
- package/dist/schemas/errors.js +1 -0
- package/dist/schemas/host.d.ts +24 -0
- package/dist/schemas/host.js +19 -0
- package/dist/schemas/install.d.ts +8 -2
- package/dist/schemas/install.js +11 -1
- package/dist/schemas/managed-pi-execution.d.ts +16 -0
- package/dist/schemas/managed-pi-execution.js +2 -0
- package/dist/schemas/outcome.d.ts +9 -5
- package/dist/workspace/config-file.js +1 -3
- package/dist/workspace/documents.js +12 -2
- package/dist/workspace/repositories.d.ts +7 -0
- package/dist/workspace/repositories.js +14 -5
- package/package.json +35 -35
- package/skills/pappra/SKILL.md +28 -7
- package/skills/pappra/references/collaboration.md +633 -0
- package/skills/pappra/references/environment.md +360 -0
- package/skills/pappra/references/hosts.md +20 -0
- package/skills/pappra/references/operations.md +36 -5
- package/dist/app/collab-from.d.ts +0 -35
- package/dist/app/collab-from.js +0 -84
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type WorkPlanEvaluation } from '../collab/work-plan.js';
|
|
2
|
+
/**
|
|
3
|
+
* Public, read-only work-plan inspection.
|
|
4
|
+
*
|
|
5
|
+
* The entry validates one bounded plan document first, then loads only the decision
|
|
6
|
+
* evidence that plan actually needs: the registered `ANSWER` envelopes addressed to the
|
|
7
|
+
* current applied reports of the planned attempts. Unrelated task decisions are neither
|
|
8
|
+
* read nor counted. Raw envelope bytes are budgeted before a full read through the
|
|
9
|
+
* descriptor-safe bounded reader, and every loaded envelope keeps the safe message-id,
|
|
10
|
+
* namespace, identity and content-digest checks. Nothing is claimed, launched, refreshed,
|
|
11
|
+
* reconciled or written, and role labels carry no authority.
|
|
12
|
+
*/
|
|
13
|
+
export declare const COLLAB_WORK_PLAN_REPORT_SCHEMA = "pappra/collaboration-work-plan-report/1";
|
|
14
|
+
export type WorkPlanReportStatus = 'evaluated' | 'incomplete' | 'invalid';
|
|
15
|
+
export interface WorkPlanReportBlocker {
|
|
16
|
+
readonly code: string;
|
|
17
|
+
readonly detail: string;
|
|
18
|
+
}
|
|
19
|
+
export interface WorkPlanReportNode {
|
|
20
|
+
readonly node_id: string;
|
|
21
|
+
readonly role: string;
|
|
22
|
+
readonly assignment_id: string;
|
|
23
|
+
readonly attempt: number;
|
|
24
|
+
readonly status: string;
|
|
25
|
+
/** Persisted assigned work with no native execution or durable dispatch intent yet. */
|
|
26
|
+
readonly dispatch_pending?: boolean;
|
|
27
|
+
readonly blockers: readonly WorkPlanReportBlocker[];
|
|
28
|
+
readonly next_action: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface WorkPlanReportDiagnostic {
|
|
31
|
+
readonly code: string;
|
|
32
|
+
readonly detail: string;
|
|
33
|
+
readonly next_action: string | null;
|
|
34
|
+
}
|
|
35
|
+
export interface WorkPlanEvidenceSummary {
|
|
36
|
+
/** Applied reports of the planned attempts that decisions must reference. */
|
|
37
|
+
readonly relevant_reports: number;
|
|
38
|
+
/** Registered decision envelopes addressed to those reports. */
|
|
39
|
+
readonly registered_decisions: number;
|
|
40
|
+
readonly supplied: number;
|
|
41
|
+
/**
|
|
42
|
+
* Raw bytes consumed by successful bounded reads, including files later rejected by
|
|
43
|
+
* realpath, JSON, envelope, identity or digest validation. Independent of `supplied`.
|
|
44
|
+
*/
|
|
45
|
+
readonly raw_bytes: number;
|
|
46
|
+
readonly per_file_limit: number;
|
|
47
|
+
readonly aggregate_limit: number;
|
|
48
|
+
readonly message_limit: number;
|
|
49
|
+
readonly unreadable: readonly {
|
|
50
|
+
message_id: string;
|
|
51
|
+
code: string;
|
|
52
|
+
}[];
|
|
53
|
+
readonly over_budget: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface WorkPlanReport {
|
|
56
|
+
readonly schema: typeof COLLAB_WORK_PLAN_REPORT_SCHEMA;
|
|
57
|
+
readonly ok: boolean;
|
|
58
|
+
readonly status: WorkPlanReportStatus;
|
|
59
|
+
readonly task_root: string | null;
|
|
60
|
+
readonly task_id: string | null;
|
|
61
|
+
readonly plan: {
|
|
62
|
+
readonly ref: string;
|
|
63
|
+
readonly digest: string | null;
|
|
64
|
+
readonly plan_id: string | null;
|
|
65
|
+
readonly owner_epoch: number | null;
|
|
66
|
+
readonly node_count: number | null;
|
|
67
|
+
};
|
|
68
|
+
readonly stale: boolean;
|
|
69
|
+
readonly summary: {
|
|
70
|
+
readonly ready: number;
|
|
71
|
+
readonly running: number;
|
|
72
|
+
readonly awaiting_acceptance: number;
|
|
73
|
+
readonly accepted: number;
|
|
74
|
+
readonly blocked: number;
|
|
75
|
+
} | null;
|
|
76
|
+
readonly nodes: readonly WorkPlanReportNode[];
|
|
77
|
+
readonly core: WorkPlanEvaluation | null;
|
|
78
|
+
readonly evidence: WorkPlanEvidenceSummary;
|
|
79
|
+
readonly diagnostics: readonly WorkPlanReportDiagnostic[];
|
|
80
|
+
readonly identity_mapping: string;
|
|
81
|
+
readonly limits: readonly string[];
|
|
82
|
+
}
|
|
83
|
+
export interface WorkPlanInspectionOptions {
|
|
84
|
+
readonly taskRoot: string;
|
|
85
|
+
readonly planFile: string;
|
|
86
|
+
}
|
|
87
|
+
export declare function inspectWorkPlan(options: WorkPlanInspectionOptions): Promise<WorkPlanReport>;
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import { readBoundedFile } from './bounded-file.js';
|
|
2
|
+
import { assertTaskStoreCurrent, openTaskStore } from './collab-task-store.js';
|
|
3
|
+
import { contentDigest, isSafeMessageId, messageFile, validateEnvelope, } from '../collab/envelope.js';
|
|
4
|
+
import { evaluateWorkPlan, validateWorkPlan, } from '../collab/work-plan.js';
|
|
5
|
+
import { observePath, resolveRealpath } from '../infra/fs.js';
|
|
6
|
+
import { isPathInside } from '../schemas/paths.js';
|
|
7
|
+
/**
|
|
8
|
+
* Public, read-only work-plan inspection.
|
|
9
|
+
*
|
|
10
|
+
* The entry validates one bounded plan document first, then loads only the decision
|
|
11
|
+
* evidence that plan actually needs: the registered `ANSWER` envelopes addressed to the
|
|
12
|
+
* current applied reports of the planned attempts. Unrelated task decisions are neither
|
|
13
|
+
* read nor counted. Raw envelope bytes are budgeted before a full read through the
|
|
14
|
+
* descriptor-safe bounded reader, and every loaded envelope keeps the safe message-id,
|
|
15
|
+
* namespace, identity and content-digest checks. Nothing is claimed, launched, refreshed,
|
|
16
|
+
* reconciled or written, and role labels carry no authority.
|
|
17
|
+
*/
|
|
18
|
+
export const COLLAB_WORK_PLAN_REPORT_SCHEMA = 'pappra/collaboration-work-plan-report/1';
|
|
19
|
+
const MAX_PLAN_BYTES = 512 * 1024;
|
|
20
|
+
const MAX_DECISION_MESSAGES = 128;
|
|
21
|
+
const MAX_DECISION_FILE_BYTES = 1024 * 1024;
|
|
22
|
+
const MAX_DECISION_BYTES = 4 * 1024 * 1024;
|
|
23
|
+
/** Refusals that mean the caller's request/plan is wrong, not that evidence is missing. */
|
|
24
|
+
const PLAN_REQUEST_CODES = new Set([
|
|
25
|
+
'plan_invalid',
|
|
26
|
+
'node_invalid',
|
|
27
|
+
'plan_too_large',
|
|
28
|
+
'duplicate_node_id',
|
|
29
|
+
'duplicate_dependency',
|
|
30
|
+
'self_dependency',
|
|
31
|
+
'unknown_dependency',
|
|
32
|
+
'dependency_cycle',
|
|
33
|
+
'resource_invalid',
|
|
34
|
+
'task_identity_mismatch',
|
|
35
|
+
]);
|
|
36
|
+
const TASK_REQUEST_CODES = new Set([
|
|
37
|
+
'task_root_required',
|
|
38
|
+
'task_root_layout_invalid',
|
|
39
|
+
]);
|
|
40
|
+
const LIMITS = Object.freeze([
|
|
41
|
+
'persisted_snapshot_only',
|
|
42
|
+
'advisory_read_only_plan',
|
|
43
|
+
'no_dispatch_or_launch',
|
|
44
|
+
'no_native_query',
|
|
45
|
+
'no_resource_fencing',
|
|
46
|
+
'not_an_authorization',
|
|
47
|
+
]);
|
|
48
|
+
const IDENTITY_MAPPING = 'plan.nodes[].assignment_id corresponds to the existing task subtask identity (record.attempts[].subtask_id); no separate assignment registry exists.';
|
|
49
|
+
function emptyEvidence() {
|
|
50
|
+
return {
|
|
51
|
+
relevant_reports: 0,
|
|
52
|
+
registered_decisions: 0,
|
|
53
|
+
supplied: 0,
|
|
54
|
+
raw_bytes: 0,
|
|
55
|
+
per_file_limit: MAX_DECISION_FILE_BYTES,
|
|
56
|
+
aggregate_limit: MAX_DECISION_BYTES,
|
|
57
|
+
message_limit: MAX_DECISION_MESSAGES,
|
|
58
|
+
unreadable: [],
|
|
59
|
+
over_budget: false,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function reportBase(planFile, digest) {
|
|
63
|
+
return {
|
|
64
|
+
schema: COLLAB_WORK_PLAN_REPORT_SCHEMA,
|
|
65
|
+
ok: false,
|
|
66
|
+
status: 'invalid',
|
|
67
|
+
task_root: null,
|
|
68
|
+
task_id: null,
|
|
69
|
+
plan: {
|
|
70
|
+
ref: planFile,
|
|
71
|
+
digest,
|
|
72
|
+
plan_id: null,
|
|
73
|
+
owner_epoch: null,
|
|
74
|
+
node_count: null,
|
|
75
|
+
},
|
|
76
|
+
stale: false,
|
|
77
|
+
summary: null,
|
|
78
|
+
nodes: [],
|
|
79
|
+
core: null,
|
|
80
|
+
evidence: emptyEvidence(),
|
|
81
|
+
diagnostics: [],
|
|
82
|
+
identity_mapping: IDENTITY_MAPPING,
|
|
83
|
+
limits: [...LIMITS],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const PLAN_READ_ACTIONS = {
|
|
87
|
+
path_not_absolute: 'Pass an absolute path to the plan document; nothing was read.',
|
|
88
|
+
symlink: 'Pass the real plan file; Pappra does not follow a redirected plan path.',
|
|
89
|
+
not_regular: 'Pass a regular JSON plan file; links and special files are not read.',
|
|
90
|
+
too_large: 'Reduce the plan document to the supported size; nothing was evaluated.',
|
|
91
|
+
unreadable: 'Check permissions on the plan file; nothing was evaluated.',
|
|
92
|
+
};
|
|
93
|
+
function appendDiagnostic(report, code, detail, nextAction) {
|
|
94
|
+
return {
|
|
95
|
+
...report,
|
|
96
|
+
diagnostics: [
|
|
97
|
+
...report.diagnostics,
|
|
98
|
+
{ code, detail, next_action: nextAction },
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function fromTaskFailure(report, failure) {
|
|
103
|
+
const withDiagnostic = appendDiagnostic(report, failure.code, failure.message, failure.nextAction);
|
|
104
|
+
return {
|
|
105
|
+
...withDiagnostic,
|
|
106
|
+
status: TASK_REQUEST_CODES.has(failure.code) ? 'invalid' : 'incomplete',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function classifyRefusal(diagnostics) {
|
|
110
|
+
return diagnostics.some((entry) => PLAN_REQUEST_CODES.has(entry.code))
|
|
111
|
+
? 'invalid'
|
|
112
|
+
: 'incomplete';
|
|
113
|
+
}
|
|
114
|
+
function coreDiagnosticAction(code) {
|
|
115
|
+
switch (code) {
|
|
116
|
+
case 'plan_invalid':
|
|
117
|
+
case 'node_invalid':
|
|
118
|
+
case 'duplicate_node_id':
|
|
119
|
+
case 'duplicate_dependency':
|
|
120
|
+
case 'self_dependency':
|
|
121
|
+
case 'unknown_dependency':
|
|
122
|
+
case 'dependency_cycle':
|
|
123
|
+
case 'resource_invalid':
|
|
124
|
+
return 'Fix the plan document and re-run the read-only inspection.';
|
|
125
|
+
case 'plan_too_large':
|
|
126
|
+
return 'Split the plan into a smaller bounded document; nothing was truncated.';
|
|
127
|
+
case 'task_identity_mismatch':
|
|
128
|
+
return 'Point the plan at this task root or inspect the intended task.';
|
|
129
|
+
case 'record_invalid':
|
|
130
|
+
case 'record_too_large':
|
|
131
|
+
return 'Inspect the task record; planning refuses facts it cannot read.';
|
|
132
|
+
default:
|
|
133
|
+
return 'Inspect the supplied decision evidence; nothing was accepted from an unreadable envelope.';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function fromCoreRefusal(report, refusal) {
|
|
137
|
+
let next = report;
|
|
138
|
+
for (const entry of refusal.diagnostics) {
|
|
139
|
+
next = appendDiagnostic(next, entry.code, entry.detail, coreDiagnosticAction(entry.code));
|
|
140
|
+
}
|
|
141
|
+
return { ...next, status: classifyRefusal(refusal.diagnostics) };
|
|
142
|
+
}
|
|
143
|
+
function summarise(evaluation) {
|
|
144
|
+
return {
|
|
145
|
+
ready: evaluation.ready_nodes.length,
|
|
146
|
+
running: evaluation.running_nodes.length,
|
|
147
|
+
awaiting_acceptance: evaluation.awaiting_acceptance_nodes.length,
|
|
148
|
+
accepted: evaluation.accepted_nodes.length,
|
|
149
|
+
blocked: evaluation.blocked_nodes.length,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function projectNodes(evaluation, plan, record) {
|
|
153
|
+
const planned = new Map(plan.nodes.map((node) => [node.node_id, node]));
|
|
154
|
+
return evaluation.nodes.map((node) => ({
|
|
155
|
+
node_id: node.node_id,
|
|
156
|
+
role: node.role,
|
|
157
|
+
assignment_id: planned.get(node.node_id)?.assignment_id ?? node.node_id,
|
|
158
|
+
attempt: planned.get(node.node_id)?.attempt ?? 1,
|
|
159
|
+
status: node.status,
|
|
160
|
+
dispatch_pending: node.status === 'running' &&
|
|
161
|
+
(() => {
|
|
162
|
+
const plannedNode = planned.get(node.node_id);
|
|
163
|
+
const attempt = record.attempts.find((row) => row.subtask_id === plannedNode?.assignment_id &&
|
|
164
|
+
row.attempt === plannedNode.attempt);
|
|
165
|
+
return (attempt !== undefined &&
|
|
166
|
+
attempt.state === 'assigned' &&
|
|
167
|
+
!attempt.awaiting &&
|
|
168
|
+
!attempt.cancel_requested_at &&
|
|
169
|
+
!attempt.closed_at &&
|
|
170
|
+
!record.dispatch_frozen &&
|
|
171
|
+
attempt.native.observation === 'unknown' &&
|
|
172
|
+
attempt.native.session_id === null &&
|
|
173
|
+
attempt.native.run_id === null &&
|
|
174
|
+
attempt.native.mission_id === null &&
|
|
175
|
+
attempt.native.evidence_ref === null &&
|
|
176
|
+
!record.messages.some((message) => message.type === 'STATUS_QUERY' &&
|
|
177
|
+
message.subtask_id === attempt.subtask_id &&
|
|
178
|
+
message.attempt === attempt.attempt &&
|
|
179
|
+
message.message_id.startsWith('msg-work-intent-')));
|
|
180
|
+
})(),
|
|
181
|
+
blockers: node.blockers.map((blocker) => ({
|
|
182
|
+
code: blocker.code,
|
|
183
|
+
detail: blocker.detail,
|
|
184
|
+
})),
|
|
185
|
+
next_action: node.recovery,
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Applied reports belong to the planned attempts only. A report that no plan node
|
|
190
|
+
* references cannot make this plan incomplete.
|
|
191
|
+
*/
|
|
192
|
+
function relevantReportIds(record, plan) {
|
|
193
|
+
const planned = new Set(plan.nodes.map((node) => `${node.assignment_id}#${node.attempt}`));
|
|
194
|
+
const ids = new Set();
|
|
195
|
+
for (const result of record.results ?? []) {
|
|
196
|
+
if (result.classification !== 'applied')
|
|
197
|
+
continue;
|
|
198
|
+
if (!planned.has(`${result.subtask_id}#${result.attempt}`))
|
|
199
|
+
continue;
|
|
200
|
+
ids.add(result.message_id);
|
|
201
|
+
}
|
|
202
|
+
return ids;
|
|
203
|
+
}
|
|
204
|
+
/** Registered decisions addressed to the relevant reports, in application order. */
|
|
205
|
+
function relevantDecisionIds(record, reportIds) {
|
|
206
|
+
const ids = [];
|
|
207
|
+
for (const entry of record.messages ?? []) {
|
|
208
|
+
if (entry.type !== 'ANSWER')
|
|
209
|
+
continue;
|
|
210
|
+
if (entry.state !== 'applied')
|
|
211
|
+
continue;
|
|
212
|
+
if (typeof entry.reply_to !== 'string')
|
|
213
|
+
continue;
|
|
214
|
+
if (!reportIds.has(entry.reply_to))
|
|
215
|
+
continue;
|
|
216
|
+
if (!ids.includes(entry.message_id))
|
|
217
|
+
ids.push(entry.message_id);
|
|
218
|
+
}
|
|
219
|
+
return ids;
|
|
220
|
+
}
|
|
221
|
+
function unreadableCode(code) {
|
|
222
|
+
switch (code) {
|
|
223
|
+
case 'symlink':
|
|
224
|
+
return 'message_redirected';
|
|
225
|
+
case 'not_regular':
|
|
226
|
+
return 'message_not_regular';
|
|
227
|
+
case 'unreadable':
|
|
228
|
+
return 'message_unreadable';
|
|
229
|
+
default:
|
|
230
|
+
return 'message_path_invalid';
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Loads the relevant decision envelopes under real raw-byte budgets.
|
|
235
|
+
*
|
|
236
|
+
* The per-file and remaining aggregate limits are applied before a full read, so a padded
|
|
237
|
+
* envelope cannot consume the budget while reporting a smaller serialized size. Every
|
|
238
|
+
* loaded envelope keeps the safe id, directory containment, realpath, identity and
|
|
239
|
+
* registered content-digest checks.
|
|
240
|
+
*/
|
|
241
|
+
async function loadDecisionEvidence(task, decisionIds) {
|
|
242
|
+
const messages = [];
|
|
243
|
+
const unreadable = [];
|
|
244
|
+
const registeredDigest = new Map((task.record.messages ?? []).map((entry) => [
|
|
245
|
+
entry.message_id,
|
|
246
|
+
entry.content_digest,
|
|
247
|
+
]));
|
|
248
|
+
let rawBytes = 0;
|
|
249
|
+
let overBudget = false;
|
|
250
|
+
for (const [index, messageId] of decisionIds.entries()) {
|
|
251
|
+
if (index >= MAX_DECISION_MESSAGES) {
|
|
252
|
+
overBudget = true;
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
if (!isSafeMessageId(messageId)) {
|
|
256
|
+
unreadable.push({ message_id: messageId, code: 'message_id_invalid' });
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const file = messageFile(task.taskRoot, messageId);
|
|
260
|
+
if (!isPathInside(task.messagesDirectory, file)) {
|
|
261
|
+
unreadable.push({ message_id: messageId, code: 'message_id_invalid' });
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const observation = await observePath(file);
|
|
265
|
+
if (observation.kind === 'missing') {
|
|
266
|
+
unreadable.push({
|
|
267
|
+
message_id: messageId,
|
|
268
|
+
code: 'message_not_registered',
|
|
269
|
+
});
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (observation.kind !== 'file' || observation.stats === null) {
|
|
273
|
+
unreadable.push({ message_id: messageId, code: 'message_not_regular' });
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const remaining = Math.min(MAX_DECISION_FILE_BYTES, MAX_DECISION_BYTES - rawBytes);
|
|
277
|
+
if (remaining <= 0) {
|
|
278
|
+
overBudget = true;
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
const read = readBoundedFile(file, remaining);
|
|
282
|
+
if (!read.ok) {
|
|
283
|
+
if (read.code === 'too_large') {
|
|
284
|
+
// Either this file alone or the remaining aggregate budget is exhausted; the
|
|
285
|
+
// report says so instead of publishing a partial readiness projection.
|
|
286
|
+
overBudget = true;
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
unreadable.push({
|
|
290
|
+
message_id: messageId,
|
|
291
|
+
code: unreadableCode(read.code),
|
|
292
|
+
});
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
// The bytes were consumed by this read, so they count against the aggregate budget
|
|
296
|
+
// even when a later check rejects the envelope.
|
|
297
|
+
rawBytes += read.bytes.length;
|
|
298
|
+
const real = await resolveRealpath(file);
|
|
299
|
+
if (real === null ||
|
|
300
|
+
real !== file ||
|
|
301
|
+
!isPathInside(task.messagesDirectory, real)) {
|
|
302
|
+
unreadable.push({ message_id: messageId, code: 'message_redirected' });
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
let payload;
|
|
306
|
+
try {
|
|
307
|
+
payload = JSON.parse(read.text);
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
unreadable.push({ message_id: messageId, code: 'message_corrupt' });
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
let message;
|
|
314
|
+
try {
|
|
315
|
+
message = validateEnvelope(payload);
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
unreadable.push({ message_id: messageId, code: 'message_invalid' });
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (message.message_id !== messageId ||
|
|
322
|
+
message.task_id !== task.record.task_id) {
|
|
323
|
+
unreadable.push({
|
|
324
|
+
message_id: messageId,
|
|
325
|
+
code: 'message_identity_mismatch',
|
|
326
|
+
});
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (contentDigest(message) !== registeredDigest.get(messageId)) {
|
|
330
|
+
unreadable.push({ message_id: messageId, code: 'content_mismatch' });
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
messages.push(message);
|
|
334
|
+
}
|
|
335
|
+
return { messages, rawBytes, unreadable, overBudget };
|
|
336
|
+
}
|
|
337
|
+
export async function inspectWorkPlan(options) {
|
|
338
|
+
const read = readBoundedFile(options.planFile, MAX_PLAN_BYTES);
|
|
339
|
+
if (!read.ok) {
|
|
340
|
+
const code = `plan_file_${read.code}`;
|
|
341
|
+
return appendDiagnostic(reportBase(options.planFile, null), code, `The plan document could not be read as a bounded regular file (${read.code}).`, PLAN_READ_ACTIONS[read.code] ?? 'Pass a readable regular plan file.');
|
|
342
|
+
}
|
|
343
|
+
let document;
|
|
344
|
+
try {
|
|
345
|
+
document = JSON.parse(read.text);
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
return appendDiagnostic(reportBase(options.planFile, read.digest), 'plan_json_invalid', 'The plan document is not valid JSON.', 'Fix the plan document syntax; nothing was evaluated.');
|
|
349
|
+
}
|
|
350
|
+
const validated = validateWorkPlan(document);
|
|
351
|
+
if (!validated.ok) {
|
|
352
|
+
const base = reportBase(options.planFile, read.digest);
|
|
353
|
+
return {
|
|
354
|
+
...fromCoreRefusal(base, validated),
|
|
355
|
+
status: 'invalid',
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
const plan = validated.plan;
|
|
359
|
+
const opened = await openTaskStore(options.taskRoot);
|
|
360
|
+
if (!opened.ok) {
|
|
361
|
+
return fromTaskFailure(reportBase(options.planFile, read.digest), opened);
|
|
362
|
+
}
|
|
363
|
+
const task = opened.value;
|
|
364
|
+
let report = {
|
|
365
|
+
...reportBase(options.planFile, read.digest),
|
|
366
|
+
task_root: task.taskRoot,
|
|
367
|
+
task_id: task.record.task_id,
|
|
368
|
+
plan: {
|
|
369
|
+
ref: options.planFile,
|
|
370
|
+
digest: read.digest,
|
|
371
|
+
plan_id: plan.plan_id,
|
|
372
|
+
owner_epoch: plan.owner_epoch,
|
|
373
|
+
node_count: plan.nodes.length,
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
if (task.record.task_id !== plan.task_id) {
|
|
377
|
+
return appendDiagnostic(report, 'task_identity_mismatch', `record is ${task.record.task_id}, plan is ${plan.task_id}`, coreDiagnosticAction('task_identity_mismatch'));
|
|
378
|
+
}
|
|
379
|
+
const reports = relevantReportIds(task.record, plan);
|
|
380
|
+
const decisions = relevantDecisionIds(task.record, reports);
|
|
381
|
+
const loaded = await loadDecisionEvidence(task, decisions);
|
|
382
|
+
// The namespace is re-proved after the evidence reads: a swapped root or record never
|
|
383
|
+
// turns previously read files into authoritative decisions.
|
|
384
|
+
const changed = await assertTaskStoreCurrent(task);
|
|
385
|
+
if (changed !== null) {
|
|
386
|
+
return fromTaskFailure({
|
|
387
|
+
...report,
|
|
388
|
+
evidence: {
|
|
389
|
+
...emptyEvidence(),
|
|
390
|
+
relevant_reports: reports.size,
|
|
391
|
+
registered_decisions: decisions.length,
|
|
392
|
+
supplied: loaded.messages.length,
|
|
393
|
+
raw_bytes: loaded.rawBytes,
|
|
394
|
+
unreadable: loaded.unreadable,
|
|
395
|
+
over_budget: loaded.overBudget,
|
|
396
|
+
},
|
|
397
|
+
}, changed);
|
|
398
|
+
}
|
|
399
|
+
report = {
|
|
400
|
+
...report,
|
|
401
|
+
evidence: {
|
|
402
|
+
...emptyEvidence(),
|
|
403
|
+
relevant_reports: reports.size,
|
|
404
|
+
registered_decisions: decisions.length,
|
|
405
|
+
supplied: loaded.messages.length,
|
|
406
|
+
raw_bytes: loaded.rawBytes,
|
|
407
|
+
unreadable: loaded.unreadable,
|
|
408
|
+
over_budget: loaded.overBudget,
|
|
409
|
+
},
|
|
410
|
+
};
|
|
411
|
+
for (const entry of loaded.unreadable) {
|
|
412
|
+
report = appendDiagnostic(report, 'decision_evidence_unavailable', `Registered decision ${entry.message_id} could not be read (${entry.code}).`, 'Restore the registered decision file; an unreadable decision never becomes acceptance.');
|
|
413
|
+
}
|
|
414
|
+
if (loaded.overBudget) {
|
|
415
|
+
report = appendDiagnostic(report, 'decision_evidence_over_budget', `The plan's relevant decision evidence exceeds the raw budget (${MAX_DECISION_MESSAGES} envelopes, ${MAX_DECISION_FILE_BYTES} bytes per file, ${MAX_DECISION_BYTES} aggregate).`, 'Inspect the oversized registered decision or narrow the plan; the partial read is reported as incomplete, never as ready work.');
|
|
416
|
+
}
|
|
417
|
+
const evaluated = evaluateWorkPlan({
|
|
418
|
+
plan,
|
|
419
|
+
record: task.record,
|
|
420
|
+
messages: loaded.messages,
|
|
421
|
+
});
|
|
422
|
+
if (evaluated.ok === false) {
|
|
423
|
+
return fromCoreRefusal(report, evaluated);
|
|
424
|
+
}
|
|
425
|
+
const coordinatorEpoch = task.record.coordinator?.owner_epoch ?? null;
|
|
426
|
+
const stale = plan.owner_epoch !== coordinatorEpoch;
|
|
427
|
+
const incomplete = loaded.unreadable.length > 0 || loaded.overBudget;
|
|
428
|
+
return {
|
|
429
|
+
...report,
|
|
430
|
+
ok: !incomplete,
|
|
431
|
+
status: incomplete ? 'incomplete' : 'evaluated',
|
|
432
|
+
stale,
|
|
433
|
+
summary: summarise(evaluated),
|
|
434
|
+
nodes: projectNodes(evaluated, plan, task.record),
|
|
435
|
+
core: evaluated,
|
|
436
|
+
};
|
|
437
|
+
}
|
|
@@ -2,6 +2,8 @@ import type { Diagnostic } from '../schemas/diagnostics.js';
|
|
|
2
2
|
import { type CollaborationEvent, type CollaborationGoal, type CollaborationPrepared } from '../schemas/collaboration.js';
|
|
3
3
|
import { admitLaunch } from '../collab/admission.js';
|
|
4
4
|
import type { Assignment } from '../collab/contracts.js';
|
|
5
|
+
import type { CancellationIntentReference } from '../collab/types.js';
|
|
6
|
+
import { type PiOptions } from '../hosts/pi/rpc.js';
|
|
5
7
|
export type CollaborationFailureStatus = 'invalid' | 'needs_input' | 'conflict' | 'unsupported' | 'failed';
|
|
6
8
|
export interface CollaborationFailure {
|
|
7
9
|
readonly ok: false;
|
|
@@ -62,7 +64,7 @@ export interface ControllerFinish {
|
|
|
62
64
|
}
|
|
63
65
|
export interface ControllerSession {
|
|
64
66
|
query(): Promise<ControllerObservation>;
|
|
65
|
-
cancel(): Promise<ControllerCancel>;
|
|
67
|
+
cancel(intent?: CancellationIntentReference): Promise<ControllerCancel>;
|
|
66
68
|
finish(): Promise<ControllerFinish>;
|
|
67
69
|
dispose?(): Promise<void>;
|
|
68
70
|
}
|
|
@@ -107,6 +109,7 @@ export interface AdmissionResult {
|
|
|
107
109
|
}
|
|
108
110
|
export declare function admitPrepared(preparedFile: string, capabilitiesFile: string, options?: {
|
|
109
111
|
readonly clock?: number;
|
|
112
|
+
readonly controllerHarness?: string | null;
|
|
110
113
|
}): Promise<CollaborationResult<AdmissionResult>>;
|
|
111
114
|
export interface StartedRun {
|
|
112
115
|
readonly prepared: CollaborationPrepared;
|
|
@@ -153,7 +156,9 @@ export declare class FixtureController implements CollaborationController {
|
|
|
153
156
|
}>;
|
|
154
157
|
}
|
|
155
158
|
export declare class PiRpcController implements CollaborationController {
|
|
159
|
+
private readonly options;
|
|
156
160
|
readonly id = "pi-rpc";
|
|
161
|
+
constructor(options?: Pick<PiOptions, 'requestTimeoutMs' | 'operationTimeoutMs' | 'settleTimeoutMs' | 'maxBytes' | 'maxLogBytes'>);
|
|
157
162
|
start(token: object, request: ControllerStartRequest): Promise<{
|
|
158
163
|
readonly ok: true;
|
|
159
164
|
readonly session: ControllerSession;
|
|
@@ -167,4 +172,5 @@ export declare class PiRpcController implements CollaborationController {
|
|
|
167
172
|
}>;
|
|
168
173
|
}
|
|
169
174
|
export declare function inspectPreparedHistory(preparedFile: string): CollaborationResult<Record<string, unknown>>;
|
|
170
|
-
export {};
|
|
175
|
+
export { COLLAB_WORK_PLAN_REPORT_SCHEMA, inspectWorkPlan, type WorkPlanInspectionOptions, type WorkPlanReport, type WorkPlanReportBlocker, type WorkPlanReportDiagnostic, type WorkPlanReportNode, type WorkPlanReportStatus, } from './collab-work-plan.js';
|
|
176
|
+
export { COLLAB_ROLLOVER_REPORT_SCHEMA, COLLAB_ROLLOVER_REQUEST_SCHEMA, inspectOrPlanRollover, loadRolloverRequest, type RolloverAction, type RolloverBlocker, type RolloverBundleRequest, type RolloverClaimsReport, type RolloverEvidenceRequest, type RolloverFailure, type RolloverIntentRequest, type RolloverNativeReport, type RolloverReport, type RolloverRequest, type RolloverRequestResult, type RolloverResult, type RolloverStepReport, type RolloverStepStatus, } from './collab-rollover.js';
|