@openrig/cli 0.4.3 → 0.4.6
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/daemon/assets/guidance/openrig-start.md +6 -0
- package/daemon/assets/plugins/openrig-core/skills/mission-slice-sop/SKILL.md +47 -21
- package/daemon/assets/plugins/openrig-core/skills/openrig-cmux/SKILL.md +86 -0
- package/daemon/assets/plugins/openrig-core/skills/openrig-herdr/SKILL.md +158 -0
- package/daemon/assets/plugins/openrig-core/skills/openrig-user/SKILL.md +742 -94
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.js +12 -8
- package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
- package/daemon/dist/adapters/pi-resume.d.ts +32 -0
- package/daemon/dist/adapters/pi-resume.d.ts.map +1 -0
- package/daemon/dist/adapters/pi-resume.js +125 -0
- package/daemon/dist/adapters/pi-resume.js.map +1 -0
- package/daemon/dist/adapters/pi-runner-protocol.d.ts +88 -0
- package/daemon/dist/adapters/pi-runner-protocol.d.ts.map +1 -0
- package/daemon/dist/adapters/pi-runner-protocol.js +153 -0
- package/daemon/dist/adapters/pi-runner-protocol.js.map +1 -0
- package/daemon/dist/adapters/pi-runner.d.ts +99 -0
- package/daemon/dist/adapters/pi-runner.d.ts.map +1 -0
- package/daemon/dist/adapters/pi-runner.js +519 -0
- package/daemon/dist/adapters/pi-runner.js.map +1 -0
- package/daemon/dist/adapters/pi-runtime-adapter.d.ts +61 -0
- package/daemon/dist/adapters/pi-runtime-adapter.d.ts.map +1 -0
- package/daemon/dist/adapters/pi-runtime-adapter.js +356 -0
- package/daemon/dist/adapters/pi-runtime-adapter.js.map +1 -0
- package/daemon/dist/adapters/tmux.d.ts +22 -1
- package/daemon/dist/adapters/tmux.d.ts.map +1 -1
- package/daemon/dist/adapters/tmux.js +40 -1
- package/daemon/dist/adapters/tmux.js.map +1 -1
- package/daemon/dist/build-info.d.ts +12 -0
- package/daemon/dist/build-info.d.ts.map +1 -0
- package/daemon/dist/build-info.js +11 -0
- package/daemon/dist/build-info.js.map +1 -0
- package/daemon/dist/builtins/workflow-specs/branched-remediation.yaml +31 -0
- package/daemon/dist/builtins/workflow-specs/factory-rsi.yaml +152 -0
- package/daemon/dist/builtins/workflow-specs/gated-release.yaml +26 -0
- package/daemon/dist/builtins/workflow-specs/linear-build.yaml +21 -0
- package/daemon/dist/db/migrations/048_queue_item_evidence_ref.d.ts +18 -0
- package/daemon/dist/db/migrations/048_queue_item_evidence_ref.d.ts.map +1 -0
- package/daemon/dist/db/migrations/048_queue_item_evidence_ref.js +22 -0
- package/daemon/dist/db/migrations/048_queue_item_evidence_ref.js.map +1 -0
- package/daemon/dist/db/migrations/049_workflow_instance_version.d.ts +20 -0
- package/daemon/dist/db/migrations/049_workflow_instance_version.d.ts.map +1 -0
- package/daemon/dist/db/migrations/049_workflow_instance_version.js +24 -0
- package/daemon/dist/db/migrations/049_workflow_instance_version.js.map +1 -0
- package/daemon/dist/db/migrations/050_workflow_spec_json.d.ts +22 -0
- package/daemon/dist/db/migrations/050_workflow_spec_json.d.ts.map +1 -0
- package/daemon/dist/db/migrations/050_workflow_spec_json.js +26 -0
- package/daemon/dist/db/migrations/050_workflow_spec_json.js.map +1 -0
- package/daemon/dist/db/migrations/051_workflow_resume.d.ts +22 -0
- package/daemon/dist/db/migrations/051_workflow_resume.d.ts.map +1 -0
- package/daemon/dist/db/migrations/051_workflow_resume.js +27 -0
- package/daemon/dist/db/migrations/051_workflow_resume.js.map +1 -0
- package/daemon/dist/db/migrations/052_workflow_instance_bound_rig.d.ts +26 -0
- package/daemon/dist/db/migrations/052_workflow_instance_bound_rig.d.ts.map +1 -0
- package/daemon/dist/db/migrations/052_workflow_instance_bound_rig.js +30 -0
- package/daemon/dist/db/migrations/052_workflow_instance_bound_rig.js.map +1 -0
- package/daemon/dist/db/migrations/053_sessions_node_id_index.d.ts +48 -0
- package/daemon/dist/db/migrations/053_sessions_node_id_index.d.ts.map +1 -0
- package/daemon/dist/db/migrations/053_sessions_node_id_index.js +53 -0
- package/daemon/dist/db/migrations/053_sessions_node_id_index.js.map +1 -0
- package/daemon/dist/db/migrations/054_queue_transitions_archive.d.ts +34 -0
- package/daemon/dist/db/migrations/054_queue_transitions_archive.d.ts.map +1 -0
- package/daemon/dist/db/migrations/054_queue_transitions_archive.js +49 -0
- package/daemon/dist/db/migrations/054_queue_transitions_archive.js.map +1 -0
- package/daemon/dist/domain/claim-service.d.ts +11 -0
- package/daemon/dist/domain/claim-service.d.ts.map +1 -1
- package/daemon/dist/domain/claim-service.js +3 -1
- package/daemon/dist/domain/claim-service.js.map +1 -1
- package/daemon/dist/domain/discovery-types.d.ts +1 -1
- package/daemon/dist/domain/discovery-types.d.ts.map +1 -1
- package/daemon/dist/domain/feed/attention-aggregator.d.ts +31 -0
- package/daemon/dist/domain/feed/attention-aggregator.d.ts.map +1 -0
- package/daemon/dist/domain/feed/attention-aggregator.js +119 -0
- package/daemon/dist/domain/feed/attention-aggregator.js.map +1 -0
- package/daemon/dist/domain/files/file-write-service.d.ts +11 -2
- package/daemon/dist/domain/files/file-write-service.d.ts.map +1 -1
- package/daemon/dist/domain/files/file-write-service.js +77 -0
- package/daemon/dist/domain/files/file-write-service.js.map +1 -1
- package/daemon/dist/domain/hosts/fanout-contract.d.ts +33 -0
- package/daemon/dist/domain/hosts/fanout-contract.d.ts.map +1 -0
- package/daemon/dist/domain/hosts/fanout-contract.js +23 -0
- package/daemon/dist/domain/hosts/fanout-contract.js.map +1 -0
- package/daemon/dist/domain/hosts/hosts-registry-reader.d.ts +50 -0
- package/daemon/dist/domain/hosts/hosts-registry-reader.d.ts.map +1 -0
- package/daemon/dist/domain/hosts/hosts-registry-reader.js +184 -0
- package/daemon/dist/domain/hosts/hosts-registry-reader.js.map +1 -0
- package/daemon/dist/domain/hosts/hosts-registry-writer.d.ts +11 -0
- package/daemon/dist/domain/hosts/hosts-registry-writer.d.ts.map +1 -0
- package/daemon/dist/domain/hosts/hosts-registry-writer.js +54 -0
- package/daemon/dist/domain/hosts/hosts-registry-writer.js.map +1 -0
- package/daemon/dist/domain/hosts/read-through.d.ts +28 -0
- package/daemon/dist/domain/hosts/read-through.d.ts.map +1 -0
- package/daemon/dist/domain/hosts/read-through.js +139 -0
- package/daemon/dist/domain/hosts/read-through.js.map +1 -0
- package/daemon/dist/domain/hosts/remote-daemon-http.d.ts +56 -0
- package/daemon/dist/domain/hosts/remote-daemon-http.d.ts.map +1 -0
- package/daemon/dist/domain/hosts/remote-daemon-http.js +154 -0
- package/daemon/dist/domain/hosts/remote-daemon-http.js.map +1 -0
- package/daemon/dist/domain/human-route-enforcer.d.ts +71 -0
- package/daemon/dist/domain/human-route-enforcer.d.ts.map +1 -0
- package/daemon/dist/domain/human-route-enforcer.js +80 -0
- package/daemon/dist/domain/human-route-enforcer.js.map +1 -0
- package/daemon/dist/domain/mission-control/audit-browse.d.ts +8 -0
- package/daemon/dist/domain/mission-control/audit-browse.d.ts.map +1 -1
- package/daemon/dist/domain/mission-control/audit-browse.js +19 -0
- package/daemon/dist/domain/mission-control/audit-browse.js.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-action-log.d.ts +1 -1
- package/daemon/dist/domain/mission-control/mission-control-action-log.d.ts.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-action-log.js +4 -0
- package/daemon/dist/domain/mission-control/mission-control-action-log.js.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-fleet-cli-capability.js +1 -1
- package/daemon/dist/domain/mission-control/mission-control-fleet-cli-capability.js.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-read-layer.js +1 -1
- package/daemon/dist/domain/mission-control/mission-control-read-layer.js.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-write-contract.d.ts +28 -0
- package/daemon/dist/domain/mission-control/mission-control-write-contract.d.ts.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-write-contract.js +125 -0
- package/daemon/dist/domain/mission-control/mission-control-write-contract.js.map +1 -1
- package/daemon/dist/domain/node-inventory.d.ts +18 -0
- package/daemon/dist/domain/node-inventory.d.ts.map +1 -1
- package/daemon/dist/domain/node-inventory.js +206 -95
- package/daemon/dist/domain/node-inventory.js.map +1 -1
- package/daemon/dist/domain/node-launcher.d.ts +11 -0
- package/daemon/dist/domain/node-launcher.d.ts.map +1 -1
- package/daemon/dist/domain/node-launcher.js +10 -0
- package/daemon/dist/domain/node-launcher.js.map +1 -1
- package/daemon/dist/domain/policies/workflow-keepalive.d.ts +7 -0
- package/daemon/dist/domain/policies/workflow-keepalive.d.ts.map +1 -1
- package/daemon/dist/domain/policies/workflow-keepalive.js +93 -13
- package/daemon/dist/domain/policies/workflow-keepalive.js.map +1 -1
- package/daemon/dist/domain/ps-projection.d.ts +28 -1
- package/daemon/dist/domain/ps-projection.d.ts.map +1 -1
- package/daemon/dist/domain/ps-projection.js +76 -26
- package/daemon/dist/domain/ps-projection.js.map +1 -1
- package/daemon/dist/domain/queue-repository.d.ts +130 -1
- package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
- package/daemon/dist/domain/queue-repository.js +304 -11
- package/daemon/dist/domain/queue-repository.js.map +1 -1
- package/daemon/dist/domain/queue-retention.d.ts +130 -0
- package/daemon/dist/domain/queue-retention.d.ts.map +1 -0
- package/daemon/dist/domain/queue-retention.js +224 -0
- package/daemon/dist/domain/queue-retention.js.map +1 -0
- package/daemon/dist/domain/restore-orchestrator.d.ts +5 -0
- package/daemon/dist/domain/restore-orchestrator.d.ts.map +1 -1
- package/daemon/dist/domain/restore-orchestrator.js +29 -2
- package/daemon/dist/domain/restore-orchestrator.js.map +1 -1
- package/daemon/dist/domain/resume-token-capture.d.ts +13 -0
- package/daemon/dist/domain/resume-token-capture.d.ts.map +1 -1
- package/daemon/dist/domain/resume-token-capture.js +14 -1
- package/daemon/dist/domain/resume-token-capture.js.map +1 -1
- package/daemon/dist/domain/resume-token-validation.d.ts +1 -1
- package/daemon/dist/domain/resume-token-validation.d.ts.map +1 -1
- package/daemon/dist/domain/resume-token-validation.js +58 -10
- package/daemon/dist/domain/resume-token-validation.js.map +1 -1
- package/daemon/dist/domain/review/brief-spine.d.ts +19 -0
- package/daemon/dist/domain/review/brief-spine.d.ts.map +1 -0
- package/daemon/dist/domain/review/brief-spine.js +86 -0
- package/daemon/dist/domain/review/brief-spine.js.map +1 -0
- package/daemon/dist/domain/review/compose.d.ts +277 -0
- package/daemon/dist/domain/review/compose.d.ts.map +1 -0
- package/daemon/dist/domain/review/compose.js +862 -0
- package/daemon/dist/domain/review/compose.js.map +1 -0
- package/daemon/dist/domain/review/fleet-compose.d.ts +52 -0
- package/daemon/dist/domain/review/fleet-compose.d.ts.map +1 -0
- package/daemon/dist/domain/review/fleet-compose.js +294 -0
- package/daemon/dist/domain/review/fleet-compose.js.map +1 -0
- package/daemon/dist/domain/review/freeze.d.ts +31 -0
- package/daemon/dist/domain/review/freeze.d.ts.map +1 -0
- package/daemon/dist/domain/review/freeze.js +257 -0
- package/daemon/dist/domain/review/freeze.js.map +1 -0
- package/daemon/dist/domain/review/gather.d.ts +115 -0
- package/daemon/dist/domain/review/gather.d.ts.map +1 -0
- package/daemon/dist/domain/review/gather.js +812 -0
- package/daemon/dist/domain/review/gather.js.map +1 -0
- package/daemon/dist/domain/review/types.d.ts +361 -0
- package/daemon/dist/domain/review/types.d.ts.map +1 -0
- package/daemon/dist/domain/review/types.js +35 -0
- package/daemon/dist/domain/review/types.js.map +1 -0
- package/daemon/dist/domain/rig-expansion-service.d.ts.map +1 -1
- package/daemon/dist/domain/rig-expansion-service.js +3 -0
- package/daemon/dist/domain/rig-expansion-service.js.map +1 -1
- package/daemon/dist/domain/rig-repository.d.ts +7 -6
- package/daemon/dist/domain/rig-repository.d.ts.map +1 -1
- package/daemon/dist/domain/rig-repository.js +33 -11
- package/daemon/dist/domain/rig-repository.js.map +1 -1
- package/daemon/dist/domain/rigspec-codec.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-codec.js +3 -0
- package/daemon/dist/domain/rigspec-codec.js.map +1 -1
- package/daemon/dist/domain/rigspec-exporter.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-exporter.js +4 -0
- package/daemon/dist/domain/rigspec-exporter.js.map +1 -1
- package/daemon/dist/domain/rigspec-instantiator.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-instantiator.js +11 -0
- package/daemon/dist/domain/rigspec-instantiator.js.map +1 -1
- package/daemon/dist/domain/rigspec-preflight.d.ts +6 -0
- package/daemon/dist/domain/rigspec-preflight.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-preflight.js +26 -1
- package/daemon/dist/domain/rigspec-preflight.js.map +1 -1
- package/daemon/dist/domain/rigspec-schema.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-schema.js +20 -1
- package/daemon/dist/domain/rigspec-schema.js.map +1 -1
- package/daemon/dist/domain/runtime-verifier.d.ts +7 -1
- package/daemon/dist/domain/runtime-verifier.d.ts.map +1 -1
- package/daemon/dist/domain/runtime-verifier.js +39 -1
- package/daemon/dist/domain/runtime-verifier.js.map +1 -1
- package/daemon/dist/domain/scope/scope-approve.d.ts +64 -0
- package/daemon/dist/domain/scope/scope-approve.d.ts.map +1 -0
- package/daemon/dist/domain/scope/scope-approve.js +153 -0
- package/daemon/dist/domain/scope/scope-approve.js.map +1 -0
- package/daemon/dist/domain/scope/scope-audit.d.ts +9 -1
- package/daemon/dist/domain/scope/scope-audit.d.ts.map +1 -1
- package/daemon/dist/domain/scope/scope-audit.js +173 -1
- package/daemon/dist/domain/scope/scope-audit.js.map +1 -1
- package/daemon/dist/domain/seat-handover-service.d.ts +9 -0
- package/daemon/dist/domain/seat-handover-service.d.ts.map +1 -1
- package/daemon/dist/domain/seat-handover-service.js +2 -0
- package/daemon/dist/domain/seat-handover-service.js.map +1 -1
- package/daemon/dist/domain/seat-identity-store.d.ts +7 -0
- package/daemon/dist/domain/seat-identity-store.d.ts.map +1 -1
- package/daemon/dist/domain/seat-identity-store.js +27 -0
- package/daemon/dist/domain/seat-identity-store.js.map +1 -1
- package/daemon/dist/domain/seat-status-service.d.ts.map +1 -1
- package/daemon/dist/domain/seat-status-service.js +6 -4
- package/daemon/dist/domain/seat-status-service.js.map +1 -1
- package/daemon/dist/domain/session-name.d.ts +22 -0
- package/daemon/dist/domain/session-name.d.ts.map +1 -1
- package/daemon/dist/domain/session-name.js +29 -0
- package/daemon/dist/domain/session-name.js.map +1 -1
- package/daemon/dist/domain/slices/slice-detail-projector.d.ts.map +1 -1
- package/daemon/dist/domain/slices/slice-detail-projector.js +4 -5
- package/daemon/dist/domain/slices/slice-detail-projector.js.map +1 -1
- package/daemon/dist/domain/spec-library-workflow-scanner.d.ts +18 -2
- package/daemon/dist/domain/spec-library-workflow-scanner.d.ts.map +1 -1
- package/daemon/dist/domain/spec-library-workflow-scanner.js +23 -1
- package/daemon/dist/domain/spec-library-workflow-scanner.js.map +1 -1
- package/daemon/dist/domain/startup-proof.d.ts +10 -6
- package/daemon/dist/domain/startup-proof.d.ts.map +1 -1
- package/daemon/dist/domain/startup-proof.js +35 -7
- package/daemon/dist/domain/startup-proof.js.map +1 -1
- package/daemon/dist/domain/successor-session-launcher.d.ts +16 -0
- package/daemon/dist/domain/successor-session-launcher.d.ts.map +1 -1
- package/daemon/dist/domain/successor-session-launcher.js +13 -0
- package/daemon/dist/domain/successor-session-launcher.js.map +1 -1
- package/daemon/dist/domain/terminal/cmux-provider-adapter.d.ts +27 -0
- package/daemon/dist/domain/terminal/cmux-provider-adapter.d.ts.map +1 -0
- package/daemon/dist/domain/terminal/cmux-provider-adapter.js +67 -0
- package/daemon/dist/domain/terminal/cmux-provider-adapter.js.map +1 -0
- package/daemon/dist/domain/terminal/herdr-adapter.d.ts +77 -0
- package/daemon/dist/domain/terminal/herdr-adapter.d.ts.map +1 -0
- package/daemon/dist/domain/terminal/herdr-adapter.js +266 -0
- package/daemon/dist/domain/terminal/herdr-adapter.js.map +1 -0
- package/daemon/dist/domain/terminal/herdr-transport.d.ts +50 -0
- package/daemon/dist/domain/terminal/herdr-transport.d.ts.map +1 -0
- package/daemon/dist/domain/terminal/herdr-transport.js +145 -0
- package/daemon/dist/domain/terminal/herdr-transport.js.map +1 -0
- package/daemon/dist/domain/terminal/terminal-provider.d.ts +88 -0
- package/daemon/dist/domain/terminal/terminal-provider.d.ts.map +1 -0
- package/daemon/dist/domain/terminal/terminal-provider.js +17 -0
- package/daemon/dist/domain/terminal/terminal-provider.js.map +1 -0
- package/daemon/dist/domain/terminal/terminal-service.d.ts +60 -0
- package/daemon/dist/domain/terminal/terminal-service.d.ts.map +1 -0
- package/daemon/dist/domain/terminal/terminal-service.js +174 -0
- package/daemon/dist/domain/terminal/terminal-service.js.map +1 -0
- package/daemon/dist/domain/terminal/terminal-views-store.d.ts +77 -0
- package/daemon/dist/domain/terminal/terminal-views-store.d.ts.map +1 -0
- package/daemon/dist/domain/terminal/terminal-views-store.js +146 -0
- package/daemon/dist/domain/terminal/terminal-views-store.js.map +1 -0
- package/daemon/dist/domain/terminal/view-composer.d.ts +42 -0
- package/daemon/dist/domain/terminal/view-composer.d.ts.map +1 -0
- package/daemon/dist/domain/terminal/view-composer.js +137 -0
- package/daemon/dist/domain/terminal/view-composer.js.map +1 -0
- package/daemon/dist/domain/tmux-option-defaults.d.ts +89 -0
- package/daemon/dist/domain/tmux-option-defaults.d.ts.map +1 -0
- package/daemon/dist/domain/tmux-option-defaults.js +132 -0
- package/daemon/dist/domain/tmux-option-defaults.js.map +1 -0
- package/daemon/dist/domain/topology/multi-rig-launcher.d.ts +49 -0
- package/daemon/dist/domain/topology/multi-rig-launcher.d.ts.map +1 -0
- package/daemon/dist/domain/topology/multi-rig-launcher.js +132 -0
- package/daemon/dist/domain/topology/multi-rig-launcher.js.map +1 -0
- package/daemon/dist/domain/topology/remote-up-leaf.d.ts +29 -0
- package/daemon/dist/domain/topology/remote-up-leaf.d.ts.map +1 -0
- package/daemon/dist/domain/topology/remote-up-leaf.js +60 -0
- package/daemon/dist/domain/topology/remote-up-leaf.js.map +1 -0
- package/daemon/dist/domain/topology/topology-manifest.d.ts +34 -0
- package/daemon/dist/domain/topology/topology-manifest.d.ts.map +1 -0
- package/daemon/dist/domain/topology/topology-manifest.js +195 -0
- package/daemon/dist/domain/topology/topology-manifest.js.map +1 -0
- package/daemon/dist/domain/types.d.ts +39 -1
- package/daemon/dist/domain/types.d.ts.map +1 -1
- package/daemon/dist/domain/types.js.map +1 -1
- package/daemon/dist/domain/up-command-router.d.ts +1 -1
- package/daemon/dist/domain/up-command-router.d.ts.map +1 -1
- package/daemon/dist/domain/up-command-router.js +34 -2
- package/daemon/dist/domain/up-command-router.js.map +1 -1
- package/daemon/dist/domain/user-settings/settings-store.d.ts +18 -1
- package/daemon/dist/domain/user-settings/settings-store.d.ts.map +1 -1
- package/daemon/dist/domain/user-settings/settings-store.js +201 -0
- package/daemon/dist/domain/user-settings/settings-store.js.map +1 -1
- package/daemon/dist/domain/workflow/slice-workflow-projection.d.ts.map +1 -1
- package/daemon/dist/domain/workflow/slice-workflow-projection.js +6 -2
- package/daemon/dist/domain/workflow/slice-workflow-projection.js.map +1 -1
- package/daemon/dist/domain/workflow-boot-sweep.d.ts +28 -0
- package/daemon/dist/domain/workflow-boot-sweep.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-boot-sweep.js +102 -0
- package/daemon/dist/domain/workflow-boot-sweep.js.map +1 -0
- package/daemon/dist/domain/workflow-deadline.d.ts +74 -0
- package/daemon/dist/domain/workflow-deadline.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-deadline.js +165 -0
- package/daemon/dist/domain/workflow-deadline.js.map +1 -0
- package/daemon/dist/domain/workflow-exception-escalation.d.ts +33 -0
- package/daemon/dist/domain/workflow-exception-escalation.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-exception-escalation.js +104 -0
- package/daemon/dist/domain/workflow-exception-escalation.js.map +1 -0
- package/daemon/dist/domain/workflow-exception-router.d.ts +33 -0
- package/daemon/dist/domain/workflow-exception-router.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-exception-router.js +96 -0
- package/daemon/dist/domain/workflow-exception-router.js.map +1 -0
- package/daemon/dist/domain/workflow-exception.d.ts +90 -0
- package/daemon/dist/domain/workflow-exception.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-exception.js +122 -0
- package/daemon/dist/domain/workflow-exception.js.map +1 -0
- package/daemon/dist/domain/workflow-frontier-guard.d.ts +24 -0
- package/daemon/dist/domain/workflow-frontier-guard.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-frontier-guard.js +30 -0
- package/daemon/dist/domain/workflow-frontier-guard.js.map +1 -0
- package/daemon/dist/domain/workflow-instance-store.d.ts +28 -0
- package/daemon/dist/domain/workflow-instance-store.d.ts.map +1 -1
- package/daemon/dist/domain/workflow-instance-store.js +66 -10
- package/daemon/dist/domain/workflow-instance-store.js.map +1 -1
- package/daemon/dist/domain/workflow-keepalive-arming.d.ts +35 -0
- package/daemon/dist/domain/workflow-keepalive-arming.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-keepalive-arming.js +87 -0
- package/daemon/dist/domain/workflow-keepalive-arming.js.map +1 -0
- package/daemon/dist/domain/workflow-projector.d.ts +117 -2
- package/daemon/dist/domain/workflow-projector.d.ts.map +1 -1
- package/daemon/dist/domain/workflow-projector.js +672 -41
- package/daemon/dist/domain/workflow-projector.js.map +1 -1
- package/daemon/dist/domain/workflow-role-context.d.ts +57 -0
- package/daemon/dist/domain/workflow-role-context.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-role-context.js +120 -0
- package/daemon/dist/domain/workflow-role-context.js.map +1 -0
- package/daemon/dist/domain/workflow-role-resolver.d.ts +65 -0
- package/daemon/dist/domain/workflow-role-resolver.d.ts.map +1 -0
- package/daemon/dist/domain/workflow-role-resolver.js +108 -0
- package/daemon/dist/domain/workflow-role-resolver.js.map +1 -0
- package/daemon/dist/domain/workflow-runtime.d.ts +157 -1
- package/daemon/dist/domain/workflow-runtime.d.ts.map +1 -1
- package/daemon/dist/domain/workflow-runtime.js +718 -11
- package/daemon/dist/domain/workflow-runtime.js.map +1 -1
- package/daemon/dist/domain/workflow-spec-cache.d.ts +26 -1
- package/daemon/dist/domain/workflow-spec-cache.d.ts.map +1 -1
- package/daemon/dist/domain/workflow-spec-cache.js +327 -13
- package/daemon/dist/domain/workflow-spec-cache.js.map +1 -1
- package/daemon/dist/domain/workflow-types.d.ts +143 -8
- package/daemon/dist/domain/workflow-types.d.ts.map +1 -1
- package/daemon/dist/domain/workflow-types.js +14 -1
- package/daemon/dist/domain/workflow-types.js.map +1 -1
- package/daemon/dist/domain/workflow-validator.d.ts +11 -1
- package/daemon/dist/domain/workflow-validator.d.ts.map +1 -1
- package/daemon/dist/domain/workflow-validator.js +246 -1
- package/daemon/dist/domain/workflow-validator.js.map +1 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.d.ts.map +1 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js +51 -6
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js.map +1 -1
- package/daemon/dist/domain/workspace/workspace-doctor.d.ts +11 -0
- package/daemon/dist/domain/workspace/workspace-doctor.d.ts.map +1 -1
- package/daemon/dist/domain/workspace/workspace-doctor.js +82 -0
- package/daemon/dist/domain/workspace/workspace-doctor.js.map +1 -1
- package/daemon/dist/index.d.ts +17 -0
- package/daemon/dist/index.d.ts.map +1 -1
- package/daemon/dist/index.js +44 -0
- package/daemon/dist/index.js.map +1 -1
- package/daemon/dist/routes/activity.js +22 -0
- package/daemon/dist/routes/activity.js.map +1 -1
- package/daemon/dist/routes/config.d.ts.map +1 -1
- package/daemon/dist/routes/config.js +15 -6
- package/daemon/dist/routes/config.js.map +1 -1
- package/daemon/dist/routes/files.d.ts.map +1 -1
- package/daemon/dist/routes/files.js +45 -1
- package/daemon/dist/routes/files.js.map +1 -1
- package/daemon/dist/routes/hosts.d.ts +5 -0
- package/daemon/dist/routes/hosts.d.ts.map +1 -0
- package/daemon/dist/routes/hosts.js +346 -0
- package/daemon/dist/routes/hosts.js.map +1 -0
- package/daemon/dist/routes/mission-control.d.ts.map +1 -1
- package/daemon/dist/routes/mission-control.js +67 -2
- package/daemon/dist/routes/mission-control.js.map +1 -1
- package/daemon/dist/routes/queue.d.ts +10 -9
- package/daemon/dist/routes/queue.d.ts.map +1 -1
- package/daemon/dist/routes/queue.js +305 -10
- package/daemon/dist/routes/queue.js.map +1 -1
- package/daemon/dist/routes/review.d.ts +3 -0
- package/daemon/dist/routes/review.d.ts.map +1 -0
- package/daemon/dist/routes/review.js +195 -0
- package/daemon/dist/routes/review.js.map +1 -0
- package/daemon/dist/routes/scope-approve.d.ts +3 -0
- package/daemon/dist/routes/scope-approve.d.ts.map +1 -0
- package/daemon/dist/routes/scope-approve.js +55 -0
- package/daemon/dist/routes/scope-approve.js.map +1 -0
- package/daemon/dist/routes/scope-audit.d.ts.map +1 -1
- package/daemon/dist/routes/scope-audit.js +28 -1
- package/daemon/dist/routes/scope-audit.js.map +1 -1
- package/daemon/dist/routes/seat.js +13 -0
- package/daemon/dist/routes/seat.js.map +1 -1
- package/daemon/dist/routes/slices.d.ts.map +1 -1
- package/daemon/dist/routes/slices.js +49 -9
- package/daemon/dist/routes/slices.js.map +1 -1
- package/daemon/dist/routes/terminal-ws.d.ts.map +1 -1
- package/daemon/dist/routes/terminal-ws.js +58 -21
- package/daemon/dist/routes/terminal-ws.js.map +1 -1
- package/daemon/dist/routes/terminal.d.ts +11 -0
- package/daemon/dist/routes/terminal.d.ts.map +1 -0
- package/daemon/dist/routes/terminal.js +104 -0
- package/daemon/dist/routes/terminal.js.map +1 -0
- package/daemon/dist/routes/up.d.ts.map +1 -1
- package/daemon/dist/routes/up.js +84 -0
- package/daemon/dist/routes/up.js.map +1 -1
- package/daemon/dist/routes/workflow.d.ts.map +1 -1
- package/daemon/dist/routes/workflow.js +102 -10
- package/daemon/dist/routes/workflow.js.map +1 -1
- package/daemon/dist/routes/workspace.js +2 -2
- package/daemon/dist/server.d.ts +6 -0
- package/daemon/dist/server.d.ts.map +1 -1
- package/daemon/dist/server.js +36 -1
- package/daemon/dist/server.js.map +1 -1
- package/daemon/dist/startup.d.ts.map +1 -1
- package/daemon/dist/startup.js +238 -14
- package/daemon/dist/startup.js.map +1 -1
- package/daemon/docs/reference/agent-startup-guide.md +1 -1
- package/daemon/docs/reference/product-factory-vps-runbook.md +132 -0
- package/daemon/docs/reference/sdlc-conventions.md +187 -0
- package/daemon/specs/agents/conveyor/builder/agent.yaml +1 -1
- package/daemon/specs/agents/conveyor/builder/guidance/role.md +1 -0
- package/daemon/specs/agents/conveyor/lead/agent.yaml +1 -1
- package/daemon/specs/agents/conveyor/lead/guidance/role.md +1 -0
- package/daemon/specs/agents/conveyor/planner/agent.yaml +1 -1
- package/daemon/specs/agents/conveyor/planner/guidance/role.md +1 -0
- package/daemon/specs/agents/conveyor/reviewer/agent.yaml +1 -1
- package/daemon/specs/agents/conveyor/reviewer/guidance/role.md +1 -0
- package/daemon/specs/agents/design/product-designer/agent.yaml +1 -1
- package/daemon/specs/agents/design/product-designer/guidance/role.md +1 -0
- package/daemon/specs/agents/development/implementer/agent.yaml +1 -1
- package/daemon/specs/agents/development/implementer/guidance/role.md +1 -0
- package/daemon/specs/agents/development/qa/agent.yaml +1 -1
- package/daemon/specs/agents/development/qa/guidance/role.md +1 -0
- package/daemon/specs/agents/factory-rsi/dogfood/agent.yaml +29 -0
- package/daemon/specs/agents/factory-rsi/dogfood/guidance/role.md +37 -0
- package/daemon/specs/agents/factory-rsi/release-manager/agent.yaml +29 -0
- package/daemon/specs/agents/factory-rsi/release-manager/guidance/role.md +40 -0
- package/daemon/specs/agents/orchestration/orchestrator/agent.yaml +1 -1
- package/daemon/specs/agents/orchestration/orchestrator/guidance/role.md +1 -0
- package/daemon/specs/agents/product-management/pm/agent.yaml +1 -0
- package/daemon/specs/agents/product-management/pm/guidance/role.md +13 -0
- package/daemon/specs/agents/review/independent-reviewer/agent.yaml +1 -1
- package/daemon/specs/agents/review/independent-reviewer/guidance/role.md +1 -0
- package/daemon/specs/agents/shared/agent.yaml +2 -0
- package/daemon/specs/agents/shared/skills/core/mission-slice-sop/SKILL.md +113 -0
- package/daemon/specs/agents/shared/skills/core/openrig-cmux/SKILL.md +86 -0
- package/daemon/specs/agents/shared/skills/core/openrig-herdr/SKILL.md +158 -0
- package/daemon/specs/agents/shared/skills/core/openrig-operator/SKILL.md +4 -4
- package/daemon/specs/agents/shared/skills/core/openrig-user/SKILL.md +75 -29
- package/daemon/specs/agents/shared/skills/pods/orchestration-team/SKILL.md +2 -2
- package/daemon/specs/rigs/focused/pm-team/CULTURE.md +4 -0
- package/daemon/specs/rigs/launch/factory-rsi/CULTURE.md +47 -0
- package/daemon/specs/rigs/launch/factory-rsi/rig.yaml +115 -0
- package/daemon/specs/rigs/launch/kernel/agents/operator/agent/guidance/role.md +1 -1
- package/daemon/specs/rigs/launch/kernel/agents/operator/agent/startup/context.md +1 -1
- package/daemon/specs/rigs/preview/product-team/CULTURE.md +4 -0
- package/dist/build-info.d.ts +8 -0
- package/dist/build-info.d.ts.map +1 -0
- package/dist/build-info.js +11 -0
- package/dist/build-info.js.map +1 -0
- package/dist/commands/broadcast.d.ts +6 -1
- package/dist/commands/broadcast.d.ts.map +1 -1
- package/dist/commands/broadcast.js +101 -15
- package/dist/commands/broadcast.js.map +1 -1
- package/dist/commands/capture.d.ts.map +1 -1
- package/dist/commands/capture.js +99 -8
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/config-init-workspace.d.ts.map +1 -1
- package/dist/commands/config-init-workspace.js +20 -4
- package/dist/commands/config-init-workspace.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +4 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/down.d.ts.map +1 -1
- package/dist/commands/down.js +5 -0
- package/dist/commands/down.js.map +1 -1
- package/dist/commands/expand.js +1 -1
- package/dist/commands/expand.js.map +1 -1
- package/dist/commands/file.d.ts +7 -0
- package/dist/commands/file.d.ts.map +1 -0
- package/dist/commands/file.js +77 -0
- package/dist/commands/file.js.map +1 -0
- package/dist/commands/host.d.ts +48 -0
- package/dist/commands/host.d.ts.map +1 -0
- package/dist/commands/host.js +772 -0
- package/dist/commands/host.js.map +1 -0
- package/dist/commands/launch.d.ts.map +1 -1
- package/dist/commands/launch.js +5 -0
- package/dist/commands/launch.js.map +1 -1
- package/dist/commands/proof.d.ts +54 -0
- package/dist/commands/proof.d.ts.map +1 -0
- package/dist/commands/proof.js +311 -0
- package/dist/commands/proof.js.map +1 -0
- package/dist/commands/ps.d.ts +41 -7
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +353 -135
- package/dist/commands/ps.js.map +1 -1
- package/dist/commands/queue.d.ts +36 -0
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/queue.js +149 -7
- package/dist/commands/queue.js.map +1 -1
- package/dist/commands/restore-packet.d.ts.map +1 -1
- package/dist/commands/restore-packet.js +13 -2
- package/dist/commands/restore-packet.js.map +1 -1
- package/dist/commands/scope.d.ts.map +1 -1
- package/dist/commands/scope.js +140 -3
- package/dist/commands/scope.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +127 -13
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/terminal.d.ts +6 -0
- package/dist/commands/terminal.d.ts.map +1 -0
- package/dist/commands/terminal.js +116 -0
- package/dist/commands/terminal.js.map +1 -0
- package/dist/commands/transcript.d.ts +6 -1
- package/dist/commands/transcript.d.ts.map +1 -1
- package/dist/commands/transcript.js +113 -30
- package/dist/commands/transcript.js.map +1 -1
- package/dist/commands/up.d.ts +2 -0
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +78 -2
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +11 -0
- package/dist/commands/whoami.js.map +1 -1
- package/dist/commands/workflow-errors.d.ts +23 -0
- package/dist/commands/workflow-errors.d.ts.map +1 -0
- package/dist/commands/workflow-errors.js +100 -0
- package/dist/commands/workflow-errors.js.map +1 -0
- package/dist/commands/workflow-follow.d.ts +71 -0
- package/dist/commands/workflow-follow.d.ts.map +1 -0
- package/dist/commands/workflow-follow.js +259 -0
- package/dist/commands/workflow-follow.js.map +1 -0
- package/dist/commands/workflow-render.d.ts +114 -0
- package/dist/commands/workflow-render.d.ts.map +1 -0
- package/dist/commands/workflow-render.js +223 -0
- package/dist/commands/workflow-render.js.map +1 -0
- package/dist/commands/workflow.d.ts +1 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +278 -14
- package/dist/commands/workflow.js.map +1 -1
- package/dist/commands/workspace.js +6 -6
- package/dist/commands/workspace.js.map +1 -1
- package/dist/config-store.d.ts +19 -1
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +171 -0
- package/dist/config-store.js.map +1 -1
- package/dist/cross-host-cli-helpers.d.ts +13 -0
- package/dist/cross-host-cli-helpers.d.ts.map +1 -1
- package/dist/cross-host-cli-helpers.js +27 -0
- package/dist/cross-host-cli-helpers.js.map +1 -1
- package/dist/cross-host-executor.d.ts +1 -0
- package/dist/cross-host-executor.d.ts.map +1 -1
- package/dist/cross-host-executor.js +4 -1
- package/dist/cross-host-executor.js.map +1 -1
- package/dist/cross-host-target.d.ts +49 -0
- package/dist/cross-host-target.d.ts.map +1 -0
- package/dist/cross-host-target.js +35 -0
- package/dist/cross-host-target.js.map +1 -0
- package/dist/daemon-lifecycle.d.ts.map +1 -1
- package/dist/daemon-lifecycle.js +4 -1
- package/dist/daemon-lifecycle.js.map +1 -1
- package/dist/host-registry.d.ts +17 -0
- package/dist/host-registry.d.ts.map +1 -1
- package/dist/host-registry.js +64 -2
- package/dist/host-registry.js.map +1 -1
- package/dist/host-selection.d.ts +13 -0
- package/dist/host-selection.d.ts.map +1 -0
- package/dist/host-selection.js +54 -0
- package/dist/host-selection.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/file-transfer.d.ts +89 -0
- package/dist/lib/file-transfer.d.ts.map +1 -0
- package/dist/lib/file-transfer.js +300 -0
- package/dist/lib/file-transfer.js.map +1 -0
- package/dist/lib/hosts/fanout-contract.d.ts +33 -0
- package/dist/lib/hosts/fanout-contract.d.ts.map +1 -0
- package/dist/lib/hosts/fanout-contract.js +23 -0
- package/dist/lib/hosts/fanout-contract.js.map +1 -0
- package/dist/lib/scope/scope-audit.d.ts +9 -1
- package/dist/lib/scope/scope-audit.d.ts.map +1 -1
- package/dist/lib/scope/scope-audit.js +173 -1
- package/dist/lib/scope/scope-audit.js.map +1 -1
- package/dist/lib/scope/templates.d.ts +1 -0
- package/dist/lib/scope/templates.d.ts.map +1 -1
- package/dist/lib/scope/templates.js +9 -0
- package/dist/lib/scope/templates.js.map +1 -1
- package/dist/lib/scope-templates/backlog-deprecation.md +16 -0
- package/dist/lib/scope-templates/backlog-tech-debt.md +16 -0
- package/dist/lib/scope-templates/bug-fix.md +16 -0
- package/dist/lib/scope-templates/implementation-prd.md +33 -0
- package/dist/lib/scope-templates/mission-placeholder.md +1 -1
- package/dist/lib/scope-templates/mission-progress.md +1 -1
- package/dist/lib/scope-templates/mission-release.md +1 -1
- package/dist/lib/scope-templates/placeholder.md +11 -7
- package/dist/lib/scope-templates/proof.md +5 -1
- package/dist/lib/scope-templates/release-feature.md +14 -6
- package/dist/lib/scope-templates/research.md +16 -0
- package/dist/lib/scope-templates/slice-progress.md +1 -1
- package/dist/remote-host-ops.d.ts +1 -0
- package/dist/remote-host-ops.d.ts.map +1 -1
- package/dist/remote-host-ops.js +11 -4
- package/dist/remote-host-ops.js.map +1 -1
- package/dist/session-name.d.ts +23 -0
- package/dist/session-name.d.ts.map +1 -0
- package/dist/session-name.js +61 -0
- package/dist/session-name.js.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +11 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
- package/ui/dist/assets/index-CFqxa0zW.css +32 -0
- package/ui/dist/assets/index-zrFqS7gL.js +623 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-DYZniQcc.js +0 -597
- package/ui/dist/assets/index-trcb4Yf_.css +0 -32
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
// Living Notes — the deterministic composer (OPR.0.4.4.20, rebuilt per the
|
|
2
|
+
// CORRECTIVE REDESIGN of 2026-07-05).
|
|
3
|
+
//
|
|
4
|
+
// PURE: `(gathered inputs) -> composed doc`. Same inputs (including the
|
|
5
|
+
// caller-supplied view-time facts nowIso/mainTip/git facts) -> byte-identical
|
|
6
|
+
// output. Every section has a named SSOT and a degrade value; a missing
|
|
7
|
+
// source renders its degrade, never invented content. The gatherer that
|
|
8
|
+
// assembles inputs from disk/queue/git lives beside this file; keeping the
|
|
9
|
+
// core pure is what makes the idempotence AC hold by construction.
|
|
10
|
+
//
|
|
11
|
+
// CORRECTIVE §3.1 — the composer builds ONE renderable structure per slice:
|
|
12
|
+
// the INTENT → PLAN → DELIVERED stack. It no longer emits `sections`,
|
|
13
|
+
// `acceptance`, `compare`, `join`, or a coequal `green` field. The
|
|
14
|
+
// recorded-verdict rigor behind the old green lives on in two places only:
|
|
15
|
+
// the per-deliverable `verified` signal (§11) and the mission ledger's
|
|
16
|
+
// completion green (FR-7 — a mission-altitude fact, not a slice structure).
|
|
17
|
+
import YAML from "yaml";
|
|
18
|
+
import * as posixPath from "node:path/posix";
|
|
19
|
+
import { renderBriefSpine } from "./brief-spine.js";
|
|
20
|
+
import { C1_ARTIFACT_TYPES, C1_VERDICTS, GATE_ROLES, PHASE_LANE_LABELS, } from "./types.js";
|
|
21
|
+
// --- Fixed, visible v1 thresholds (markdown-steered tuning is a named fast-follow) ---
|
|
22
|
+
export const IDLE_WITH_WORK_THRESHOLD_MIN = 30;
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Media refs (shared shape helpers — pure string work, no filesystem)
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
const IMAGE_EXTS = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"]);
|
|
27
|
+
const VIDEO_EXTS = new Set([".mp4", ".webm", ".mov", ".m4v"]);
|
|
28
|
+
function extOf(ref) {
|
|
29
|
+
const clean = ref.split(/[?#]/)[0];
|
|
30
|
+
const i = clean.lastIndexOf(".");
|
|
31
|
+
return i === -1 ? "" : clean.slice(i).toLowerCase();
|
|
32
|
+
}
|
|
33
|
+
export function mediaKind(ref) {
|
|
34
|
+
const ext = extOf(ref);
|
|
35
|
+
if (IMAGE_EXTS.has(ext))
|
|
36
|
+
return "image";
|
|
37
|
+
if (VIDEO_EXTS.has(ext))
|
|
38
|
+
return "video";
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/** Markdown/HTML media refs in a source string (http(s) refs excluded —
|
|
42
|
+
* media is co-located slice content, FR-5). */
|
|
43
|
+
export function extractMediaRefs(markdown) {
|
|
44
|
+
if (!markdown)
|
|
45
|
+
return [];
|
|
46
|
+
const refs = [];
|
|
47
|
+
const re = /!\[[^\]]*\]\(([^)]+)\)|<(?:video|img|source)[^>]*\ssrc="([^"]+)"/g;
|
|
48
|
+
for (const m of markdown.matchAll(re)) {
|
|
49
|
+
const ref = (m[1] ?? m[2] ?? "").trim();
|
|
50
|
+
if (ref && !ref.startsWith("http"))
|
|
51
|
+
refs.push(ref);
|
|
52
|
+
}
|
|
53
|
+
return refs;
|
|
54
|
+
}
|
|
55
|
+
/** Normalizes a media ref written relative to `baseDir` (slice-relative "")
|
|
56
|
+
* into a slice-relative path. Returns null when the ref is absolute or
|
|
57
|
+
* escapes the slice dir — the caller records the defect (FR-5), never a
|
|
58
|
+
* silent drop. */
|
|
59
|
+
export function sliceRelativeMediaPath(ref, baseDir) {
|
|
60
|
+
if (ref.startsWith("/"))
|
|
61
|
+
return null;
|
|
62
|
+
const joined = baseDir ? posixPath.join(baseDir, ref) : ref;
|
|
63
|
+
const normalized = posixPath.normalize(joined);
|
|
64
|
+
if (normalized === ".." || normalized.startsWith("../"))
|
|
65
|
+
return null;
|
|
66
|
+
return normalized;
|
|
67
|
+
}
|
|
68
|
+
function toReviewMedia(ref, baseDir) {
|
|
69
|
+
const kind = mediaKind(ref);
|
|
70
|
+
if (!kind)
|
|
71
|
+
return null;
|
|
72
|
+
const src = sliceRelativeMediaPath(ref, baseDir);
|
|
73
|
+
if (!src)
|
|
74
|
+
return null;
|
|
75
|
+
return { kind, src, caption: ref };
|
|
76
|
+
}
|
|
77
|
+
function dedupMedia(media) {
|
|
78
|
+
const seen = new Set();
|
|
79
|
+
return media.filter((m) => {
|
|
80
|
+
if (seen.has(m.src))
|
|
81
|
+
return false;
|
|
82
|
+
seen.add(m.src);
|
|
83
|
+
return true;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// C1 header parsing
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
/** Parses a proof artifact's YAML frontmatter into a ProofArtifact.
|
|
90
|
+
* Out-of-set / missing verdicts become null (a present artifact is not a
|
|
91
|
+
* verdict — FR-2); the parse never throws on malformed input. Body media
|
|
92
|
+
* refs are captured for the §3.4 curated-proof projection. */
|
|
93
|
+
export function parseC1Header(content, relPath, droppedAtIso) {
|
|
94
|
+
const out = {
|
|
95
|
+
relPath,
|
|
96
|
+
slice: null,
|
|
97
|
+
candidateSha: null,
|
|
98
|
+
artifactType: null,
|
|
99
|
+
verdict: null,
|
|
100
|
+
moneyEvidence: null,
|
|
101
|
+
evidences: [],
|
|
102
|
+
selfCheck: null,
|
|
103
|
+
mediaRefs: [],
|
|
104
|
+
droppedAt: droppedAtIso,
|
|
105
|
+
};
|
|
106
|
+
const m = content.match(/^---\n([\s\S]*?)\n---/);
|
|
107
|
+
out.mediaRefs = extractMediaRefs(m ? content.slice(m[0].length) : content);
|
|
108
|
+
if (!m)
|
|
109
|
+
return out;
|
|
110
|
+
let fm;
|
|
111
|
+
try {
|
|
112
|
+
fm = (YAML.parse(m[1]) ?? {});
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
const str = (v) => (typeof v === "string" && v.trim() ? v.trim() : v != null && typeof v !== "object" ? String(v) : null);
|
|
118
|
+
out.slice = str(fm["slice"]);
|
|
119
|
+
out.candidateSha = str(fm["candidate_sha"]);
|
|
120
|
+
const at = str(fm["artifact_type"]);
|
|
121
|
+
out.artifactType = at && C1_ARTIFACT_TYPES.includes(at) ? at : null;
|
|
122
|
+
const v = str(fm["verdict"]);
|
|
123
|
+
out.verdict = v && C1_VERDICTS.includes(v) ? v : null;
|
|
124
|
+
out.moneyEvidence = str(fm["money_evidence"]);
|
|
125
|
+
out.selfCheck = str(fm["self_check"]);
|
|
126
|
+
const ev = fm["evidences"];
|
|
127
|
+
if (Array.isArray(ev))
|
|
128
|
+
out.evidences = ev.map((e) => String(e)).filter((e) => e.trim().length > 0);
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// FR-2 — verdict selection, pass-mapping, lineage (KEEP)
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
/** The pinned pass-mapping ("passing" is never left to interpretation). */
|
|
135
|
+
export function isPassing(artifactType, verdict) {
|
|
136
|
+
if (verdict === null)
|
|
137
|
+
return false;
|
|
138
|
+
if (artifactType === "qa")
|
|
139
|
+
return verdict === "PASS";
|
|
140
|
+
if (artifactType === "adjudication")
|
|
141
|
+
return verdict === "CLEAR" || verdict === "PASS";
|
|
142
|
+
// guard, rev1-r1, rev1-r2
|
|
143
|
+
return verdict === "CLEAR";
|
|
144
|
+
}
|
|
145
|
+
function toneFor(artifactType, verdict) {
|
|
146
|
+
if (verdict === null)
|
|
147
|
+
return "unknown";
|
|
148
|
+
return isPassing(artifactType, verdict) ? "pass" : "fail";
|
|
149
|
+
}
|
|
150
|
+
/** Latest-wins per (candidate_sha, artifact_type) — the ratified C1 selection
|
|
151
|
+
* rule. A non-passing verdict is superseded only by a LATER artifact of the
|
|
152
|
+
* SAME tuple, never by adjacent artifacts, presence, or approval. */
|
|
153
|
+
export function selectWinning(artifacts, candidateSha) {
|
|
154
|
+
const winning = new Map();
|
|
155
|
+
for (const a of artifacts) {
|
|
156
|
+
if (!a.artifactType)
|
|
157
|
+
continue;
|
|
158
|
+
if (candidateSha !== null && a.candidateSha !== candidateSha)
|
|
159
|
+
continue;
|
|
160
|
+
const prev = winning.get(a.artifactType);
|
|
161
|
+
if (!prev || a.droppedAt > prev.droppedAt || (a.droppedAt === prev.droppedAt && a.relPath > prev.relPath)) {
|
|
162
|
+
winning.set(a.artifactType, a);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return winning;
|
|
166
|
+
}
|
|
167
|
+
/** The candidate under judgment: the candidate_sha of the latest-dropped gate
|
|
168
|
+
* artifact (deterministic; ties broken by relPath). Null when no artifact
|
|
169
|
+
* carries one. */
|
|
170
|
+
export function deriveCandidateSha(artifacts) {
|
|
171
|
+
let best = null;
|
|
172
|
+
for (const a of artifacts) {
|
|
173
|
+
if (!a.candidateSha || !a.artifactType || a.artifactType === "adjudication")
|
|
174
|
+
continue;
|
|
175
|
+
if (!best || a.droppedAt > best.droppedAt || (a.droppedAt === best.droppedAt && a.relPath > best.relPath))
|
|
176
|
+
best = a;
|
|
177
|
+
}
|
|
178
|
+
return best?.candidateSha ?? null;
|
|
179
|
+
}
|
|
180
|
+
export function deriveGateCells(artifacts, candidateSha) {
|
|
181
|
+
const winning = selectWinning(artifacts, candidateSha);
|
|
182
|
+
return GATE_ROLES.map((role) => {
|
|
183
|
+
const a = winning.get(role);
|
|
184
|
+
if (!a || a.verdict === null) {
|
|
185
|
+
return { role, recordedToken: null, tone: "unknown", state: "missing", source: a?.relPath ?? null };
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
role,
|
|
189
|
+
recordedToken: a.verdict,
|
|
190
|
+
tone: toneFor(role, a.verdict),
|
|
191
|
+
state: isPassing(role, a.verdict) ? "passing" : "non-passing",
|
|
192
|
+
source: a.relPath,
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/** Near-tip tolerance for the pre-merge fresh label. */
|
|
197
|
+
const FRESH_BEHIND_TOLERANCE = 3;
|
|
198
|
+
export function composeLineage(candidateSha, git, gateCells) {
|
|
199
|
+
let freshness = "unknown";
|
|
200
|
+
let staleBehind = null;
|
|
201
|
+
if (git.mergeSha !== null) {
|
|
202
|
+
if (git.mergeIsAncestorOfTip !== null)
|
|
203
|
+
freshness = git.mergeIsAncestorOfTip ? "fresh" : "stale";
|
|
204
|
+
}
|
|
205
|
+
else if (candidateSha !== null && git.candidateBehindTip !== null) {
|
|
206
|
+
if (git.candidateBehindTip <= FRESH_BEHIND_TOLERANCE) {
|
|
207
|
+
freshness = "fresh";
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
freshness = "stale";
|
|
211
|
+
staleBehind = git.candidateBehindTip;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return { candidateSha, mergeSha: git.mergeSha, mainTip: git.mainTip, freshness, staleBehind, gateCells };
|
|
215
|
+
}
|
|
216
|
+
export function lockFrom(stamp) {
|
|
217
|
+
if (!stamp)
|
|
218
|
+
return null;
|
|
219
|
+
return { by: stamp.by, at: stamp.at, auditVerified: stamp.auditRowPresent };
|
|
220
|
+
}
|
|
221
|
+
export function computeRecordedGreen(gateCells, artifacts, candidateSha) {
|
|
222
|
+
if (gateCells.every((c) => c.state === "passing"))
|
|
223
|
+
return { green: true, regime: 1 };
|
|
224
|
+
const adjudication = selectWinning(artifacts, candidateSha).get("adjudication");
|
|
225
|
+
if (adjudication && isPassing("adjudication", adjudication.verdict))
|
|
226
|
+
return { green: true, regime: 2 };
|
|
227
|
+
return { green: false, regime: null };
|
|
228
|
+
}
|
|
229
|
+
/** Convenience for the mission gatherer: derive the ledger green straight
|
|
230
|
+
* from a slice's artifacts (candidate + gate cells derived internally). */
|
|
231
|
+
export function composeRecordedGreenForSlice(artifacts) {
|
|
232
|
+
const candidateSha = deriveCandidateSha(artifacts);
|
|
233
|
+
return computeRecordedGreen(deriveGateCells(artifacts, candidateSha), artifacts, candidateSha);
|
|
234
|
+
}
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
// FR-1 — markdown structure extraction (KEEP the extractors; the sections/
|
|
237
|
+
// acceptance/compare structures they used to feed are gone)
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
/** Extracts a `## <heading>` section body, verbatim (character-identical). */
|
|
240
|
+
export function extractSection(markdown, heading) {
|
|
241
|
+
if (!markdown)
|
|
242
|
+
return null;
|
|
243
|
+
const re = new RegExp(`^##\\s+${heading}\\s*$`, "im");
|
|
244
|
+
const m = re.exec(markdown);
|
|
245
|
+
if (!m)
|
|
246
|
+
return null;
|
|
247
|
+
const start = m.index + m[0].length;
|
|
248
|
+
const rest = markdown.slice(start);
|
|
249
|
+
const next = rest.search(/^##?\s/m);
|
|
250
|
+
const body = next === -1 ? rest : rest.slice(0, next);
|
|
251
|
+
return body.replace(/^\n+/, "").replace(/\s+$/, "");
|
|
252
|
+
}
|
|
253
|
+
/** The pinned mini-requirements tier at the PRD top (plan.concise.text). */
|
|
254
|
+
export function extractMiniReqs(prd) {
|
|
255
|
+
return extractSection(prd, "Mini-requirements(?:[^\\n]*)?");
|
|
256
|
+
}
|
|
257
|
+
export function extractProofContract(prd) {
|
|
258
|
+
const body = extractSection(prd, "Proof contract");
|
|
259
|
+
if (!body)
|
|
260
|
+
return [];
|
|
261
|
+
const items = [];
|
|
262
|
+
for (const line of body.split("\n")) {
|
|
263
|
+
const m = line.match(/^\s*-?\s*\[(?:\s|x|X)\]\s+(.+)$/);
|
|
264
|
+
if (!m)
|
|
265
|
+
continue;
|
|
266
|
+
let text = m[1].trim();
|
|
267
|
+
let plannedRef = null;
|
|
268
|
+
const img = text.match(/!\[[^\]]*\]\(([^)]+)\)/);
|
|
269
|
+
if (img) {
|
|
270
|
+
plannedRef = img[1].trim();
|
|
271
|
+
text = text.replace(img[0], "").replace(/\s{2,}/g, " ").trim();
|
|
272
|
+
}
|
|
273
|
+
items.push({ text, plannedRef });
|
|
274
|
+
}
|
|
275
|
+
return items;
|
|
276
|
+
}
|
|
277
|
+
/** Top-down by precedence — locked > review > building > spec > intent —
|
|
278
|
+
* stated explicitly because one signal can satisfy two lanes. */
|
|
279
|
+
export function derivePhase(s) {
|
|
280
|
+
if (s.approved)
|
|
281
|
+
return "locked";
|
|
282
|
+
if (s.verdictOrEvidenceSetPresent)
|
|
283
|
+
return "review";
|
|
284
|
+
if (s.proofArtifactPresent || s.activeQitemPresent)
|
|
285
|
+
return "building";
|
|
286
|
+
if (s.prdPresent)
|
|
287
|
+
return "spec";
|
|
288
|
+
return "intent";
|
|
289
|
+
}
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
// §3.1 DELIVERED — the redesigned join: planned ↔ curated proof ↔ verified
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
/** An `evidences:` ref matches a promised item by exact text or 1-based index. */
|
|
294
|
+
function refMatches(ref, promised, index) {
|
|
295
|
+
const trimmed = ref.trim();
|
|
296
|
+
return trimmed === promised[index].text || trimmed === String(index + 1);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* `delivered.items` IS the join, reframed (§3.1): each `## Proof contract`
|
|
300
|
+
* deliverable pairs with the CURATED proof media of the artifacts covering it
|
|
301
|
+
* and QA's recorded comparison signal.
|
|
302
|
+
*
|
|
303
|
+
* `verified` binds to the SHIPPED C1 fields (arch F3), never presence:
|
|
304
|
+
* verified — a covering qa|adjudication artifact records the comparison
|
|
305
|
+
* (self_check) AND its recorded verdict is passing;
|
|
306
|
+
* unverified — some covering artifact exists but no passing recorded QA
|
|
307
|
+
* comparison (QA's why-kicked-back note still surfaces);
|
|
308
|
+
* missing — promised, nothing delivered.
|
|
309
|
+
* Fail-open by construction: these are render states, never blocks.
|
|
310
|
+
*/
|
|
311
|
+
export function composeDelivered(promised, artifacts) {
|
|
312
|
+
const escaping = new Set();
|
|
313
|
+
const mediaOf = (a) => {
|
|
314
|
+
const out = [];
|
|
315
|
+
for (const ref of a.mediaRefs) {
|
|
316
|
+
const m = toReviewMedia(ref, "proof");
|
|
317
|
+
if (m)
|
|
318
|
+
out.push(m);
|
|
319
|
+
else if (mediaKind(ref))
|
|
320
|
+
escaping.add(ref);
|
|
321
|
+
}
|
|
322
|
+
return out;
|
|
323
|
+
};
|
|
324
|
+
const byLatest = (a, b) => a.droppedAt < b.droppedAt ? 1 : a.droppedAt > b.droppedAt ? -1 : a.relPath.localeCompare(b.relPath);
|
|
325
|
+
const covered = new Set();
|
|
326
|
+
const items = promised.map((p, i) => {
|
|
327
|
+
const covering = artifacts.filter((a) => a.evidences.some((ref) => refMatches(ref, promised, i))).sort(byLatest);
|
|
328
|
+
covering.forEach((a) => covered.add(a.relPath));
|
|
329
|
+
const qaCovering = covering.filter((a) => a.artifactType === "qa" || a.artifactType === "adjudication");
|
|
330
|
+
const verifiedBy = qaCovering.find((a) => a.selfCheck !== null && a.artifactType !== null && isPassing(a.artifactType, a.verdict));
|
|
331
|
+
const noteSource = qaCovering.find((a) => a.selfCheck !== null) ?? covering.find((a) => a.selfCheck !== null);
|
|
332
|
+
const plannedRef = p.plannedRef ? toReviewMedia(p.plannedRef, "") : null;
|
|
333
|
+
if (p.plannedRef && !plannedRef && mediaKind(p.plannedRef))
|
|
334
|
+
escaping.add(p.plannedRef);
|
|
335
|
+
const item = {
|
|
336
|
+
promised: plannedRef ? { text: p.text, plannedRef } : { text: p.text },
|
|
337
|
+
proof: dedupMedia(covering.flatMap(mediaOf)),
|
|
338
|
+
verified: verifiedBy ? "verified" : covering.length > 0 ? "unverified" : "missing",
|
|
339
|
+
};
|
|
340
|
+
const note = noteSource?.selfCheck ?? null;
|
|
341
|
+
if (note)
|
|
342
|
+
item.note = note;
|
|
343
|
+
return item;
|
|
344
|
+
});
|
|
345
|
+
// Helpful-but-unmapped artifacts (§6): their media renders bounded under
|
|
346
|
+
// the extraProof label — visible, never dropped, never a primary-view pile.
|
|
347
|
+
const extraProof = dedupMedia(artifacts
|
|
348
|
+
.filter((a) => !covered.has(a.relPath))
|
|
349
|
+
.sort(byLatest)
|
|
350
|
+
.flatMap(mediaOf));
|
|
351
|
+
return {
|
|
352
|
+
items,
|
|
353
|
+
extraProof,
|
|
354
|
+
missingCount: items.filter((it) => it.verified === "missing").length,
|
|
355
|
+
escapingRefs: [...escaping].sort(),
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function minutesBetween(aIso, bIso) {
|
|
359
|
+
return Math.floor((Date.parse(bIso) - Date.parse(aIso)) / 60_000);
|
|
360
|
+
}
|
|
361
|
+
/** The four ▲ exception rules over captured signals. Every row carries its
|
|
362
|
+
* evidence + crossed threshold; no evidence -> no exception (never a bare
|
|
363
|
+
* accusation). A ▲ is information for the human, invisible to the flagged
|
|
364
|
+
* agent's workflow. */
|
|
365
|
+
export function deriveExceptions(agents, attention, delivered, scopeLabel, nowIso, latestArtifactIso, governingStampIso) {
|
|
366
|
+
const items = [];
|
|
367
|
+
const push = (identity, summary, d) => {
|
|
368
|
+
items.push({
|
|
369
|
+
source: "derived",
|
|
370
|
+
identity,
|
|
371
|
+
summary,
|
|
372
|
+
leg: d.kind,
|
|
373
|
+
where: scopeLabel,
|
|
374
|
+
ageIso: null,
|
|
375
|
+
priority: null,
|
|
376
|
+
tier: null,
|
|
377
|
+
evidenceRef: null,
|
|
378
|
+
unblocks: null,
|
|
379
|
+
qitemId: null,
|
|
380
|
+
destinationSession: null,
|
|
381
|
+
derived: d,
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
for (const a of agents) {
|
|
385
|
+
if (a.idle === true && a.holdsCount > 0 && a.idleSinceIso) {
|
|
386
|
+
const idleMin = minutesBetween(a.idleSinceIso, nowIso);
|
|
387
|
+
if (idleMin >= IDLE_WITH_WORK_THRESHOLD_MIN) {
|
|
388
|
+
push(`${a.sessionName}|stuck|${a.idleSinceIso}`, `${a.agentName} looks stuck`, {
|
|
389
|
+
kind: "stuck",
|
|
390
|
+
evidence: `idle ${idleMin}m >= ${IDLE_WITH_WORK_THRESHOLD_MIN}m default · holds ${a.holdsCount}`,
|
|
391
|
+
threshold: `idle-with-work >= ${IDLE_WITH_WORK_THRESHOLD_MIN}m`,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
for (const q of attention) {
|
|
397
|
+
if (q.closureRequiredAtIso && q.closureRequiredAtIso < nowIso) {
|
|
398
|
+
push(`${q.qitemId}|overdue|${q.closureRequiredAtIso}`, `${q.summary ?? q.qitemId} is overdue`, {
|
|
399
|
+
kind: "overdue",
|
|
400
|
+
evidence: `closure required at ${q.closureRequiredAtIso} · now ${nowIso}`,
|
|
401
|
+
threshold: "past closure_required_at",
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (delivered.promisedCount > 0 && delivered.missingCount > 0) {
|
|
406
|
+
push(`${scopeLabel}|insufficient-proof|${delivered.missingCount}`, `insufficient proof: ${delivered.missingCount}/${delivered.promisedCount} promised items missing`, {
|
|
407
|
+
kind: "insufficient-proof",
|
|
408
|
+
evidence: `${delivered.missingCount} of ${delivered.promisedCount} promised deliverables have no delivered evidence`,
|
|
409
|
+
threshold: "delivered.items MISSING count > 0",
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
if (latestArtifactIso && governingStampIso && latestArtifactIso > governingStampIso) {
|
|
413
|
+
push(`${scopeLabel}|stale-after-change|${latestArtifactIso}`, "artifacts changed after the governing stamp", {
|
|
414
|
+
kind: "stale-after-change",
|
|
415
|
+
evidence: `artifact at ${latestArtifactIso} is newer than the stamp at ${governingStampIso}`,
|
|
416
|
+
threshold: "artifact newer than governing stamp",
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
return items;
|
|
420
|
+
}
|
|
421
|
+
export function composeNeedsYou(attention, derived, confirmFaithful, computedOver, nowIso) {
|
|
422
|
+
const agentItems = attention.map((q) => ({
|
|
423
|
+
source: "agent",
|
|
424
|
+
// OPR.0.4.6.WF4 Q6 — carry the gatherer's pointer verbatim; OMITTED for
|
|
425
|
+
// non-workflow items (byte-identity-by-omission).
|
|
426
|
+
...(q.workflow ? { workflow: q.workflow } : {}),
|
|
427
|
+
identity: q.qitemId,
|
|
428
|
+
summary: q.summary ?? q.qitemId,
|
|
429
|
+
leg: q.leg,
|
|
430
|
+
where: q.where,
|
|
431
|
+
ageIso: q.createdAtIso,
|
|
432
|
+
priority: q.priority,
|
|
433
|
+
tier: q.tier,
|
|
434
|
+
evidenceRef: q.evidenceRef,
|
|
435
|
+
unblocks: q.unblocks,
|
|
436
|
+
qitemId: q.qitemId,
|
|
437
|
+
destinationSession: q.destinationSession,
|
|
438
|
+
derived: null,
|
|
439
|
+
}));
|
|
440
|
+
// One-count identity rule: distinct identities within this scope only.
|
|
441
|
+
const seen = new Set();
|
|
442
|
+
const all = [...agentItems, ...confirmFaithful, ...derived].filter((i) => {
|
|
443
|
+
if (seen.has(i.identity))
|
|
444
|
+
return false;
|
|
445
|
+
seen.add(i.identity);
|
|
446
|
+
return true;
|
|
447
|
+
});
|
|
448
|
+
// Priority-ordered, most-consequential-first: explicit priority rank, then age.
|
|
449
|
+
const rank = { urgent: 0, high: 1, normal: 2, low: 3 };
|
|
450
|
+
all.sort((a, b) => {
|
|
451
|
+
const ra = rank[a.priority ?? "normal"] ?? 2;
|
|
452
|
+
const rb = rank[b.priority ?? "normal"] ?? 2;
|
|
453
|
+
if (ra !== rb)
|
|
454
|
+
return ra - rb;
|
|
455
|
+
return (a.ageIso ?? "9999") < (b.ageIso ?? "9999") ? -1 : 1;
|
|
456
|
+
});
|
|
457
|
+
return {
|
|
458
|
+
items: all,
|
|
459
|
+
provenance: all.length === 0
|
|
460
|
+
? `0 attention items · 0 parks · 0 unconfirmed proofs — computed from ${computedOver} at ${nowIso}`
|
|
461
|
+
: `computed from ${computedOver} at ${nowIso}`,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* OPR.0.4.6.WF5 FR-3 — the workflow_instances ▲ source + THE AWARENESS
|
|
466
|
+
* CHANNEL. One-count across channels (BR-3): an exception with a live
|
|
467
|
+
* HUMAN-routed ● item renders NOTHING here (the item IS the human's
|
|
468
|
+
* row); an ORCHESTRATOR-routed ● item renders exactly ONE awareness row
|
|
469
|
+
* (same identity, second projection — the human KNOWS at altitude); a
|
|
470
|
+
* failed instance with NO item renders the ▲ backstop naming BOTH the
|
|
471
|
+
* exception AND the missing-item anomaly (the backstop firing is itself
|
|
472
|
+
* evidence of a bug). Healthy instances render zero rows (the band's
|
|
473
|
+
* zero-noise negative). Durable-by-derivation: recomputed from recorded
|
|
474
|
+
* state on every composition; rows clear on state-exit (recomposition,
|
|
475
|
+
* never hand-clearing).
|
|
476
|
+
*/
|
|
477
|
+
export function deriveWorkflowExceptions(workflows, scopeLabel, nowIso) {
|
|
478
|
+
const items = [];
|
|
479
|
+
const push = (identity, summary, d, evidenceRef, workflow) => {
|
|
480
|
+
items.push({
|
|
481
|
+
source: "derived",
|
|
482
|
+
// OPR.0.4.6.WF4 Q6 — every derived workflow row carries the pointer.
|
|
483
|
+
workflow,
|
|
484
|
+
identity,
|
|
485
|
+
summary,
|
|
486
|
+
leg: d.kind,
|
|
487
|
+
where: scopeLabel,
|
|
488
|
+
ageIso: null,
|
|
489
|
+
priority: null,
|
|
490
|
+
tier: null,
|
|
491
|
+
evidenceRef,
|
|
492
|
+
unblocks: null,
|
|
493
|
+
qitemId: null,
|
|
494
|
+
destinationSession: null,
|
|
495
|
+
derived: d,
|
|
496
|
+
});
|
|
497
|
+
};
|
|
498
|
+
for (const w of workflows) {
|
|
499
|
+
const trace = `rig workflow trace ${w.instanceId}`;
|
|
500
|
+
// OPR.0.4.6.WF4 Q6 — the pointer for every row this instance emits;
|
|
501
|
+
// identity derived exactly once, here (never from prose downstream).
|
|
502
|
+
const wref = {
|
|
503
|
+
instanceId: w.instanceId,
|
|
504
|
+
workflowName: w.workflowName,
|
|
505
|
+
...(w.currentStepId ? { stepId: w.currentStepId } : {}),
|
|
506
|
+
};
|
|
507
|
+
// The anomaly backstop fires regardless of item state — the
|
|
508
|
+
// corruption is orthogonal to exception routing.
|
|
509
|
+
if (w.frontierRefsNonOpenPacket) {
|
|
510
|
+
push(`${w.instanceId}|anomaly|frontier-non-open`, `${w.workflowName} instance frontier references a closed packet`, {
|
|
511
|
+
kind: "anomaly",
|
|
512
|
+
evidence: `instance ${w.instanceId} frontier points at a non-open packet — out-of-band closure got past the WF-3 close-path guard`,
|
|
513
|
+
threshold: "frontier packet must be open",
|
|
514
|
+
}, trace, wref);
|
|
515
|
+
}
|
|
516
|
+
const exceptional = w.status === "failed" || (w.deadlineState !== "healthy" && w.deadlineEvidence !== null);
|
|
517
|
+
if (!exceptional)
|
|
518
|
+
continue;
|
|
519
|
+
const kindLabel = w.status === "failed" ? "failed" : w.deadlineState;
|
|
520
|
+
if (w.openItem && w.openItem.humanRouted) {
|
|
521
|
+
// The ● item already sits in the human attention legs — a row
|
|
522
|
+
// here would double-render (one-count).
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (w.openItem) {
|
|
526
|
+
// ORCHESTRATOR-routed: the awareness row — holder + age +
|
|
527
|
+
// evidence; awareness, not assignment. Same recorded identity as
|
|
528
|
+
// the ● item, projected into the human band.
|
|
529
|
+
const ageMin = w.openItem.createdAtIso ? minutesBetween(w.openItem.createdAtIso, nowIso) : null;
|
|
530
|
+
push(`${w.instanceId}|awareness|${w.openItem.qitemId}`, `awareness: ${w.workflowName} ${kindLabel} — held by ${w.openItem.destinationSession}`, {
|
|
531
|
+
kind: "awareness",
|
|
532
|
+
evidence: `exception item ${w.openItem.qitemId} on ${w.openItem.destinationSession}${ageMin !== null ? ` for ${ageMin}m` : ""}${w.openItem.summary ? ` — ${w.openItem.summary}` : ""}`,
|
|
533
|
+
threshold: "awareness (orchestrator acting; step in any time)",
|
|
534
|
+
}, trace, wref);
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
// NO item: the ▲ backstop — names the exception AND the anomaly of
|
|
538
|
+
// the missing item.
|
|
539
|
+
push(`${w.instanceId}|workflow-${kindLabel}|no-item`, `${w.workflowName} instance ${kindLabel} with NO exception item`, {
|
|
540
|
+
kind: w.status === "failed" ? "workflow-failed" : "stuck",
|
|
541
|
+
evidence: `${w.deadlineEvidence ?? `instance ${w.instanceId} is ${kindLabel} at step ${w.currentStepId ?? "?"}`} · MISSING-ITEM ANOMALY: the never-lost channel produced no item (itself a bug — report it)`,
|
|
542
|
+
threshold: w.status === "failed" ? "failed instances carry an exception item" : "past the WF-1 deadline evaluator threshold",
|
|
543
|
+
}, trace, wref);
|
|
544
|
+
}
|
|
545
|
+
return items;
|
|
546
|
+
}
|
|
547
|
+
/** The third NAMED ▲ heuristic's visible v1 default (slice-22 FR-3:
|
|
548
|
+
* too-long-in-state — no transition beyond threshold). Lives HERE because
|
|
549
|
+
* compose.ts is the single threshold home (P2 arch note N2): changes land
|
|
550
|
+
* once and every altitude inherits. Same markdown-steered tuning
|
|
551
|
+
* fast-follow as IDLE_WITH_WORK_THRESHOLD_MIN. */
|
|
552
|
+
export const TOO_LONG_IN_STATE_THRESHOLD_MIN = 120;
|
|
553
|
+
/**
|
|
554
|
+
* Slice-22 FR-3 — the agent-scope ▲ set: exactly the three NAMED heuristics
|
|
555
|
+
* (idle-with-assigned-work, overdue handoff, too-long-in-state). The first
|
|
556
|
+
* two REUSE deriveExceptions' rules (called with zero delivered counts and
|
|
557
|
+
* no artifact/stamp facts, so the slice-only insufficient-proof /
|
|
558
|
+
* stale-after-change rules cannot fire); too-long-in-state is added here —
|
|
559
|
+
* additively, so slice-scope composition is byte-unchanged. No evidence →
|
|
560
|
+
* no exception (unknown is not idle; unknown lastTransition is not
|
|
561
|
+
* too-long).
|
|
562
|
+
*/
|
|
563
|
+
export function deriveAgentScopeExceptions(agents, attention, scopeLabel, nowIso) {
|
|
564
|
+
const items = deriveExceptions(agents, attention, { promisedCount: 0, missingCount: 0 }, scopeLabel, nowIso, null, null);
|
|
565
|
+
for (const a of agents) {
|
|
566
|
+
if (a.holdsCount > 0 && a.lastTransitionIso) {
|
|
567
|
+
const sinceMin = minutesBetween(a.lastTransitionIso, nowIso);
|
|
568
|
+
if (sinceMin >= TOO_LONG_IN_STATE_THRESHOLD_MIN) {
|
|
569
|
+
items.push({
|
|
570
|
+
source: "derived",
|
|
571
|
+
identity: `${a.sessionName}|too-long-in-state|${a.lastTransitionIso}`,
|
|
572
|
+
summary: `${a.agentName} has not transitioned in ${sinceMin}m`,
|
|
573
|
+
leg: "stuck",
|
|
574
|
+
where: scopeLabel,
|
|
575
|
+
ageIso: null,
|
|
576
|
+
priority: null,
|
|
577
|
+
tier: null,
|
|
578
|
+
evidenceRef: null,
|
|
579
|
+
unblocks: null,
|
|
580
|
+
qitemId: null,
|
|
581
|
+
destinationSession: null,
|
|
582
|
+
derived: {
|
|
583
|
+
kind: "stuck",
|
|
584
|
+
evidence: `no transition for ${sinceMin}m >= ${TOO_LONG_IN_STATE_THRESHOLD_MIN}m default · holds ${a.holdsCount}`,
|
|
585
|
+
threshold: `too-long-in-state >= ${TOO_LONG_IN_STATE_THRESHOLD_MIN}m`,
|
|
586
|
+
},
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return items;
|
|
592
|
+
}
|
|
593
|
+
/** Slice-22 FR-1..FR-4 — the rig-scope composition root. PURE: same inputs,
|
|
594
|
+
* byte-identical output (idempotence is a money proof). */
|
|
595
|
+
export function composeRigAgents(inputs) {
|
|
596
|
+
const { nowIso } = inputs;
|
|
597
|
+
const scopeLabel = "rig";
|
|
598
|
+
const derived = [
|
|
599
|
+
...deriveAgentScopeExceptions(inputs.agents, inputs.overdue, scopeLabel, nowIso),
|
|
600
|
+
...deriveWorkflowExceptions(inputs.workflows ?? [], scopeLabel, nowIso),
|
|
601
|
+
];
|
|
602
|
+
const needsYou = composeNeedsYou(inputs.attention, derived, [], `queue+ps (rig scope) · window: ${inputs.rosterWindow}`, nowIso);
|
|
603
|
+
const band = composeAgentsBand(inputs.agents, "rig", derived, nowIso);
|
|
604
|
+
return {
|
|
605
|
+
scope: "rig",
|
|
606
|
+
needsYou,
|
|
607
|
+
agents: {
|
|
608
|
+
...band,
|
|
609
|
+
provenance: band.rows.length === 0
|
|
610
|
+
? `no agents holding or recently holding work — computed from queue+ps · window: ${inputs.rosterWindow} · at ${nowIso}`
|
|
611
|
+
: `computed from queue+ps · window: ${inputs.rosterWindow} · at ${nowIso}`,
|
|
612
|
+
// FR-4: one health line per scope, from the transitions log.
|
|
613
|
+
coordinationHealth: `${inputs.handoffsToday} handoffs today · ${inputs.overdueCount} overdue`,
|
|
614
|
+
},
|
|
615
|
+
settled: inputs.settled,
|
|
616
|
+
settledProvenance: inputs.settled.length === 0
|
|
617
|
+
? `0 handoffs today — computed from queue transitions · window: today · at ${nowIso}`
|
|
618
|
+
: `computed from queue transitions · window: today · at ${nowIso}`,
|
|
619
|
+
composedAt: nowIso,
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
/** Region membership derives from work-on-THIS-scope, never rig co-residency. */
|
|
623
|
+
export function composeAgentsBand(agents, scope, exceptions, nowIso) {
|
|
624
|
+
const rows = agents.map((a) => {
|
|
625
|
+
const ex = exceptions.find((e) => e.derived && e.identity.startsWith(`${a.sessionName}|`));
|
|
626
|
+
return {
|
|
627
|
+
agentName: a.agentName,
|
|
628
|
+
runtime: a.runtime,
|
|
629
|
+
stateGlyph: a.parkedOn ? "parked" : a.idle === null ? "unknown" : a.idle ? "idle" : "active",
|
|
630
|
+
doing: a.doing,
|
|
631
|
+
holdsCount: a.holdsCount,
|
|
632
|
+
lastTransitionIso: a.lastTransitionIso,
|
|
633
|
+
exception: ex?.derived ?? null,
|
|
634
|
+
sessionName: a.sessionName,
|
|
635
|
+
slices: a.slices,
|
|
636
|
+
};
|
|
637
|
+
});
|
|
638
|
+
return {
|
|
639
|
+
scope,
|
|
640
|
+
rows,
|
|
641
|
+
provenance: rows.length === 0
|
|
642
|
+
? `no agents holding or recently holding work — computed from queue at ${nowIso}`
|
|
643
|
+
: `computed from queue at ${nowIso}`,
|
|
644
|
+
coordinationHealth: null,
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
/** A self-asserted PASS in the slice's own PROOF.md (never a verdict). */
|
|
648
|
+
export function proofClaimsPass(proofMd) {
|
|
649
|
+
if (!proofMd)
|
|
650
|
+
return false;
|
|
651
|
+
return proofMd
|
|
652
|
+
.split(/\r?\n/)
|
|
653
|
+
.some((line) => /^\s*(?:Closed by:.*\bVerdict:|Verdict:|Result:)\s*PASS\b/i.test(line));
|
|
654
|
+
}
|
|
655
|
+
function sectionMedia(sectionBody, escaping) {
|
|
656
|
+
const out = [];
|
|
657
|
+
for (const ref of extractMediaRefs(sectionBody)) {
|
|
658
|
+
const m = toReviewMedia(ref, "");
|
|
659
|
+
if (m)
|
|
660
|
+
out.push(m);
|
|
661
|
+
else if (mediaKind(ref))
|
|
662
|
+
escaping.add(ref);
|
|
663
|
+
}
|
|
664
|
+
return out;
|
|
665
|
+
}
|
|
666
|
+
export function composeSliceReview(inputs) {
|
|
667
|
+
const { slice, nowIso } = inputs;
|
|
668
|
+
const sliceRef = `${slice.missionId ?? "?"}/slices/${slice.name}`;
|
|
669
|
+
const candidateSha = deriveCandidateSha(inputs.artifacts);
|
|
670
|
+
const gateCells = deriveGateCells(inputs.artifacts, candidateSha);
|
|
671
|
+
const lineage = composeLineage(candidateSha, inputs.git, gateCells);
|
|
672
|
+
const planLock = lockFrom(inputs.approval.spec);
|
|
673
|
+
const deliveredLock = lockFrom(inputs.approval.delivery);
|
|
674
|
+
const escaping = new Set();
|
|
675
|
+
const intentText = extractSection(inputs.readme, "Intent");
|
|
676
|
+
const intentMedia = sectionMedia(intentText, escaping);
|
|
677
|
+
const miniReqs = extractMiniReqs(inputs.prd);
|
|
678
|
+
const planMedia = dedupMedia([
|
|
679
|
+
...sectionMedia(miniReqs, escaping),
|
|
680
|
+
...inputs.lockedArtifacts
|
|
681
|
+
.map((a) => (mediaKind(a.path) ? toReviewMedia(a.path, "") : null))
|
|
682
|
+
.filter((m) => m !== null),
|
|
683
|
+
]);
|
|
684
|
+
const promised = extractProofContract(inputs.prd);
|
|
685
|
+
const delivered = composeDelivered(promised, inputs.artifacts);
|
|
686
|
+
delivered.escapingRefs.forEach((r) => escaping.add(r));
|
|
687
|
+
const claimedPass = proofClaimsPass(inputs.proofMd);
|
|
688
|
+
const anyRecordedVerdict = gateCells.some((c) => c.state !== "missing");
|
|
689
|
+
const evidencePresent = inputs.artifacts.length > 0 || claimedPass;
|
|
690
|
+
const phase = derivePhase({
|
|
691
|
+
prdPresent: inputs.prd !== null,
|
|
692
|
+
proofArtifactPresent: inputs.artifacts.length > 0 || inputs.proofMd !== null,
|
|
693
|
+
activeQitemPresent: inputs.activeQitemPresent,
|
|
694
|
+
verdictOrEvidenceSetPresent: anyRecordedVerdict || claimedPass,
|
|
695
|
+
approved: deliveredLock !== null,
|
|
696
|
+
});
|
|
697
|
+
// Regime 2: evidence present, NO recorded passing state -> confirm-faithful.
|
|
698
|
+
const recordedGreen = computeRecordedGreen(gateCells, inputs.artifacts, candidateSha);
|
|
699
|
+
const confirmFaithful = [];
|
|
700
|
+
if (!recordedGreen.green && evidencePresent && claimedPass) {
|
|
701
|
+
confirmFaithful.push({
|
|
702
|
+
source: "agent",
|
|
703
|
+
identity: `${slice.name}|confirm-faithful|${candidateSha ?? "no-sha"}`,
|
|
704
|
+
summary: "confirm this proof is faithful",
|
|
705
|
+
leg: "confirm-faithful",
|
|
706
|
+
where: sliceRef,
|
|
707
|
+
ageIso: null,
|
|
708
|
+
priority: "high",
|
|
709
|
+
tier: null,
|
|
710
|
+
evidenceRef: `${sliceRef}/PROOF.md`,
|
|
711
|
+
unblocks: `${slice.name} green (regime 2)`,
|
|
712
|
+
qitemId: null,
|
|
713
|
+
destinationSession: null,
|
|
714
|
+
derived: null,
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
const latestArtifactIso = inputs.artifacts.reduce((acc, a) => (acc === null || a.droppedAt > acc ? a.droppedAt : acc), null);
|
|
718
|
+
const derived = deriveExceptions(inputs.agents, inputs.attention, { promisedCount: promised.length, missingCount: delivered.missingCount }, sliceRef, nowIso, latestArtifactIso, inputs.approval.delivery?.at ?? null);
|
|
719
|
+
const workflowDerived = deriveWorkflowExceptions(inputs.workflows ?? [], sliceRef, nowIso);
|
|
720
|
+
const needsYou = composeNeedsYou(inputs.attention, [...derived, ...workflowDerived], confirmFaithful, "queue+artifacts", nowIso);
|
|
721
|
+
const agents = composeAgentsBand(inputs.agents, `slice:${slice.name}`, derived, nowIso);
|
|
722
|
+
// FR-5: an out-of-slice media ref = a defect finding, never a silent
|
|
723
|
+
// no-render. Absolute paths AND ../ traversal segments both escape the
|
|
724
|
+
// co-located contract (rev1 fixback at d6135921 — slice-19 containment class).
|
|
725
|
+
const defects = [
|
|
726
|
+
...inputs.mediaRefs
|
|
727
|
+
.filter((r) => r.startsWith("/") || /(^|\/)\.\.(\/|$)/.test(r))
|
|
728
|
+
.map((r) => r.startsWith("/")
|
|
729
|
+
? `absolute media path (must be slice-relative): ${r}`
|
|
730
|
+
: `media ref escapes the slice dir (must be co-located): ${r}`),
|
|
731
|
+
...[...escaping]
|
|
732
|
+
.sort()
|
|
733
|
+
.map((r) => r.startsWith("/")
|
|
734
|
+
? `absolute media path (must be slice-relative): ${r}`
|
|
735
|
+
: `media ref escapes the slice dir (must be co-located): ${r}`),
|
|
736
|
+
];
|
|
737
|
+
return {
|
|
738
|
+
slice: slice.name,
|
|
739
|
+
sliceId: slice.id,
|
|
740
|
+
title: slice.title,
|
|
741
|
+
missionId: slice.missionId,
|
|
742
|
+
phase,
|
|
743
|
+
laneLabel: PHASE_LANE_LABELS[phase],
|
|
744
|
+
intent: {
|
|
745
|
+
text: intentText,
|
|
746
|
+
media: intentMedia,
|
|
747
|
+
ssotPath: inputs.readme !== null ? `${sliceRef}/README.md` : null,
|
|
748
|
+
degrade: intentText === null ? "no intent recorded" : null,
|
|
749
|
+
},
|
|
750
|
+
plan: {
|
|
751
|
+
concise: { text: miniReqs, media: planMedia },
|
|
752
|
+
lockedArtifacts: inputs.lockedArtifacts,
|
|
753
|
+
lock: planLock,
|
|
754
|
+
ssotPath: inputs.prd !== null ? `${sliceRef}/IMPLEMENTATION-PRD.md` : null,
|
|
755
|
+
},
|
|
756
|
+
delivered: {
|
|
757
|
+
items: delivered.items,
|
|
758
|
+
extraProof: delivered.extraProof,
|
|
759
|
+
lock: deliveredLock,
|
|
760
|
+
proofDirPath: inputs.proofDirExists ? `${sliceRef}/proof` : null,
|
|
761
|
+
},
|
|
762
|
+
needsYou,
|
|
763
|
+
agents,
|
|
764
|
+
lineage,
|
|
765
|
+
defects,
|
|
766
|
+
composedAt: nowIso,
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
export function composeMissionReview(inputs) {
|
|
770
|
+
const { nowIso } = inputs;
|
|
771
|
+
const board = inputs.slices.map(({ review: s, green }) => {
|
|
772
|
+
let stageCell;
|
|
773
|
+
switch (s.phase) {
|
|
774
|
+
case "spec":
|
|
775
|
+
stageCell = s.plan.lock ? `spec-approved ${s.plan.lock.at}` : "spec unstamped";
|
|
776
|
+
break;
|
|
777
|
+
case "building":
|
|
778
|
+
stageCell =
|
|
779
|
+
s.delivered.items.length > 0
|
|
780
|
+
? `${s.delivered.items.filter((it) => it.verified !== "missing").length}/${s.delivered.items.length} proofs`
|
|
781
|
+
: "building";
|
|
782
|
+
break;
|
|
783
|
+
case "review":
|
|
784
|
+
stageCell = `${green ? "GREEN" : "not green"} · ${s.lineage.mergeSha ?? "UNMERGED"}`;
|
|
785
|
+
break;
|
|
786
|
+
case "locked":
|
|
787
|
+
stageCell = `stamped ${s.delivered.lock?.at ?? "?"}`;
|
|
788
|
+
break;
|
|
789
|
+
default:
|
|
790
|
+
stageCell = "intent";
|
|
791
|
+
}
|
|
792
|
+
const changedSinceStamp = s.needsYou.items.some((i) => i.derived?.kind === "stale-after-change");
|
|
793
|
+
return {
|
|
794
|
+
slice: s.slice,
|
|
795
|
+
title: s.title,
|
|
796
|
+
phase: s.phase,
|
|
797
|
+
laneLabel: s.laneLabel,
|
|
798
|
+
agentsCount: s.agents.rows.length,
|
|
799
|
+
stageCell,
|
|
800
|
+
changedSinceStamp,
|
|
801
|
+
attentionWorthy: s.needsYou.items.length > 0 || changedSinceStamp,
|
|
802
|
+
};
|
|
803
|
+
});
|
|
804
|
+
// The completion ledger — a query over the mission's slice set, never an
|
|
805
|
+
// authored list (omission-proof by construction).
|
|
806
|
+
const ledger = inputs.slices.map(({ review: s, green }) => ({
|
|
807
|
+
slice: s.slice,
|
|
808
|
+
candidateSha: s.lineage.candidateSha,
|
|
809
|
+
gateCells: s.lineage.gateCells,
|
|
810
|
+
mergeSha: s.lineage.mergeSha,
|
|
811
|
+
needsHumanCount: s.needsYou.items.length,
|
|
812
|
+
green,
|
|
813
|
+
}));
|
|
814
|
+
// Cut-complete: TRUE only when EVERY in-cut slice is (a) green, (b) merged,
|
|
815
|
+
// (c) zero open needs-human items — never asserted from a status field.
|
|
816
|
+
const incomplete = ledger.filter((r) => !(r.green && r.mergeSha !== null && r.needsHumanCount === 0));
|
|
817
|
+
const cutComplete = ledger.length > 0 && incomplete.length === 0;
|
|
818
|
+
// Mission NEEDS YOU = the union query (slice ∪ mission ∪ ▲), distinct
|
|
819
|
+
// identities — an item at N altitudes is one item seen from N heights.
|
|
820
|
+
const seen = new Set();
|
|
821
|
+
const unionItems = [];
|
|
822
|
+
for (const { review: s } of inputs.slices) {
|
|
823
|
+
for (const i of s.needsYou.items) {
|
|
824
|
+
if (!seen.has(i.identity)) {
|
|
825
|
+
seen.add(i.identity);
|
|
826
|
+
unionItems.push(i);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
const missionBand = composeNeedsYou(inputs.missionAttention, [], [], "mission queue+slice unions", nowIso);
|
|
831
|
+
for (const i of missionBand.items) {
|
|
832
|
+
if (!seen.has(i.identity)) {
|
|
833
|
+
seen.add(i.identity);
|
|
834
|
+
unionItems.push(i);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
const agents = composeAgentsBand(inputs.agents, `mission:${inputs.mission.name}`, [], nowIso);
|
|
838
|
+
const composed = {
|
|
839
|
+
mission: inputs.mission.name,
|
|
840
|
+
missionId: inputs.mission.id,
|
|
841
|
+
title: inputs.mission.title,
|
|
842
|
+
intent: inputs.mission.intent ?? null,
|
|
843
|
+
briefSpine: { building: "", progress: "", proven: "", needsYou: "" },
|
|
844
|
+
board,
|
|
845
|
+
ledger,
|
|
846
|
+
cutComplete,
|
|
847
|
+
cutCompleteBasis: cutComplete
|
|
848
|
+
? `all ${ledger.length} in-cut slices green + merged + zero needs-human · computed at ${nowIso}`
|
|
849
|
+
: `${incomplete.length} of ${ledger.length} slices not cut-complete (${incomplete.map((r) => r.slice).join(", ") || "none"}) · computed at ${nowIso}`,
|
|
850
|
+
needsYou: {
|
|
851
|
+
items: unionItems,
|
|
852
|
+
provenance: unionItems.length === 0
|
|
853
|
+
? `0 attention items across ${inputs.slices.length} slices — computed from queue+artifacts at ${nowIso}`
|
|
854
|
+
: `union of ${inputs.slices.length} slice scopes + mission scope · computed at ${nowIso}`,
|
|
855
|
+
},
|
|
856
|
+
agents,
|
|
857
|
+
composedAt: nowIso,
|
|
858
|
+
};
|
|
859
|
+
composed.briefSpine = renderBriefSpine(composed);
|
|
860
|
+
return composed;
|
|
861
|
+
}
|
|
862
|
+
//# sourceMappingURL=compose.js.map
|