@quickchatai/quickreview 0.0.0-stage → 1.1.0
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/LICENSE +23 -0
- package/README.md +385 -2
- package/THIRD-PARTY-NOTICES.md +134 -0
- package/agents/pass-abstraction.md +64 -0
- package/agents/pass-ask-human.md +134 -0
- package/agents/pass-backcompat.md +67 -0
- package/agents/pass-baseline.md +61 -0
- package/agents/pass-behaviour-delta.md +64 -0
- package/agents/pass-bounds.md +36 -0
- package/agents/pass-claims.md +31 -0
- package/agents/pass-concurrency.md +168 -0
- package/agents/pass-consistency.md +57 -0
- package/agents/pass-contracts.md +30 -0
- package/agents/pass-data-safety.md +54 -0
- package/agents/pass-deferred.md +35 -0
- package/agents/pass-delivery.md +37 -0
- package/agents/pass-duplication.md +60 -0
- package/agents/pass-intent.md +63 -0
- package/agents/pass-lint-conformance.md +46 -0
- package/agents/pass-maintainability.md +67 -0
- package/agents/pass-placement.md +68 -0
- package/agents/pass-prod-risk.md +24 -0
- package/agents/pass-rollout.md +32 -0
- package/agents/pass-roundtrip.md +46 -0
- package/agents/pass-security.md +31 -0
- package/agents/pass-simplicity.md +68 -0
- package/agents/pass-statelessness.md +27 -0
- package/agents/pass-style.md +37 -0
- package/agents/pass-sweep.md +57 -0
- package/agents/pass-tests.md +58 -0
- package/agents/pass-ui.md +23 -0
- package/agents/pass-validate.md +50 -0
- package/agents/pass-widened.md +46 -0
- package/agents/scan/pass-scan.md +86 -0
- package/bin/qcr.js +11 -0
- package/config.example.toml +1067 -0
- package/deploy/ansible/README.md +356 -0
- package/deploy/ansible/group_vars/all.yml +212 -0
- package/deploy/ansible/inventory.example.ini +25 -0
- package/deploy/ansible/playbook.yml +360 -0
- package/deploy/collect-secrets.sh +289 -0
- package/deploy/collect-slack-secrets.mjs +1190 -0
- package/deploy/github-app-manifest.json +31 -0
- package/deploy/manifest.schema.json +75 -0
- package/deploy/qcr-update.sh +803 -0
- package/deploy/reviewer/AGENTS.override.md +12 -0
- package/dist/extensions/cli/bash-guard-ambient.js +42 -0
- package/dist/extensions/cli/bash-guard-ambient.js.map +1 -0
- package/dist/extensions/cli/bash-guard.js +5 -0
- package/dist/extensions/cli/bash-guard.js.map +1 -0
- package/dist/extensions/cli/companion-guard.js +5 -0
- package/dist/extensions/cli/companion-guard.js.map +1 -0
- package/dist/extensions/cli/debug-round.js +8 -0
- package/dist/extensions/cli/debug-round.js.map +1 -0
- package/dist/extensions/cli/inject-bridge.js +5 -0
- package/dist/extensions/cli/inject-bridge.js.map +1 -0
- package/dist/extensions/cli/ledger-pin.js +5 -0
- package/dist/extensions/cli/ledger-pin.js.map +1 -0
- package/dist/extensions/cli/lens.js +13 -0
- package/dist/extensions/cli/lens.js.map +1 -0
- package/dist/extensions/cli/muted-theme.js +5 -0
- package/dist/extensions/cli/muted-theme.js.map +1 -0
- package/dist/extensions/cli/onboarding.js +5 -0
- package/dist/extensions/cli/onboarding.js.map +1 -0
- package/dist/extensions/cli/setup.js +5 -0
- package/dist/extensions/cli/setup.js.map +1 -0
- package/dist/extensions/cli/tui-view.js +5 -0
- package/dist/extensions/cli/tui-view.js.map +1 -0
- package/dist/extensions/companion-guard.js +361 -0
- package/dist/extensions/companion-guard.js.map +1 -0
- package/dist/extensions/debug-round.js +204 -0
- package/dist/extensions/debug-round.js.map +1 -0
- package/dist/extensions/inject-bridge.js +603 -0
- package/dist/extensions/inject-bridge.js.map +1 -0
- package/dist/extensions/muted-theme.js +12 -0
- package/dist/extensions/muted-theme.js.map +1 -0
- package/dist/extensions/onboarding.js +175 -0
- package/dist/extensions/onboarding.js.map +1 -0
- package/dist/extensions/setup-replay.js +269 -0
- package/dist/extensions/setup-replay.js.map +1 -0
- package/dist/extensions/setup-scan.js +998 -0
- package/dist/extensions/setup-scan.js.map +1 -0
- package/dist/extensions/setup-triage.js +175 -0
- package/dist/extensions/setup-triage.js.map +1 -0
- package/dist/extensions/setup.js +1160 -0
- package/dist/extensions/setup.js.map +1 -0
- package/dist/extensions/tui-view.js +389 -0
- package/dist/extensions/tui-view.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/client.js +376 -0
- package/dist/extensions/vendor/openviking-pi/client.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/config.js +189 -0
- package/dist/extensions/vendor/openviking-pi/config.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/index.js +421 -0
- package/dist/extensions/vendor/openviking-pi/index.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/lib/capture-adapter.mjs +86 -0
- package/dist/extensions/vendor/openviking-pi/lib/capture-adapter.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/lib/takeover-core.mjs +408 -0
- package/dist/extensions/vendor/openviking-pi/lib/takeover-core.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs +41 -0
- package/dist/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-hint.js +290 -0
- package/dist/extensions/vendor/openviking-pi/qcr-hint.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-honest.js +148 -0
- package/dist/extensions/vendor/openviking-pi/qcr-honest.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-hooks.js +68 -0
- package/dist/extensions/vendor/openviking-pi/qcr-hooks.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-leaf.js +77 -0
- package/dist/extensions/vendor/openviking-pi/qcr-leaf.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-lesson.js +216 -0
- package/dist/extensions/vendor/openviking-pi/qcr-lesson.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-namespaces.js +154 -0
- package/dist/extensions/vendor/openviking-pi/qcr-namespaces.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-recall.js +254 -0
- package/dist/extensions/vendor/openviking-pi/qcr-recall.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-shim.js +94 -0
- package/dist/extensions/vendor/openviking-pi/qcr-shim.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-write.js +333 -0
- package/dist/extensions/vendor/openviking-pi/qcr-write.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/recall.js +108 -0
- package/dist/extensions/vendor/openviking-pi/recall.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/capture-utils.mjs +529 -0
- package/dist/extensions/vendor/openviking-pi/shared/capture-utils.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/credentials.mjs +205 -0
- package/dist/extensions/vendor/openviking-pi/shared/credentials.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/pending-queue.mjs +442 -0
- package/dist/extensions/vendor/openviking-pi/shared/pending-queue.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/profile-inject.mjs +286 -0
- package/dist/extensions/vendor/openviking-pi/shared/profile-inject.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs +189 -0
- package/dist/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/recall-core.mjs +580 -0
- package/dist/extensions/vendor/openviking-pi/shared/recall-core.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/retryable.mjs +11 -0
- package/dist/extensions/vendor/openviking-pi/shared/retryable.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/session-model.mjs +63 -0
- package/dist/extensions/vendor/openviking-pi/shared/session-model.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/uri-guard.mjs +58 -0
- package/dist/extensions/vendor/openviking-pi/shared/uri-guard.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/workspace-peer.mjs +16 -0
- package/dist/extensions/vendor/openviking-pi/shared/workspace-peer.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/sync.js +127 -0
- package/dist/extensions/vendor/openviking-pi/sync.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/takeover.js +25 -0
- package/dist/extensions/vendor/openviking-pi/takeover.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/tools.js +417 -0
- package/dist/extensions/vendor/openviking-pi/tools.js.map +1 -0
- package/dist/src/anomalies.js +483 -0
- package/dist/src/anomalies.js.map +1 -0
- package/dist/src/answerworker.js +180 -0
- package/dist/src/answerworker.js.map +1 -0
- package/dist/src/appstamp.js +68 -0
- package/dist/src/appstamp.js.map +1 -0
- package/dist/src/archive/admission.js +3 -0
- package/dist/src/archive/admission.js.map +1 -0
- package/dist/src/archive/archivedb.js +474 -0
- package/dist/src/archive/archivedb.js.map +1 -0
- package/dist/src/archive/archiver.js +1770 -0
- package/dist/src/archive/archiver.js.map +1 -0
- package/dist/src/archive/archivewrite.js +198 -0
- package/dist/src/archive/archivewrite.js.map +1 -0
- package/dist/src/archive/bundle.js +266 -0
- package/dist/src/archive/bundle.js.map +1 -0
- package/dist/src/archive/dbmove.js +638 -0
- package/dist/src/archive/dbmove.js.map +1 -0
- package/dist/src/archive/duplicatecounts.js +80 -0
- package/dist/src/archive/duplicatecounts.js.map +1 -0
- package/dist/src/archive/eligibility.js +113 -0
- package/dist/src/archive/eligibility.js.map +1 -0
- package/dist/src/archive/extract.js +288 -0
- package/dist/src/archive/extract.js.map +1 -0
- package/dist/src/archive/fsutil.js +330 -0
- package/dist/src/archive/fsutil.js.map +1 -0
- package/dist/src/archive/gzfile.js +277 -0
- package/dist/src/archive/gzfile.js.map +1 -0
- package/dist/src/archive/kinds.js +22 -0
- package/dist/src/archive/kinds.js.map +1 -0
- package/dist/src/archive/livecheckpoint.js +178 -0
- package/dist/src/archive/livecheckpoint.js.map +1 -0
- package/dist/src/archive/liveretention.js +145 -0
- package/dist/src/archive/liveretention.js.map +1 -0
- package/dist/src/archive/manifest.js +284 -0
- package/dist/src/archive/manifest.js.map +1 -0
- package/dist/src/archive/overseer.js +283 -0
- package/dist/src/archive/overseer.js.map +1 -0
- package/dist/src/archive/piglobal.js +129 -0
- package/dist/src/archive/piglobal.js.map +1 -0
- package/dist/src/archive/plan.js +398 -0
- package/dist/src/archive/plan.js.map +1 -0
- package/dist/src/archive/prarchive.js +831 -0
- package/dist/src/archive/prarchive.js.map +1 -0
- package/dist/src/archive/prfiles.js +303 -0
- package/dist/src/archive/prfiles.js.map +1 -0
- package/dist/src/archive/report.js +169 -0
- package/dist/src/archive/report.js.map +1 -0
- package/dist/src/archive/restore.js +276 -0
- package/dist/src/archive/restore.js.map +1 -0
- package/dist/src/archive/rows.js +106 -0
- package/dist/src/archive/rows.js.map +1 -0
- package/dist/src/archive/seal.js +480 -0
- package/dist/src/archive/seal.js.map +1 -0
- package/dist/src/archive/status.js +528 -0
- package/dist/src/archive/status.js.map +1 -0
- package/dist/src/archive/storepass.js +409 -0
- package/dist/src/archive/storepass.js.map +1 -0
- package/dist/src/backfill.js +217 -0
- package/dist/src/backfill.js.map +1 -0
- package/dist/src/bench/cost.js +87 -0
- package/dist/src/bench/exec.js +76 -0
- package/dist/src/bench/values.js +14 -0
- package/dist/src/botcontrol.js +127 -0
- package/dist/src/botcontrol.js.map +1 -0
- package/dist/src/botworker.js +805 -0
- package/dist/src/botworker.js.map +1 -0
- package/dist/src/capture.js +234 -0
- package/dist/src/capture.js.map +1 -0
- package/dist/src/cases.js +1491 -0
- package/dist/src/cases.js.map +1 -0
- package/dist/src/channelfs.js +27 -0
- package/dist/src/channelfs.js.map +1 -0
- package/dist/src/checklist.js +312 -0
- package/dist/src/checklist.js.map +1 -0
- package/dist/src/ciretry.js +91 -0
- package/dist/src/ciretry.js.map +1 -0
- package/dist/src/cli.js +1916 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/cliops.js +333 -0
- package/dist/src/cliops.js.map +1 -0
- package/dist/src/clonedir.js +15 -0
- package/dist/src/clonedir.js.map +1 -0
- package/dist/src/commandeffects.js +43 -0
- package/dist/src/commandeffects.js.map +1 -0
- package/dist/src/commands.js +1312 -0
- package/dist/src/commands.js.map +1 -0
- package/dist/src/companioninbox.js +203 -0
- package/dist/src/companioninbox.js.map +1 -0
- package/dist/src/compare.js +673 -0
- package/dist/src/compare.js.map +1 -0
- package/dist/src/config.js +1027 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/configcheck.js +111 -0
- package/dist/src/configcheck.js.map +1 -0
- package/dist/src/coreext.js +43 -0
- package/dist/src/coreext.js.map +1 -0
- package/dist/src/daemon.js +929 -0
- package/dist/src/daemon.js.map +1 -0
- package/dist/src/debuground.js +731 -0
- package/dist/src/debuground.js.map +1 -0
- package/dist/src/debugroundpi.js +219 -0
- package/dist/src/debugroundpi.js.map +1 -0
- package/dist/src/diagnostics.js +14 -0
- package/dist/src/diagnostics.js.map +1 -0
- package/dist/src/digest.js +139 -0
- package/dist/src/digest.js.map +1 -0
- package/dist/src/dispatch.js +1726 -0
- package/dist/src/dispatch.js.map +1 -0
- package/dist/src/engine/answerguard.js +18 -0
- package/dist/src/engine/answerguard.js.map +1 -0
- package/dist/src/engine/botsdk.js +262 -0
- package/dist/src/engine/botsdk.js.map +1 -0
- package/dist/src/engine/caserunner-sdk.js +332 -0
- package/dist/src/engine/caserunner-sdk.js.map +1 -0
- package/dist/src/engine/debugpi.js +194 -0
- package/dist/src/engine/debugpi.js.map +1 -0
- package/dist/src/eod.js +473 -0
- package/dist/src/eod.js.map +1 -0
- package/dist/src/eodpinwatch.js +391 -0
- package/dist/src/eodpinwatch.js.map +1 -0
- package/dist/src/escalation.js +1009 -0
- package/dist/src/escalation.js.map +1 -0
- package/dist/src/eventloop.js +779 -0
- package/dist/src/eventloop.js.map +1 -0
- package/dist/src/execboundary.js +430 -0
- package/dist/src/execboundary.js.map +1 -0
- package/dist/src/feedback.js +915 -0
- package/dist/src/feedback.js.map +1 -0
- package/dist/src/findingscheck.js +200 -0
- package/dist/src/findingscheck.js.map +1 -0
- package/dist/src/fsdenied.js +26 -0
- package/dist/src/fsdenied.js.map +1 -0
- package/dist/src/ghread.js +181 -0
- package/dist/src/ghread.js.map +1 -0
- package/dist/src/github.js +1063 -0
- package/dist/src/github.js.map +1 -0
- package/dist/src/homes.js +103 -0
- package/dist/src/homes.js.map +1 -0
- package/dist/src/hostroute.js +24 -0
- package/dist/src/hostroute.js.map +1 -0
- package/dist/src/improvements.js +625 -0
- package/dist/src/improvements.js.map +1 -0
- package/dist/src/install.js +946 -0
- package/dist/src/install.js.map +1 -0
- package/dist/src/installkind.js +40 -0
- package/dist/src/installkind.js.map +1 -0
- package/dist/src/ipc/capability.js +286 -0
- package/dist/src/ipc/capability.js.map +1 -0
- package/dist/src/ipc/client.js +226 -0
- package/dist/src/ipc/client.js.map +1 -0
- package/dist/src/ipc/control.js +70 -0
- package/dist/src/ipc/control.js.map +1 -0
- package/dist/src/ipc/ghreadshim.js +77 -0
- package/dist/src/ipc/ghreadshim.js.map +1 -0
- package/dist/src/ipc/launcher.js +65 -0
- package/dist/src/ipc/launcher.js.map +1 -0
- package/dist/src/ipc/permits.js +293 -0
- package/dist/src/ipc/permits.js.map +1 -0
- package/dist/src/ipc/postshim.js +137 -0
- package/dist/src/ipc/postshim.js.map +1 -0
- package/dist/src/ipc/protocol.js +239 -0
- package/dist/src/ipc/protocol.js.map +1 -0
- package/dist/src/ipc/server.js +312 -0
- package/dist/src/ipc/server.js.map +1 -0
- package/dist/src/ipc/workerspec.js +148 -0
- package/dist/src/ipc/workerspec.js.map +1 -0
- package/dist/src/learner/learner.js +1272 -0
- package/dist/src/learner/learner.js.map +1 -0
- package/dist/src/learner/miner.js +948 -0
- package/dist/src/learner/miner.js.map +1 -0
- package/dist/src/learner/packet.js +216 -0
- package/dist/src/learner/packet.js.map +1 -0
- package/dist/src/learner/receipt.js +135 -0
- package/dist/src/learner/receipt.js.map +1 -0
- package/dist/src/learner/status.js +38 -0
- package/dist/src/learner/status.js.map +1 -0
- package/dist/src/ledgercheck.js +120 -0
- package/dist/src/ledgercheck.js.map +1 -0
- package/dist/src/lessonledger.js +451 -0
- package/dist/src/lessonledger.js.map +1 -0
- package/dist/src/lessonselect.js +639 -0
- package/dist/src/lessonselect.js.map +1 -0
- package/dist/src/lessonshadow.js +540 -0
- package/dist/src/lessonshadow.js.map +1 -0
- package/dist/src/levers.js +302 -0
- package/dist/src/levers.js.map +1 -0
- package/dist/src/live/projection.js +450 -0
- package/dist/src/live/projection.js.map +1 -0
- package/dist/src/live/publish.js +83 -0
- package/dist/src/live/publish.js.map +1 -0
- package/dist/src/live/read.js +60 -0
- package/dist/src/live/read.js.map +1 -0
- package/dist/src/livecli.js +288 -0
- package/dist/src/livecli.js.map +1 -0
- package/dist/src/loginhint.js +42 -0
- package/dist/src/loginhint.js.map +1 -0
- package/dist/src/loginrefresh/atomic.js +66 -0
- package/dist/src/loginrefresh/atomic.js.map +1 -0
- package/dist/src/loginrefresh/lock.js +93 -0
- package/dist/src/loginrefresh/lock.js.map +1 -0
- package/dist/src/loginrefresh/main.js +58 -0
- package/dist/src/loginrefresh/main.js.map +1 -0
- package/dist/src/loginrefresh/pirefresh.js +49 -0
- package/dist/src/loginrefresh/pirefresh.js.map +1 -0
- package/dist/src/loginrefresh/refresher.js +286 -0
- package/dist/src/loginrefresh/refresher.js.map +1 -0
- package/dist/src/loginrefresh/supervisor.js +253 -0
- package/dist/src/loginrefresh/supervisor.js.map +1 -0
- package/dist/src/loginrefresh/types.js +4 -0
- package/dist/src/loginrefresh/types.js.map +1 -0
- package/dist/src/memory/context.js +251 -0
- package/dist/src/memory/context.js.map +1 -0
- package/dist/src/memory/datafence.js +5 -0
- package/dist/src/memory/datafence.js.map +1 -0
- package/dist/src/memory/delivery.js +131 -0
- package/dist/src/memory/delivery.js.map +1 -0
- package/dist/src/memory/eventtags.js +81 -0
- package/dist/src/memory/eventtags.js.map +1 -0
- package/dist/src/memory/health.js +713 -0
- package/dist/src/memory/health.js.map +1 -0
- package/dist/src/memory/import.js +504 -0
- package/dist/src/memory/import.js.map +1 -0
- package/dist/src/memory/layout.js +252 -0
- package/dist/src/memory/layout.js.map +1 -0
- package/dist/src/memory/legacy-file.js +100 -0
- package/dist/src/memory/legacy-file.js.map +1 -0
- package/dist/src/memory/lessons.js +370 -0
- package/dist/src/memory/lessons.js.map +1 -0
- package/dist/src/memory/ovsession.js +449 -0
- package/dist/src/memory/ovsession.js.map +1 -0
- package/dist/src/memory/relayout.js +259 -0
- package/dist/src/memory/relayout.js.map +1 -0
- package/dist/src/memory/roundactivity.js +180 -0
- package/dist/src/memory/roundactivity.js.map +1 -0
- package/dist/src/memory/selection.js +690 -0
- package/dist/src/memory/selection.js.map +1 -0
- package/dist/src/memory/shadowstatus.js +69 -0
- package/dist/src/memory/shadowstatus.js.map +1 -0
- package/dist/src/memory/store.js +83 -0
- package/dist/src/memory/store.js.map +1 -0
- package/dist/src/memory/textidentity.js +8 -0
- package/dist/src/memory/textidentity.js.map +1 -0
- package/dist/src/metrics.js +773 -0
- package/dist/src/metrics.js.map +1 -0
- package/dist/src/missingconfig.js +8 -0
- package/dist/src/missingconfig.js.map +1 -0
- package/dist/src/npmverbs.js +226 -0
- package/dist/src/npmverbs.js.map +1 -0
- package/dist/src/onboard/choices.js +191 -0
- package/dist/src/onboard/choices.js.map +1 -0
- package/dist/src/onboard/engine.js +344 -0
- package/dist/src/onboard/engine.js.map +1 -0
- package/dist/src/onboard/launch.js +83 -0
- package/dist/src/onboard/launch.js.map +1 -0
- package/dist/src/onboard/steps/appslug.js +211 -0
- package/dist/src/onboard/steps/appslug.js.map +1 -0
- package/dist/src/onboard/steps/bringup.js +408 -0
- package/dist/src/onboard/steps/bringup.js.map +1 -0
- package/dist/src/onboard/steps/compose.js +343 -0
- package/dist/src/onboard/steps/compose.js.map +1 -0
- package/dist/src/onboard/steps/configdelivery.js +50 -0
- package/dist/src/onboard/steps/configdelivery.js.map +1 -0
- package/dist/src/onboard/steps/configfill.js +1148 -0
- package/dist/src/onboard/steps/configfill.js.map +1 -0
- package/dist/src/onboard/steps/deploysh.js +80 -0
- package/dist/src/onboard/steps/deploysh.js.map +1 -0
- package/dist/src/onboard/steps/embeddings.js +472 -0
- package/dist/src/onboard/steps/embeddings.js.map +1 -0
- package/dist/src/onboard/steps/escalation.js +571 -0
- package/dist/src/onboard/steps/escalation.js.map +1 -0
- package/dist/src/onboard/steps/githubapp.js +1092 -0
- package/dist/src/onboard/steps/githubapp.js.map +1 -0
- package/dist/src/onboard/steps/golive.js +506 -0
- package/dist/src/onboard/steps/golive.js.map +1 -0
- package/dist/src/onboard/steps/index.js +67 -0
- package/dist/src/onboard/steps/index.js.map +1 -0
- package/dist/src/onboard/steps/ingress.js +762 -0
- package/dist/src/onboard/steps/ingress.js.map +1 -0
- package/dist/src/onboard/steps/inventory.js +420 -0
- package/dist/src/onboard/steps/inventory.js.map +1 -0
- package/dist/src/onboard/steps/llmauth.js +893 -0
- package/dist/src/onboard/steps/llmauth.js.map +1 -0
- package/dist/src/onboard/steps/memory.js +1060 -0
- package/dist/src/onboard/steps/memory.js.map +1 -0
- package/dist/src/onboard/steps/memorykeys.js +43 -0
- package/dist/src/onboard/steps/memorykeys.js.map +1 -0
- package/dist/src/onboard/steps/preflight.js +172 -0
- package/dist/src/onboard/steps/preflight.js.map +1 -0
- package/dist/src/onboard/steps/proof.js +502 -0
- package/dist/src/onboard/steps/proof.js.map +1 -0
- package/dist/src/onboard/steps/ssh.js +300 -0
- package/dist/src/onboard/steps/ssh.js.map +1 -0
- package/dist/src/onboard/steps/topology.js +291 -0
- package/dist/src/onboard/steps/topology.js.map +1 -0
- package/dist/src/onboard/steps/transport.js +511 -0
- package/dist/src/onboard/steps/transport.js.map +1 -0
- package/dist/src/onboard/steps/verifyup.js +362 -0
- package/dist/src/onboard/steps/verifyup.js.map +1 -0
- package/dist/src/onboard/steps/vmdeploy.js +368 -0
- package/dist/src/onboard/steps/vmdeploy.js.map +1 -0
- package/dist/src/onboard/toml.js +53 -0
- package/dist/src/onboard/toml.js.map +1 -0
- package/dist/src/opencli.js +508 -0
- package/dist/src/opencli.js.map +1 -0
- package/dist/src/openpr.js +457 -0
- package/dist/src/openpr.js.map +1 -0
- package/dist/src/openviking/client.js +821 -0
- package/dist/src/openviking/client.js.map +1 -0
- package/dist/src/openviking/context.js +218 -0
- package/dist/src/openviking/context.js.map +1 -0
- package/dist/src/openviking/embedder.js +457 -0
- package/dist/src/openviking/embedder.js.map +1 -0
- package/dist/src/openviking/gapsink.js +38 -0
- package/dist/src/openviking/gapsink.js.map +1 -0
- package/dist/src/openviking/health.js +69 -0
- package/dist/src/openviking/health.js.map +1 -0
- package/dist/src/openviking/index.js +24 -0
- package/dist/src/openviking/index.js.map +1 -0
- package/dist/src/openviking/lessonfind.js +54 -0
- package/dist/src/openviking/lessonfind.js.map +1 -0
- package/dist/src/openviking/probe.js +89 -0
- package/dist/src/openviking/probe.js.map +1 -0
- package/dist/src/openviking/proc.js +95 -0
- package/dist/src/openviking/proc.js.map +1 -0
- package/dist/src/openviking/provisionreport.js +144 -0
- package/dist/src/openviking/provisionreport.js.map +1 -0
- package/dist/src/openviking/reembed.js +317 -0
- package/dist/src/openviking/reembed.js.map +1 -0
- package/dist/src/openviking/relayout.js +153 -0
- package/dist/src/openviking/relayout.js.map +1 -0
- package/dist/src/openviking/sidecar-main.js +39 -0
- package/dist/src/openviking/sidecar-main.js.map +1 -0
- package/dist/src/openviking/sidecar.js +79 -0
- package/dist/src/openviking/sidecar.js.map +1 -0
- package/dist/src/openviking/store.js +1758 -0
- package/dist/src/openviking/store.js.map +1 -0
- package/dist/src/openviking/supervisor.js +422 -0
- package/dist/src/openviking/supervisor.js.map +1 -0
- package/dist/src/openviking/types.js +5 -0
- package/dist/src/openviking/types.js.map +1 -0
- package/dist/src/operator-recovery.js +172 -0
- package/dist/src/operator-recovery.js.map +1 -0
- package/dist/src/operatormessage.js +44 -0
- package/dist/src/operatormessage.js.map +1 -0
- package/dist/src/outcomes.js +1361 -0
- package/dist/src/outcomes.js.map +1 -0
- package/dist/src/piauthcopy.js +5 -0
- package/dist/src/piauthcopy.js.map +1 -0
- package/dist/src/picli.js +45 -0
- package/dist/src/picli.js.map +1 -0
- package/dist/src/picwd.js +25 -0
- package/dist/src/picwd.js.map +1 -0
- package/dist/src/pilogin.js +35 -0
- package/dist/src/pilogin.js.map +1 -0
- package/dist/src/pingpong.js +1028 -0
- package/dist/src/pingpong.js.map +1 -0
- package/dist/src/posting-journal.js +441 -0
- package/dist/src/posting-journal.js.map +1 -0
- package/dist/src/posting-outbox.js +662 -0
- package/dist/src/posting-outbox.js.map +1 -0
- package/dist/src/posting-receipt.js +203 -0
- package/dist/src/posting-receipt.js.map +1 -0
- package/dist/src/posting.js +348 -0
- package/dist/src/posting.js.map +1 -0
- package/dist/src/postops.js +637 -0
- package/dist/src/postops.js.map +1 -0
- package/dist/src/pr-activity.js +11 -0
- package/dist/src/pr-activity.js.map +1 -0
- package/dist/src/pr-author.js +5 -0
- package/dist/src/pr-author.js.map +1 -0
- package/dist/src/pr-conversation.js +355 -0
- package/dist/src/pr-conversation.js.map +1 -0
- package/dist/src/pr-session-lifecycle.js +542 -0
- package/dist/src/pr-session-lifecycle.js.map +1 -0
- package/dist/src/preflight.js +341 -0
- package/dist/src/preflight.js.map +1 -0
- package/dist/src/priorresolve.js +275 -0
- package/dist/src/priorresolve.js.map +1 -0
- package/dist/src/qcrbin.js +180 -0
- package/dist/src/qcrbin.js.map +1 -0
- package/dist/src/recheck.js +1398 -0
- package/dist/src/recheck.js.map +1 -0
- package/dist/src/reconcile.js +820 -0
- package/dist/src/reconcile.js.map +1 -0
- package/dist/src/recordedfindings.js +15 -0
- package/dist/src/recordedfindings.js.map +1 -0
- package/dist/src/regression.js +546 -0
- package/dist/src/regression.js.map +1 -0
- package/dist/src/replay.js +598 -0
- package/dist/src/replay.js.map +1 -0
- package/dist/src/requiredpasses.js +113 -0
- package/dist/src/requiredpasses.js.map +1 -0
- package/dist/src/resumecheck.js +168 -0
- package/dist/src/resumecheck.js.map +1 -0
- package/dist/src/reviewcli.js +671 -0
- package/dist/src/reviewcli.js.map +1 -0
- package/dist/src/reviewcontext.js +22 -0
- package/dist/src/reviewcontext.js.map +1 -0
- package/dist/src/reviewdetach.js +574 -0
- package/dist/src/reviewdetach.js.map +1 -0
- package/dist/src/reviewhistory.js +284 -0
- package/dist/src/reviewhistory.js.map +1 -0
- package/dist/src/reviewhome.js +26 -0
- package/dist/src/reviewhome.js.map +1 -0
- package/dist/src/reviewmemory.js +110 -0
- package/dist/src/reviewmemory.js.map +1 -0
- package/dist/src/reviewrendercli.js +104 -0
- package/dist/src/reviewrendercli.js.map +1 -0
- package/dist/src/round-work.js +20 -0
- package/dist/src/round-work.js.map +1 -0
- package/dist/src/runhost.js +72 -0
- package/dist/src/runhost.js.map +1 -0
- package/dist/src/scanauth.js +25 -0
- package/dist/src/scanauth.js.map +1 -0
- package/dist/src/scanbox.js +846 -0
- package/dist/src/scanbox.js.map +1 -0
- package/dist/src/scancli.js +1074 -0
- package/dist/src/scancli.js.map +1 -0
- package/dist/src/scandriverlog.js +30 -0
- package/dist/src/scandriverlog.js.map +1 -0
- package/dist/src/session-bridge.js +75 -0
- package/dist/src/session-bridge.js.map +1 -0
- package/dist/src/session-command-payload.js +29 -0
- package/dist/src/session-command-payload.js.map +1 -0
- package/dist/src/session-command-supervisor.js +939 -0
- package/dist/src/session-command-supervisor.js.map +1 -0
- package/dist/src/sessionjsonl.js +85 -0
- package/dist/src/sessionjsonl.js.map +1 -0
- package/dist/src/sessions.js +541 -0
- package/dist/src/sessions.js.map +1 -0
- package/dist/src/setup/adapters.js +330 -0
- package/dist/src/setup/adapters.js.map +1 -0
- package/dist/src/setup/baselines.js +64 -0
- package/dist/src/setup/baselines.js.map +1 -0
- package/dist/src/setup/caserunner.js +554 -0
- package/dist/src/setup/caserunner.js.map +1 -0
- package/dist/src/setup/configcommit.js +358 -0
- package/dist/src/setup/configcommit.js.map +1 -0
- package/dist/src/setup/engine.js +672 -0
- package/dist/src/setup/engine.js.map +1 -0
- package/dist/src/setup/facts.js +593 -0
- package/dist/src/setup/facts.js.map +1 -0
- package/dist/src/setup/findings.js +948 -0
- package/dist/src/setup/findings.js.map +1 -0
- package/dist/src/setup/history.js +338 -0
- package/dist/src/setup/history.js.map +1 -0
- package/dist/src/setup/interview.js +185 -0
- package/dist/src/setup/interview.js.map +1 -0
- package/dist/src/setup/ledger.js +207 -0
- package/dist/src/setup/ledger.js.map +1 -0
- package/dist/src/setup/pins.js +43 -0
- package/dist/src/setup/pins.js.map +1 -0
- package/dist/src/setup/portrait.js +432 -0
- package/dist/src/setup/portrait.js.map +1 -0
- package/dist/src/setup/presentation.js +9 -0
- package/dist/src/setup/presentation.js.map +1 -0
- package/dist/src/setup/profile.js +417 -0
- package/dist/src/setup/profile.js.map +1 -0
- package/dist/src/setup/replay.js +240 -0
- package/dist/src/setup/replay.js.map +1 -0
- package/dist/src/setup/replaybuild.js +311 -0
- package/dist/src/setup/replaybuild.js.map +1 -0
- package/dist/src/setup/replayrun.js +806 -0
- package/dist/src/setup/replayrun.js.map +1 -0
- package/dist/src/setup/replaysource.js +169 -0
- package/dist/src/setup/replaysource.js.map +1 -0
- package/dist/src/setup/retune.js +333 -0
- package/dist/src/setup/retune.js.map +1 -0
- package/dist/src/setup/retunelog.js +51 -0
- package/dist/src/setup/retunelog.js.map +1 -0
- package/dist/src/setup/scan.js +725 -0
- package/dist/src/setup/scan.js.map +1 -0
- package/dist/src/setup/scanbuild.js +133 -0
- package/dist/src/setup/scanbuild.js.map +1 -0
- package/dist/src/setup/scanfacts.js +96 -0
- package/dist/src/setup/scanfacts.js.map +1 -0
- package/dist/src/setup/scanlease.js +251 -0
- package/dist/src/setup/scanlease.js.map +1 -0
- package/dist/src/setup/scanreport.js +289 -0
- package/dist/src/setup/scanreport.js.map +1 -0
- package/dist/src/setup/scanrun.js +1733 -0
- package/dist/src/setup/scanrun.js.map +1 -0
- package/dist/src/setup/scantree.js +257 -0
- package/dist/src/setup/scantree.js.map +1 -0
- package/dist/src/setup/stage2.js +617 -0
- package/dist/src/setup/stage2.js.map +1 -0
- package/dist/src/setup/stage2request.js +259 -0
- package/dist/src/setup/stage2request.js.map +1 -0
- package/dist/src/setup/survey.js +307 -0
- package/dist/src/setup/survey.js.map +1 -0
- package/dist/src/setup/surveyrun.js +549 -0
- package/dist/src/setup/surveyrun.js.map +1 -0
- package/dist/src/setup/textsniff.js +89 -0
- package/dist/src/setup/textsniff.js.map +1 -0
- package/dist/src/setup/trackersink.js +395 -0
- package/dist/src/setup/trackersink.js.map +1 -0
- package/dist/src/setup/triage.js +636 -0
- package/dist/src/setup/triage.js.map +1 -0
- package/dist/src/setup/tuning.js +585 -0
- package/dist/src/setup/tuning.js.map +1 -0
- package/dist/src/setup/unitcut.js +437 -0
- package/dist/src/setup/unitcut.js.map +1 -0
- package/dist/src/singleflight.js +72 -0
- package/dist/src/singleflight.js.map +1 -0
- package/dist/src/slack/announce.js +725 -0
- package/dist/src/slack/announce.js.map +1 -0
- package/dist/src/slack/api.js +227 -0
- package/dist/src/slack/api.js.map +1 -0
- package/dist/src/slack/messages.js +158 -0
- package/dist/src/slack/messages.js.map +1 -0
- package/dist/src/slack/origin.js +550 -0
- package/dist/src/slack/origin.js.map +1 -0
- package/dist/src/slack/policy.js +225 -0
- package/dist/src/slack/policy.js.map +1 -0
- package/dist/src/slack/reply.js +153 -0
- package/dist/src/slack/reply.js.map +1 -0
- package/dist/src/slack/router.js +189 -0
- package/dist/src/slack/router.js.map +1 -0
- package/dist/src/slack/socket.js +323 -0
- package/dist/src/slack/socket.js.map +1 -0
- package/dist/src/slack/types.js +11 -0
- package/dist/src/slack/types.js.map +1 -0
- package/dist/src/sqlitehint.js +30 -0
- package/dist/src/sqlitehint.js.map +1 -0
- package/dist/src/ssh-observation.js +25 -0
- package/dist/src/ssh-observation.js.map +1 -0
- package/dist/src/state.js +5869 -0
- package/dist/src/state.js.map +1 -0
- package/dist/src/statemachine.js +220 -0
- package/dist/src/statemachine.js.map +1 -0
- package/dist/src/stubs.js +52 -0
- package/dist/src/stubs.js.map +1 -0
- package/dist/src/takeover.js +506 -0
- package/dist/src/takeover.js.map +1 -0
- package/dist/src/takeoverpi.js +249 -0
- package/dist/src/takeoverpi.js.map +1 -0
- package/dist/src/terminal-failure.js +26 -0
- package/dist/src/terminal-failure.js.map +1 -0
- package/dist/src/thread-resolution-refusal.js +4 -0
- package/dist/src/thread-resolution-refusal.js.map +1 -0
- package/dist/src/tmux.js +126 -0
- package/dist/src/tmux.js.map +1 -0
- package/dist/src/trackerid.js +43 -0
- package/dist/src/trackerid.js.map +1 -0
- package/dist/src/transcriptindex.js +512 -0
- package/dist/src/transcriptindex.js.map +1 -0
- package/dist/src/tui/actions.js +404 -0
- package/dist/src/tui/actions.js.map +1 -0
- package/dist/src/tui/alerts.js +523 -0
- package/dist/src/tui/alerts.js.map +1 -0
- package/dist/src/tui/app.js +1835 -0
- package/dist/src/tui/app.js.map +1 -0
- package/dist/src/tui/archiveops.js +164 -0
- package/dist/src/tui/archiveops.js.map +1 -0
- package/dist/src/tui/autofile.js +191 -0
- package/dist/src/tui/autofile.js.map +1 -0
- package/dist/src/tui/board.js +1143 -0
- package/dist/src/tui/board.js.map +1 -0
- package/dist/src/tui/candidates.js +699 -0
- package/dist/src/tui/candidates.js.map +1 -0
- package/dist/src/tui/cellwidth.js +151 -0
- package/dist/src/tui/cellwidth.js.map +1 -0
- package/dist/src/tui/changelog-store.js +404 -0
- package/dist/src/tui/changelog-store.js.map +1 -0
- package/dist/src/tui/chord.js +26 -0
- package/dist/src/tui/chord.js.map +1 -0
- package/dist/src/tui/clipboard.js +81 -0
- package/dist/src/tui/clipboard.js.map +1 -0
- package/dist/src/tui/cmdbar.js +253 -0
- package/dist/src/tui/cmdbar.js.map +1 -0
- package/dist/src/tui/companion.js +1275 -0
- package/dist/src/tui/companion.js.map +1 -0
- package/dist/src/tui/companionplan.js +200 -0
- package/dist/src/tui/companionplan.js.map +1 -0
- package/dist/src/tui/companiontab.js +61 -0
- package/dist/src/tui/companiontab.js.map +1 -0
- package/dist/src/tui/confighome.js +105 -0
- package/dist/src/tui/confighome.js.map +1 -0
- package/dist/src/tui/connect.js +44 -0
- package/dist/src/tui/connect.js.map +1 -0
- package/dist/src/tui/deploy-ceremony.js +75 -0
- package/dist/src/tui/deploy-ceremony.js.map +1 -0
- package/dist/src/tui/deploy-drain.js +93 -0
- package/dist/src/tui/deploy-drain.js.map +1 -0
- package/dist/src/tui/deploy-process.js +234 -0
- package/dist/src/tui/deploy-process.js.map +1 -0
- package/dist/src/tui/deploytab.js +1263 -0
- package/dist/src/tui/deploytab.js.map +1 -0
- package/dist/src/tui/design.js +111 -0
- package/dist/src/tui/design.js.map +1 -0
- package/dist/src/tui/digesttab.js +148 -0
- package/dist/src/tui/digesttab.js.map +1 -0
- package/dist/src/tui/emptystate.js +32 -0
- package/dist/src/tui/emptystate.js.map +1 -0
- package/dist/src/tui/evidence.js +790 -0
- package/dist/src/tui/evidence.js.map +1 -0
- package/dist/src/tui/feed.js +415 -0
- package/dist/src/tui/feed.js.map +1 -0
- package/dist/src/tui/feedbacktab.js +907 -0
- package/dist/src/tui/feedbacktab.js.map +1 -0
- package/dist/src/tui/filters.js +72 -0
- package/dist/src/tui/filters.js.map +1 -0
- package/dist/src/tui/ghread.js +272 -0
- package/dist/src/tui/ghread.js.map +1 -0
- package/dist/src/tui/historypull.js +61 -0
- package/dist/src/tui/historypull.js.map +1 -0
- package/dist/src/tui/inboxpull.js +197 -0
- package/dist/src/tui/inboxpull.js.map +1 -0
- package/dist/src/tui/index.js +1425 -0
- package/dist/src/tui/index.js.map +1 -0
- package/dist/src/tui/issuesink.js +206 -0
- package/dist/src/tui/issuesink.js.map +1 -0
- package/dist/src/tui/jsonfile.js +32 -0
- package/dist/src/tui/jsonfile.js.map +1 -0
- package/dist/src/tui/keys.js +97 -0
- package/dist/src/tui/keys.js.map +1 -0
- package/dist/src/tui/layout.js +70 -0
- package/dist/src/tui/layout.js.map +1 -0
- package/dist/src/tui/learning.js +469 -0
- package/dist/src/tui/learning.js.map +1 -0
- package/dist/src/tui/lessonswitch.js +103 -0
- package/dist/src/tui/lessonswitch.js.map +1 -0
- package/dist/src/tui/livecontrol.js +167 -0
- package/dist/src/tui/livecontrol.js.map +1 -0
- package/dist/src/tui/memforward.js +310 -0
- package/dist/src/tui/memforward.js.map +1 -0
- package/dist/src/tui/memincident.js +287 -0
- package/dist/src/tui/memincident.js.map +1 -0
- package/dist/src/tui/memory.js +485 -0
- package/dist/src/tui/memory.js.map +1 -0
- package/dist/src/tui/memtab.js +513 -0
- package/dist/src/tui/memtab.js.map +1 -0
- package/dist/src/tui/metricstab.js +979 -0
- package/dist/src/tui/metricstab.js.map +1 -0
- package/dist/src/tui/model.js +104 -0
- package/dist/src/tui/model.js.map +1 -0
- package/dist/src/tui/mouse.js +83 -0
- package/dist/src/tui/mouse.js.map +1 -0
- package/dist/src/tui/msg.js +196 -0
- package/dist/src/tui/msg.js.map +1 -0
- package/dist/src/tui/nativecompanion.js +321 -0
- package/dist/src/tui/nativecompanion.js.map +1 -0
- package/dist/src/tui/openurl.js +17 -0
- package/dist/src/tui/openurl.js.map +1 -0
- package/dist/src/tui/paint.js +501 -0
- package/dist/src/tui/paint.js.map +1 -0
- package/dist/src/tui/panes.js +74 -0
- package/dist/src/tui/panes.js.map +1 -0
- package/dist/src/tui/pipane.js +166 -0
- package/dist/src/tui/pipane.js.map +1 -0
- package/dist/src/tui/poll-hooks.js +11 -0
- package/dist/src/tui/poll-hooks.js.map +1 -0
- package/dist/src/tui/poll.js +113 -0
- package/dist/src/tui/poll.js.map +1 -0
- package/dist/src/tui/proposals.js +715 -0
- package/dist/src/tui/proposals.js.map +1 -0
- package/dist/src/tui/prpause.js +132 -0
- package/dist/src/tui/prpause.js.map +1 -0
- package/dist/src/tui/reload.js +351 -0
- package/dist/src/tui/reload.js.map +1 -0
- package/dist/src/tui/remote.js +312 -0
- package/dist/src/tui/remote.js.map +1 -0
- package/dist/src/tui/rollover.js +767 -0
- package/dist/src/tui/rollover.js.map +1 -0
- package/dist/src/tui/scantab.js +1053 -0
- package/dist/src/tui/scantab.js.map +1 -0
- package/dist/src/tui/setupentry.js +81 -0
- package/dist/src/tui/setupentry.js.map +1 -0
- package/dist/src/tui/sidebar.js +602 -0
- package/dist/src/tui/sidebar.js.map +1 -0
- package/dist/src/tui/sshtriage.js +393 -0
- package/dist/src/tui/sshtriage.js.map +1 -0
- package/dist/src/tui/startup.js +172 -0
- package/dist/src/tui/startup.js.map +1 -0
- package/dist/src/tui/tabs.js +41 -0
- package/dist/src/tui/tabs.js.map +1 -0
- package/dist/src/tui/termmirror.js +217 -0
- package/dist/src/tui/termmirror.js.map +1 -0
- package/dist/src/tui/theme.js +95 -0
- package/dist/src/tui/theme.js.map +1 -0
- package/dist/src/tui/ticketstab.js +224 -0
- package/dist/src/tui/ticketstab.js.map +1 -0
- package/dist/src/tui/tmuxsocket.js +101 -0
- package/dist/src/tui/tmuxsocket.js.map +1 -0
- package/dist/src/tui/trackertickets.js +77 -0
- package/dist/src/tui/trackertickets.js.map +1 -0
- package/dist/src/tui/unwedge.js +245 -0
- package/dist/src/tui/unwedge.js.map +1 -0
- package/dist/src/tui/viewer.js +479 -0
- package/dist/src/tui/viewer.js.map +1 -0
- package/dist/src/tui/viewerinput.js +125 -0
- package/dist/src/tui/viewerinput.js.map +1 -0
- package/dist/src/updatenotice.js +143 -0
- package/dist/src/updatenotice.js.map +1 -0
- package/dist/src/usage.js +1007 -0
- package/dist/src/usage.js.map +1 -0
- package/dist/src/verdicts.js +3848 -0
- package/dist/src/verdicts.js.map +1 -0
- package/dist/src/version.js +58 -0
- package/dist/src/version.js.map +1 -0
- package/dist/src/wakes.js +411 -0
- package/dist/src/wakes.js.map +1 -0
- package/dist/src/webhook.js +725 -0
- package/dist/src/webhook.js.map +1 -0
- package/dist/src/webhookheal.js +238 -0
- package/dist/src/webhookheal.js.map +1 -0
- package/dist/src/wire.js +1801 -0
- package/dist/src/wire.js.map +1 -0
- package/dist/src/worker-session-host.js +531 -0
- package/dist/src/worker-session-host.js.map +1 -0
- package/dist/src/workerbreaker.js +112 -0
- package/dist/src/workerbreaker.js.map +1 -0
- package/dist/src/workercontrol.js +49 -0
- package/dist/src/workercontrol.js.map +1 -0
- package/dist/src/workerlease.js +351 -0
- package/dist/src/workerlease.js.map +1 -0
- package/dist/src/workerliveness.js +84 -0
- package/dist/src/workerliveness.js.map +1 -0
- package/dist/src/workerlog.js +65 -0
- package/dist/src/workerlog.js.map +1 -0
- package/dist/src/workerruntime.js +10 -0
- package/dist/src/workerruntime.js.map +1 -0
- package/dist/src/workersupervisor.js +1206 -0
- package/dist/src/workersupervisor.js.map +1 -0
- package/dist/src/workerusage.js +23 -0
- package/dist/src/workerusage.js.map +1 -0
- package/dist/src/workerworld.js +332 -0
- package/dist/src/workerworld.js.map +1 -0
- package/dist/src/worktrees.js +984 -0
- package/dist/src/worktrees.js.map +1 -0
- package/docker/Dockerfile +284 -0
- package/docker/Dockerfile.dockerignore +35 -0
- package/docker/README.md +221 -0
- package/docker/companion/Dockerfile +139 -0
- package/docker/companion/agents/evidence.md +34 -0
- package/docker/companion/agents/explore.md +26 -0
- package/docker/companion/agents/pass-survey.md +49 -0
- package/docker/companion/agents/study.md +26 -0
- package/docker/companion/entrypoint.sh +343 -0
- package/docker/companion/memory-health.mjs +269 -0
- package/docker/entrypoint.sh +782 -0
- package/docker/memory/Dockerfile +191 -0
- package/docker/memory/Dockerfile.dockerignore +20 -0
- package/docker/memory/README.md +60 -0
- package/docker/memory/entrypoint.sh +163 -0
- package/docker/setid/qcr-setid.c +109 -0
- package/docker/tunnel/Dockerfile.cloudflared +51 -0
- package/docker/tunnel/Dockerfile.ngrok +40 -0
- package/docker/tunnel/sidecar.mjs +411 -0
- package/docker/vm/tmux.conf +26 -0
- package/docker-compose.yml +348 -0
- package/extensions/cli/bash-guard-ambient.ts +71 -0
- package/extensions/cli/bash-guard.ts +12 -0
- package/extensions/cli/companion-guard.ts +8 -0
- package/extensions/cli/debug-round.ts +9 -0
- package/extensions/cli/inject-bridge.ts +8 -0
- package/extensions/cli/ledger-pin.ts +13 -0
- package/extensions/cli/lens.ts +22 -0
- package/extensions/cli/muted-theme.ts +9 -0
- package/extensions/cli/onboarding.ts +8 -0
- package/extensions/cli/setup.ts +8 -0
- package/extensions/cli/tui-view.ts +8 -0
- package/extensions/companion-guard.ts +411 -0
- package/extensions/debug-round.ts +281 -0
- package/extensions/inject-bridge.ts +630 -0
- package/extensions/inline-bash.ts +102 -0
- package/extensions/muted-theme.json +68 -0
- package/extensions/muted-theme.ts +23 -0
- package/extensions/onboarding.ts +233 -0
- package/extensions/setup-replay.ts +336 -0
- package/extensions/setup-scan.ts +1236 -0
- package/extensions/setup-triage.ts +190 -0
- package/extensions/setup.ts +1428 -0
- package/extensions/tui-view.ts +489 -0
- package/extensions/vendor/openviking-pi/LICENSE +201 -0
- package/extensions/vendor/openviking-pi/NOTICE +68 -0
- package/extensions/vendor/openviking-pi/README.md +550 -0
- package/extensions/vendor/openviking-pi/client.ts +588 -0
- package/extensions/vendor/openviking-pi/config.json +28 -0
- package/extensions/vendor/openviking-pi/config.ts +271 -0
- package/extensions/vendor/openviking-pi/index.ts +523 -0
- package/extensions/vendor/openviking-pi/lib/capture-adapter.d.mts +10 -0
- package/extensions/vendor/openviking-pi/lib/capture-adapter.mjs +88 -0
- package/extensions/vendor/openviking-pi/lib/takeover-core.d.mts +80 -0
- package/extensions/vendor/openviking-pi/lib/takeover-core.mjs +406 -0
- package/extensions/vendor/openviking-pi/lib/uri-guard-adapter.d.mts +1 -0
- package/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs +42 -0
- package/extensions/vendor/openviking-pi/patches/0000-vendoring-and-build-conformance.patch +726 -0
- package/extensions/vendor/openviking-pi/patches/0001-remove-session-before-compact-handler.patch +101 -0
- package/extensions/vendor/openviking-pi/patches/0002-no-ambient-work-in-subagent-leaves.patch +202 -0
- package/extensions/vendor/openviking-pi/patches/0003-never-auto-create-openviking-sessions.patch +120 -0
- package/extensions/vendor/openviking-pi/patches/0004-viking-write-durable-batch-write.patch +521 -0
- package/extensions/vendor/openviking-pi/patches/0005-second-memory-namespace.patch +786 -0
- package/extensions/vendor/openviking-pi/patches/0006-writes-that-stick-and-honest-errors.patch +996 -0
- package/extensions/vendor/openviking-pi/patches/0007-bounded-recall-no-commit.patch +794 -0
- package/extensions/vendor/openviking-pi/patches/0008-pr-derived-recall.patch +379 -0
- package/extensions/vendor/openviking-pi/patches/0009-pr-session-tools-in-round-areas.patch +375 -0
- package/extensions/vendor/openviking-pi/patches/0010-typed-lessons.patch +448 -0
- package/extensions/vendor/openviking-pi/patches/0011-review-session-memory-boundary.patch +382 -0
- package/extensions/vendor/openviking-pi/patches/0012-typecheck-against-the-real-pi.patch +129 -0
- package/extensions/vendor/openviking-pi/patches/0013-createopenviking-factory.patch +1168 -0
- package/extensions/vendor/openviking-pi/qcr-hint.ts +313 -0
- package/extensions/vendor/openviking-pi/qcr-honest.ts +183 -0
- package/extensions/vendor/openviking-pi/qcr-hooks.ts +87 -0
- package/extensions/vendor/openviking-pi/qcr-leaf.ts +78 -0
- package/extensions/vendor/openviking-pi/qcr-lesson.ts +231 -0
- package/extensions/vendor/openviking-pi/qcr-namespaces.ts +198 -0
- package/extensions/vendor/openviking-pi/qcr-recall.ts +288 -0
- package/extensions/vendor/openviking-pi/qcr-shim.ts +142 -0
- package/extensions/vendor/openviking-pi/qcr-write.ts +427 -0
- package/extensions/vendor/openviking-pi/recall.ts +149 -0
- package/extensions/vendor/openviking-pi/shared/capture-utils.d.mts +9 -0
- package/extensions/vendor/openviking-pi/shared/capture-utils.mjs +515 -0
- package/extensions/vendor/openviking-pi/shared/credentials.d.mts +14 -0
- package/extensions/vendor/openviking-pi/shared/credentials.mjs +228 -0
- package/extensions/vendor/openviking-pi/shared/pending-queue.d.mts +19 -0
- package/extensions/vendor/openviking-pi/shared/pending-queue.mjs +458 -0
- package/extensions/vendor/openviking-pi/shared/profile-inject.d.mts +17 -0
- package/extensions/vendor/openviking-pi/shared/profile-inject.mjs +294 -0
- package/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs +195 -0
- package/extensions/vendor/openviking-pi/shared/recall-core.d.mts +13 -0
- package/extensions/vendor/openviking-pi/shared/recall-core.mjs +609 -0
- package/extensions/vendor/openviking-pi/shared/retryable.mjs +9 -0
- package/extensions/vendor/openviking-pi/shared/session-model.d.mts +3 -0
- package/extensions/vendor/openviking-pi/shared/session-model.mjs +57 -0
- package/extensions/vendor/openviking-pi/shared/uri-guard.mjs +56 -0
- package/extensions/vendor/openviking-pi/shared/workspace-peer.d.mts +5 -0
- package/extensions/vendor/openviking-pi/shared/workspace-peer.mjs +16 -0
- package/extensions/vendor/openviking-pi/sync.ts +163 -0
- package/extensions/vendor/openviking-pi/takeover.ts +36 -0
- package/extensions/vendor/openviking-pi/tools.ts +479 -0
- package/extensions/vendor/openviking-pi/upstream.json +48 -0
- package/package.json +138 -4
- package/profiles/default/README.md +21 -0
- package/profiles/default/addenda/.gitkeep +0 -0
- package/profiles/default/profile.toml +17 -0
- package/profiles/example-django/README.md +21 -0
- package/profiles/example-django/addenda/10-migration-discipline.md +13 -0
- package/profiles/example-django/addenda/20-new-column-nullability.md +12 -0
- package/profiles/example-django/addenda/30-test-doctrine.md +12 -0
- package/profiles/example-django/addenda/40-orm-usage.md +19 -0
- package/profiles/example-django/addenda/50-declared-shape.md +10 -0
- package/profiles/example-django/addenda/60-config-placement.md +14 -0
- package/profiles/example-django/heuristics.toml +24 -0
- package/profiles/example-django/profile.toml +9 -0
- package/profiles/fast/README.md +24 -0
- package/profiles/fast/profile.toml +59 -0
- package/profiles/minimal/README.md +17 -0
- package/profiles/minimal/addenda/.gitkeep +0 -0
- package/profiles/minimal/profile.toml +8 -0
- package/profiles/snappy/README.md +24 -0
- package/profiles/snappy/addenda/10-race-as-question.md +6 -0
- package/profiles/snappy/profile.toml +46 -0
- package/prompts/companion-day-open.md +46 -0
- package/prompts/companion-first-run.md +104 -0
- package/prompts/companion.md +821 -0
- package/prompts/conversation-system.md +117 -0
- package/prompts/eod-sweep.md +120 -0
- package/prompts/onboarding.md +74 -0
- package/prompts/pass-common.md +52 -0
- package/prompts/pass-quality-common.md +22 -0
- package/prompts/round-first.md +874 -0
- package/prompts/round-follow-up.md +991 -0
- package/prompts/round-re-review.md +889 -0
- package/prompts/round-recheck.md +196 -0
- package/prompts/round-staleness.md +856 -0
- package/schemas/review-result.v1.json +391 -0
- package/schemas/scan-result.v1.json +421 -0
- package/schemas/version.v1.json +57 -0
- package/scripts/approve-pr.sh +16 -0
- package/scripts/build-stamp.mjs +67 -0
- package/scripts/commit-verdict.sh +155 -0
- package/scripts/companion-e2e.sh +250 -0
- package/scripts/companion-memory-forward.mjs +1966 -0
- package/scripts/config-fingerprint.sh +28 -0
- package/scripts/deploy-manifest.mjs +141 -0
- package/scripts/deploy.sh +1435 -0
- package/scripts/directory-lock.mjs +193 -0
- package/scripts/heartbeat-fresh.mjs +54 -0
- package/scripts/install-locator.sh +328 -0
- package/scripts/install-wrapper.sh +76 -0
- package/scripts/memory-search-check.mjs +98 -0
- package/scripts/mint-token.sh +212 -0
- package/scripts/openviking-embedder.py +392 -0
- package/scripts/openviking-ov-conf.mjs +161 -0
- package/scripts/openviking-provision.mjs +1122 -0
- package/scripts/openviking-reembed.mjs +1154 -0
- package/scripts/post-review.sh +16 -0
- package/scripts/pr-checks.sh +256 -0
- package/scripts/pr-context.py +174 -0
- package/scripts/pr-context.sh +63 -0
- package/scripts/pr-self.sh +144 -0
- package/scripts/pr-threads.sh +145 -0
- package/scripts/qcr +15 -0
- package/scripts/qcr-host.sh +769 -0
- package/scripts/render-review.sh +24 -0
- package/scripts/reply-thread.sh +16 -0
- package/scripts/required-passes.py +112 -0
- package/scripts/smoke-companion.sh +211 -0
- package/scripts/tui-deploy-runner.mjs +61 -0
- package/scripts/verify-dist.mjs +201 -0
- package/scripts/vm-ghcr-login.sh +188 -0
- package/seeds/agents/pass-baseline.md +61 -0
- package/seeds/agents/pass-contracts.md +30 -0
- package/seeds/agents/pass-data-safety.md +54 -0
- package/seeds/agents/pass-delivery.md +37 -0
- package/seeds/agents/pass-prod-risk.md +24 -0
- package/seeds/agents/pass-security.md +31 -0
- package/seeds/agents/pass-statelessness.md +27 -0
- package/seeds/agents/pass-ui.md +23 -0
- package/seeds/agents/pass-validate.md +50 -0
- package/seeds/prompts/conversation-system.md +117 -0
- package/seeds/prompts/eod-sweep.md +120 -0
- package/seeds/prompts/pass-common.md +52 -0
- package/skills/companion/adjudicate/SKILL.md +247 -0
- package/skills/companion/evidence/SKILL.md +150 -0
- package/skills/companion/land/SKILL.md +200 -0
- package/skills/companion/replay/SKILL.md +138 -0
- package/skills/companion/setup/SKILL.md +167 -0
- package/skills/companion/survey/SKILL.md +160 -0
- package/skills/selfimprove/README.md +34 -0
- package/skills/selfimprove/SKILL.md +127 -0
- package/skills/selfimprove/agents/openai.yaml +2 -0
- package/skills/selfimprove/commands/selfimprove.md +6 -0
- package/skills/selfimprove/references/fix-loop.md +49 -0
- package/skills/selfimprove/references/ledger.md +20 -0
- package/skills/selfimprove/references/setup.md +40 -0
- package/src/anomalies.ts +566 -0
- package/src/answerworker.ts +251 -0
- package/src/appstamp.ts +65 -0
- package/src/archive/admission.ts +3 -0
- package/src/archive/archivedb.ts +548 -0
- package/src/archive/archiver.ts +1963 -0
- package/src/archive/archivewrite.ts +279 -0
- package/src/archive/bundle.ts +333 -0
- package/src/archive/dbmove.ts +911 -0
- package/src/archive/duplicatecounts.ts +98 -0
- package/src/archive/eligibility.ts +181 -0
- package/src/archive/extract.ts +342 -0
- package/src/archive/fsutil.ts +415 -0
- package/src/archive/gzfile.ts +370 -0
- package/src/archive/kinds.ts +21 -0
- package/src/archive/livecheckpoint.ts +217 -0
- package/src/archive/liveretention.ts +180 -0
- package/src/archive/manifest.ts +519 -0
- package/src/archive/overseer.ts +336 -0
- package/src/archive/piglobal.ts +174 -0
- package/src/archive/plan.ts +612 -0
- package/src/archive/prarchive.ts +984 -0
- package/src/archive/prfiles.ts +406 -0
- package/src/archive/report.ts +252 -0
- package/src/archive/restore.ts +330 -0
- package/src/archive/rows.ts +187 -0
- package/src/archive/seal.ts +630 -0
- package/src/archive/status.ts +719 -0
- package/src/archive/storepass.ts +581 -0
- package/src/backfill.ts +362 -0
- package/src/bench/cost.ts +113 -0
- package/src/bench/exec.ts +90 -0
- package/src/bench/values.ts +13 -0
- package/src/botcontrol.ts +176 -0
- package/src/botworker.ts +953 -0
- package/src/capture.ts +321 -0
- package/src/cases.ts +1789 -0
- package/src/channelfs.ts +26 -0
- package/src/checklist.ts +506 -0
- package/src/ciretry.ts +141 -0
- package/src/cli.ts +2271 -0
- package/src/cliops.ts +384 -0
- package/src/clonedir.ts +15 -0
- package/src/commandeffects.ts +57 -0
- package/src/commands.ts +1678 -0
- package/src/companioninbox.ts +239 -0
- package/src/compare.ts +957 -0
- package/src/config.ts +2050 -0
- package/src/configcheck.ts +133 -0
- package/src/coreext.ts +47 -0
- package/src/daemon.ts +1302 -0
- package/src/debuground.ts +927 -0
- package/src/debugroundpi.ts +262 -0
- package/src/diagnostics.ts +14 -0
- package/src/digest.ts +183 -0
- package/src/dispatch.ts +2250 -0
- package/src/engine/answerguard.ts +27 -0
- package/src/engine/botsdk.ts +336 -0
- package/src/engine/caserunner-sdk.ts +423 -0
- package/src/engine/debugpi.ts +235 -0
- package/src/eod.ts +669 -0
- package/src/eodpinwatch.ts +556 -0
- package/src/escalation.ts +1253 -0
- package/src/eventloop.ts +1045 -0
- package/src/execboundary.ts +633 -0
- package/src/feedback.ts +1162 -0
- package/src/findingscheck.ts +298 -0
- package/src/fsdenied.ts +24 -0
- package/src/ghread.ts +242 -0
- package/src/github.ts +1497 -0
- package/src/homes.ts +175 -0
- package/src/hostroute.ts +53 -0
- package/src/improvements.ts +787 -0
- package/src/install.ts +1103 -0
- package/src/installkind.ts +50 -0
- package/src/ipc/capability.ts +333 -0
- package/src/ipc/client.ts +269 -0
- package/src/ipc/control.ts +90 -0
- package/src/ipc/ghreadshim.ts +94 -0
- package/src/ipc/launcher.ts +65 -0
- package/src/ipc/permits.ts +362 -0
- package/src/ipc/postshim.ts +164 -0
- package/src/ipc/protocol.ts +342 -0
- package/src/ipc/server.ts +371 -0
- package/src/ipc/workerspec.ts +218 -0
- package/src/learner/learner.ts +1655 -0
- package/src/learner/miner.ts +1290 -0
- package/src/learner/packet.ts +340 -0
- package/src/learner/receipt.ts +168 -0
- package/src/learner/status.ts +107 -0
- package/src/ledgercheck.ts +157 -0
- package/src/lessonledger.ts +703 -0
- package/src/lessonselect.ts +888 -0
- package/src/lessonshadow.ts +810 -0
- package/src/levers.ts +393 -0
- package/src/live/projection.ts +491 -0
- package/src/live/publish.ts +92 -0
- package/src/live/read.ts +86 -0
- package/src/livecli.ts +336 -0
- package/src/loginhint.ts +56 -0
- package/src/loginrefresh/atomic.ts +76 -0
- package/src/loginrefresh/lock.ts +104 -0
- package/src/loginrefresh/main.ts +59 -0
- package/src/loginrefresh/pirefresh.ts +57 -0
- package/src/loginrefresh/refresher.ts +326 -0
- package/src/loginrefresh/supervisor.ts +273 -0
- package/src/loginrefresh/types.ts +35 -0
- package/src/memory/context.ts +385 -0
- package/src/memory/datafence.ts +9 -0
- package/src/memory/delivery.ts +171 -0
- package/src/memory/eventtags.ts +80 -0
- package/src/memory/health.ts +953 -0
- package/src/memory/import.ts +664 -0
- package/src/memory/layout.ts +261 -0
- package/src/memory/legacy-file.ts +104 -0
- package/src/memory/lessons.ts +447 -0
- package/src/memory/ovsession.ts +601 -0
- package/src/memory/relayout.ts +335 -0
- package/src/memory/roundactivity.ts +209 -0
- package/src/memory/selection.ts +989 -0
- package/src/memory/shadowstatus.ts +125 -0
- package/src/memory/store.ts +275 -0
- package/src/memory/textidentity.ts +8 -0
- package/src/metrics.ts +1056 -0
- package/src/missingconfig.ts +7 -0
- package/src/npmverbs.ts +264 -0
- package/src/onboard/choices.ts +222 -0
- package/src/onboard/engine.ts +518 -0
- package/src/onboard/launch.ts +115 -0
- package/src/onboard/steps/appslug.ts +265 -0
- package/src/onboard/steps/bringup.ts +482 -0
- package/src/onboard/steps/compose.ts +459 -0
- package/src/onboard/steps/configdelivery.ts +58 -0
- package/src/onboard/steps/configfill.ts +1352 -0
- package/src/onboard/steps/deploysh.ts +105 -0
- package/src/onboard/steps/embeddings.ts +550 -0
- package/src/onboard/steps/escalation.ts +640 -0
- package/src/onboard/steps/githubapp.ts +1414 -0
- package/src/onboard/steps/golive.ts +577 -0
- package/src/onboard/steps/index.ts +71 -0
- package/src/onboard/steps/ingress.ts +907 -0
- package/src/onboard/steps/inventory.ts +526 -0
- package/src/onboard/steps/llmauth.ts +1095 -0
- package/src/onboard/steps/memory.ts +1290 -0
- package/src/onboard/steps/memorykeys.ts +85 -0
- package/src/onboard/steps/preflight.ts +191 -0
- package/src/onboard/steps/proof.ts +624 -0
- package/src/onboard/steps/ssh.ts +377 -0
- package/src/onboard/steps/topology.ts +337 -0
- package/src/onboard/steps/transport.ts +665 -0
- package/src/onboard/steps/verifyup.ts +448 -0
- package/src/onboard/steps/vmdeploy.ts +442 -0
- package/src/onboard/toml.ts +50 -0
- package/src/opencli.ts +591 -0
- package/src/openpr.ts +568 -0
- package/src/openviking/client.ts +1131 -0
- package/src/openviking/context.ts +263 -0
- package/src/openviking/embedder.ts +516 -0
- package/src/openviking/gapsink.ts +63 -0
- package/src/openviking/health.ts +83 -0
- package/src/openviking/index.ts +119 -0
- package/src/openviking/lessonfind.ts +92 -0
- package/src/openviking/probe.ts +129 -0
- package/src/openviking/proc.ts +110 -0
- package/src/openviking/provisionreport.ts +160 -0
- package/src/openviking/reembed.ts +412 -0
- package/src/openviking/relayout.ts +177 -0
- package/src/openviking/sidecar-main.ts +38 -0
- package/src/openviking/sidecar.ts +106 -0
- package/src/openviking/store.ts +2025 -0
- package/src/openviking/supervisor.ts +474 -0
- package/src/openviking/types.ts +174 -0
- package/src/operator-recovery.ts +237 -0
- package/src/operatormessage.ts +52 -0
- package/src/outcomes.ts +1670 -0
- package/src/piauthcopy.ts +12 -0
- package/src/picli.ts +49 -0
- package/src/picwd.ts +25 -0
- package/src/pilogin.ts +37 -0
- package/src/pingpong.ts +1339 -0
- package/src/posting-journal.ts +549 -0
- package/src/posting-outbox.ts +802 -0
- package/src/posting-receipt.ts +324 -0
- package/src/posting.ts +603 -0
- package/src/postops.ts +832 -0
- package/src/pr-activity.ts +20 -0
- package/src/pr-author.ts +6 -0
- package/src/pr-conversation.ts +432 -0
- package/src/pr-session-lifecycle.ts +631 -0
- package/src/preflight.ts +391 -0
- package/src/priorresolve.ts +343 -0
- package/src/qcrbin.ts +186 -0
- package/src/recheck.ts +1775 -0
- package/src/reconcile.ts +1030 -0
- package/src/recordedfindings.ts +27 -0
- package/src/regression.ts +833 -0
- package/src/replay.ts +816 -0
- package/src/requiredpasses.ts +148 -0
- package/src/resumecheck.ts +246 -0
- package/src/reviewcli.ts +787 -0
- package/src/reviewcontext.ts +35 -0
- package/src/reviewdetach.ts +734 -0
- package/src/reviewhistory.ts +427 -0
- package/src/reviewhome.ts +36 -0
- package/src/reviewmemory.ts +133 -0
- package/src/reviewrendercli.ts +139 -0
- package/src/round-work.ts +42 -0
- package/src/runhost.ts +108 -0
- package/src/scanauth.ts +36 -0
- package/src/scanbox.ts +1081 -0
- package/src/scancli.ts +1296 -0
- package/src/scandriverlog.ts +32 -0
- package/src/session-bridge.ts +139 -0
- package/src/session-command-payload.ts +35 -0
- package/src/session-command-supervisor.ts +1142 -0
- package/src/sessionjsonl.ts +88 -0
- package/src/sessions.ts +659 -0
- package/src/setup/adapters.ts +335 -0
- package/src/setup/baselines.ts +110 -0
- package/src/setup/caserunner.ts +611 -0
- package/src/setup/configcommit.ts +443 -0
- package/src/setup/engine.ts +1001 -0
- package/src/setup/facts.ts +627 -0
- package/src/setup/findings.ts +1264 -0
- package/src/setup/history.ts +443 -0
- package/src/setup/interview.ts +243 -0
- package/src/setup/ledger.ts +324 -0
- package/src/setup/pins.ts +66 -0
- package/src/setup/portrait.ts +635 -0
- package/src/setup/presentation.ts +18 -0
- package/src/setup/profile.ts +508 -0
- package/src/setup/replay.ts +370 -0
- package/src/setup/replaybuild.ts +392 -0
- package/src/setup/replayrun.ts +1096 -0
- package/src/setup/replaysource.ts +198 -0
- package/src/setup/retune.ts +415 -0
- package/src/setup/retunelog.ts +95 -0
- package/src/setup/scan.ts +1033 -0
- package/src/setup/scanbuild.ts +168 -0
- package/src/setup/scanfacts.ts +107 -0
- package/src/setup/scanlease.ts +297 -0
- package/src/setup/scanreport.ts +373 -0
- package/src/setup/scanrun.ts +2268 -0
- package/src/setup/scantree.ts +259 -0
- package/src/setup/stage2.ts +926 -0
- package/src/setup/stage2request.ts +347 -0
- package/src/setup/survey.ts +458 -0
- package/src/setup/surveyrun.ts +758 -0
- package/src/setup/textsniff.ts +95 -0
- package/src/setup/trackersink.ts +433 -0
- package/src/setup/triage.ts +768 -0
- package/src/setup/tuning.ts +766 -0
- package/src/setup/unitcut.ts +523 -0
- package/src/singleflight.ts +86 -0
- package/src/slack/announce.ts +911 -0
- package/src/slack/api.ts +303 -0
- package/src/slack/messages.ts +288 -0
- package/src/slack/origin.ts +599 -0
- package/src/slack/policy.ts +354 -0
- package/src/slack/reply.ts +201 -0
- package/src/slack/router.ts +285 -0
- package/src/slack/socket.ts +384 -0
- package/src/slack/types.ts +108 -0
- package/src/sqlitehint.ts +32 -0
- package/src/ssh-observation.ts +30 -0
- package/src/state.ts +8243 -0
- package/src/statemachine.ts +369 -0
- package/src/stubs.ts +68 -0
- package/src/takeover.ts +634 -0
- package/src/takeoverpi.ts +293 -0
- package/src/terminal-failure.ts +41 -0
- package/src/thread-resolution-refusal.ts +2 -0
- package/src/tmux.ts +153 -0
- package/src/trackerid.ts +41 -0
- package/src/transcriptindex.ts +665 -0
- package/src/tui/actions.ts +484 -0
- package/src/tui/alerts.ts +666 -0
- package/src/tui/app.ts +1979 -0
- package/src/tui/archiveops.ts +192 -0
- package/src/tui/autofile.ts +233 -0
- package/src/tui/board.ts +1432 -0
- package/src/tui/candidates.ts +889 -0
- package/src/tui/cellwidth.ts +148 -0
- package/src/tui/changelog-store.ts +503 -0
- package/src/tui/chord.ts +25 -0
- package/src/tui/clipboard.ts +92 -0
- package/src/tui/cmdbar.ts +296 -0
- package/src/tui/companion.ts +1427 -0
- package/src/tui/companionplan.ts +247 -0
- package/src/tui/companiontab.ts +83 -0
- package/src/tui/confighome.ts +155 -0
- package/src/tui/connect.ts +68 -0
- package/src/tui/deploy-ceremony.ts +104 -0
- package/src/tui/deploy-drain.ts +129 -0
- package/src/tui/deploy-process.ts +265 -0
- package/src/tui/deploytab.ts +1523 -0
- package/src/tui/design.ts +125 -0
- package/src/tui/digesttab.ts +214 -0
- package/src/tui/emptystate.ts +39 -0
- package/src/tui/evidence.ts +999 -0
- package/src/tui/feed.ts +604 -0
- package/src/tui/feedbacktab.ts +1077 -0
- package/src/tui/filters.ts +90 -0
- package/src/tui/ghread.ts +321 -0
- package/src/tui/historypull.ts +81 -0
- package/src/tui/inboxpull.ts +236 -0
- package/src/tui/index.ts +1565 -0
- package/src/tui/issuesink.ts +238 -0
- package/src/tui/jsonfile.ts +42 -0
- package/src/tui/keys.ts +109 -0
- package/src/tui/layout.ts +108 -0
- package/src/tui/learning.ts +627 -0
- package/src/tui/lessonswitch.ts +118 -0
- package/src/tui/livecontrol.ts +228 -0
- package/src/tui/memforward.ts +443 -0
- package/src/tui/memincident.ts +363 -0
- package/src/tui/memory.ts +620 -0
- package/src/tui/memtab.ts +606 -0
- package/src/tui/metricstab.ts +1177 -0
- package/src/tui/model.ts +131 -0
- package/src/tui/mouse.ts +98 -0
- package/src/tui/msg.ts +268 -0
- package/src/tui/nativecompanion.ts +417 -0
- package/src/tui/openurl.ts +21 -0
- package/src/tui/paint.ts +511 -0
- package/src/tui/panes.ts +98 -0
- package/src/tui/pipane.ts +219 -0
- package/src/tui/poll-hooks.ts +12 -0
- package/src/tui/poll.ts +147 -0
- package/src/tui/proposals.ts +838 -0
- package/src/tui/prpause.ts +150 -0
- package/src/tui/reload.ts +436 -0
- package/src/tui/remote.ts +413 -0
- package/src/tui/rollover.ts +969 -0
- package/src/tui/scantab.ts +1290 -0
- package/src/tui/setupentry.ts +93 -0
- package/src/tui/sidebar.ts +749 -0
- package/src/tui/sshtriage.ts +510 -0
- package/src/tui/startup.ts +231 -0
- package/src/tui/tabs.ts +45 -0
- package/src/tui/termmirror.ts +224 -0
- package/src/tui/theme.ts +95 -0
- package/src/tui/ticketstab.ts +310 -0
- package/src/tui/tmuxsocket.ts +129 -0
- package/src/tui/trackertickets.ts +84 -0
- package/src/tui/unwedge.ts +286 -0
- package/src/tui/viewer.ts +575 -0
- package/src/tui/viewerinput.ts +173 -0
- package/src/updatenotice.ts +178 -0
- package/src/usage.ts +1154 -0
- package/src/verdicts.ts +4689 -0
- package/src/version.ts +80 -0
- package/src/wakes.ts +476 -0
- package/src/webhook.ts +942 -0
- package/src/webhookheal.ts +276 -0
- package/src/wire.ts +2153 -0
- package/src/worker-session-host.ts +602 -0
- package/src/workerbreaker.ts +156 -0
- package/src/workercontrol.ts +104 -0
- package/src/workerlease.ts +441 -0
- package/src/workerliveness.ts +103 -0
- package/src/workerlog.ts +79 -0
- package/src/workerruntime.ts +30 -0
- package/src/workersupervisor.ts +1538 -0
- package/src/workerusage.ts +42 -0
- package/src/workerworld.ts +427 -0
- package/src/worktrees.ts +1138 -0
- package/tests/fixtures/regression-cases.json +795 -0
- package/tests/fixtures/seed-manifest.json +19 -0
|
@@ -0,0 +1,1272 @@
|
|
|
1
|
+
// The learner: candidates in, curated lessons out, and a person told when the
|
|
2
|
+
// curation did not happen.
|
|
3
|
+
//
|
|
4
|
+
// The loop, daemon-side and deterministic up to the curator's own judgement:
|
|
5
|
+
//
|
|
6
|
+
// 1. MINE (src/learner/miner.ts) — at EOD − `lessons_mine_lead_min`, and on
|
|
7
|
+
// the operator's word (`qcr lessons mine`): every human outcome becomes a
|
|
8
|
+
// row of `lesson_candidates`, deduplicated by a deterministic ref, with a
|
|
9
|
+
// class. The first mine also turns the digests' lost "Learnings" into
|
|
10
|
+
// candidates (`source = digest-backfill`), and a post-approval recheck's
|
|
11
|
+
// APPROVE → REQUEST_CHANGES reversal is one too (`source = recheck`): the
|
|
12
|
+
// reviewer's own conclusion, labelled so, offered after every other
|
|
13
|
+
// source.
|
|
14
|
+
// 2. PACKET (src/learner/packet.ts) — at the day's EOD fire: candidates
|
|
15
|
+
// first offered more than `lessons_expiry_ops_days` ago are expired
|
|
16
|
+
// (recorded on the row, in an event, and in the packet's own list — never
|
|
17
|
+
// silent); up to `lessons_packet_new_max` queued ones are offered for the first
|
|
18
|
+
// time; every undecided offered candidate is carried forward. Clustered
|
|
19
|
+
// by class with the 90-day recurrence, the fixed / left-open counterweight
|
|
20
|
+
// and the lessons already covering the class. Written to
|
|
21
|
+
// `state/eod/<day>/outcomes.{json,md}`; the sweep prompt points at it
|
|
22
|
+
// (`prepareEod` → wire.ts's `dayContext`).
|
|
23
|
+
// 3. RECEIPT — the curator answers with the whitelisted command
|
|
24
|
+
// `eod-curation-receipt` (src/learner/receipt.ts): per candidate,
|
|
25
|
+
// adopted / declined with a reason / refused (the write failed).
|
|
26
|
+
// 4. VERIFY — an adoption counts only when a lesson in `experiences/`
|
|
27
|
+
// carries a typed header whose evidence cites the candidate
|
|
28
|
+
// (`cand:c<id>`, src/memory/lessons.ts). Checked against memory while it
|
|
29
|
+
// reads healthy; a claimed lesson memory does not hold, or a refused
|
|
30
|
+
// write, wakes `eod_lessons_not_persisted` and puts the candidate back
|
|
31
|
+
// in the packet. No receipt `lessons_receipt_wait_min` after the sweep
|
|
32
|
+
// was delivered wakes `eod_curation_missing`. Both are wake kinds and
|
|
33
|
+
// ride status.json `memory.curation` — the board banner, the desktop
|
|
34
|
+
// notification and `qcr status`.
|
|
35
|
+
//
|
|
36
|
+
// Also measured: the look-for : don't-raise balance of the lessons in force
|
|
37
|
+
// (`lessonBalance`), the learner's health metric.
|
|
38
|
+
//
|
|
39
|
+
// Nothing here writes memory or GitHub, and nothing here is on the round
|
|
40
|
+
// path. Its tables live on the state database beside the outcome capture's.
|
|
41
|
+
import { withinBudget } from "@quickchatai/pi-quickreview/src/budget.js";
|
|
42
|
+
import { mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
43
|
+
import { join } from "node:path";
|
|
44
|
+
import { MEMORY_DEFAULTS } from "../config.js";
|
|
45
|
+
import { localWallClockToInstant, zoneDateString, zonedParts, parseHHMM } from "../eod.js";
|
|
46
|
+
import { jsonColumn } from "../lessonledger.js";
|
|
47
|
+
import { EXPERIENCES_AREA, areaOfId } from "../memory/layout.js";
|
|
48
|
+
import { coveringLessons, lessonBalance, parseLesson, } from "../memory/lessons.js";
|
|
49
|
+
import { chainRoots, outcomeRows, findingClass, lensIdsOf, mineDigestBackfill, mineFates, mineFeedback, mineHumanRecall, minePostMerge, mineRecheckFlips, mineTaggedComments, RECALL_SCAN_LIMITS, reviewFateCandidates, tableExists, } from "./miner.js";
|
|
50
|
+
import { addDays, dayDiff, majorityPolarity, packetPointer, packetMarkdownRel, packetRelDir, renderCurationSection, renderPacketMarkdown, } from "./packet.js";
|
|
51
|
+
import { candidateLabel } from "./receipt.js";
|
|
52
|
+
export { curationPhrase } from "./status.js";
|
|
53
|
+
export const LEARNER_WAKE = Object.freeze({
|
|
54
|
+
missing: "eod_curation_missing",
|
|
55
|
+
notPersisted: "eod_lessons_not_persisted",
|
|
56
|
+
});
|
|
57
|
+
/** The learner's knobs at their shipped values — the `[memory]` defaults
|
|
58
|
+
* (src/config.ts MEMORY_DEFAULTS), which hold each value once. */
|
|
59
|
+
export const LEARNER_DEFAULTS = Object.freeze({
|
|
60
|
+
lessons_mine_lead_min: MEMORY_DEFAULTS.lessons_mine_lead_min,
|
|
61
|
+
lessons_mine_days: MEMORY_DEFAULTS.lessons_mine_days,
|
|
62
|
+
lessons_receipt_wait_min: MEMORY_DEFAULTS.lessons_receipt_wait_min,
|
|
63
|
+
lessons_expiry_ops_days: MEMORY_DEFAULTS.lessons_expiry_ops_days,
|
|
64
|
+
lessons_packet_new_max: MEMORY_DEFAULTS.lessons_packet_new_max,
|
|
65
|
+
lessons_recall_window_days: MEMORY_DEFAULTS.lessons_recall_window_days,
|
|
66
|
+
lessons_recurrence_days: MEMORY_DEFAULTS.lessons_recurrence_days,
|
|
67
|
+
lessons_digest_backfill_from: MEMORY_DEFAULTS.lessons_digest_backfill_from,
|
|
68
|
+
lessons_digest_backfill_to: MEMORY_DEFAULTS.lessons_digest_backfill_to,
|
|
69
|
+
});
|
|
70
|
+
/** The `[memory] lessons_*` knobs (src/config.ts) as the learner takes them,
|
|
71
|
+
* with floors — a mistyped 0 must not expire every candidate at once or wake
|
|
72
|
+
* the moment the sweep is delivered. One mapping, for wire.ts and the CLI. */
|
|
73
|
+
export function learnerKnobsOf(m) {
|
|
74
|
+
return {
|
|
75
|
+
lessons_mine_lead_min: Math.max(0, m.lessons_mine_lead_min),
|
|
76
|
+
lessons_mine_days: Math.max(1, m.lessons_mine_days),
|
|
77
|
+
lessons_receipt_wait_min: Math.max(1, m.lessons_receipt_wait_min),
|
|
78
|
+
lessons_expiry_ops_days: Math.max(1, m.lessons_expiry_ops_days),
|
|
79
|
+
lessons_packet_new_max: Math.max(0, m.lessons_packet_new_max),
|
|
80
|
+
lessons_recall_window_days: Math.max(1, m.lessons_recall_window_days),
|
|
81
|
+
lessons_recurrence_days: Math.max(1, m.lessons_recurrence_days),
|
|
82
|
+
lessons_digest_backfill_from: m.lessons_digest_backfill_from,
|
|
83
|
+
lessons_digest_backfill_to: m.lessons_digest_backfill_to,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const SCHEMA = `
|
|
87
|
+
CREATE TABLE IF NOT EXISTS lesson_candidates (
|
|
88
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
89
|
+
-- the dedup key: one human outcome is one candidate, whichever mine saw it
|
|
90
|
+
ref TEXT NOT NULL UNIQUE,
|
|
91
|
+
source TEXT NOT NULL,
|
|
92
|
+
kind TEXT NOT NULL,
|
|
93
|
+
polarity TEXT NOT NULL,
|
|
94
|
+
class TEXT NOT NULL,
|
|
95
|
+
lens_ids TEXT NOT NULL DEFAULT '[]',
|
|
96
|
+
pr INTEGER,
|
|
97
|
+
round_no INTEGER,
|
|
98
|
+
finding_key TEXT,
|
|
99
|
+
path TEXT,
|
|
100
|
+
line INTEGER,
|
|
101
|
+
summary TEXT NOT NULL,
|
|
102
|
+
quote TEXT,
|
|
103
|
+
evidence TEXT NOT NULL DEFAULT '[]',
|
|
104
|
+
occurred_at TEXT NOT NULL,
|
|
105
|
+
mined_at TEXT NOT NULL,
|
|
106
|
+
-- the ops day it first rode a packet; NULL = queued, never offered
|
|
107
|
+
offered_day TEXT,
|
|
108
|
+
last_offered_day TEXT,
|
|
109
|
+
offers INTEGER NOT NULL DEFAULT 0,
|
|
110
|
+
-- the ops day a refused write or an unfound adoption re-opened it: its
|
|
111
|
+
-- expiry clock restarts there (NULL = it runs from offered_day)
|
|
112
|
+
reopened_day TEXT,
|
|
113
|
+
-- open | adopting (the receipt said adopted; memory not checked yet) |
|
|
114
|
+
-- adopted (a lesson header cites it) | declined | expired |
|
|
115
|
+
-- withdrawn (its human outcome changed since it was mined — never deleted)
|
|
116
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
117
|
+
decided_at TEXT,
|
|
118
|
+
decided_day TEXT,
|
|
119
|
+
reason TEXT,
|
|
120
|
+
lesson_ids TEXT,
|
|
121
|
+
claimed_lesson TEXT,
|
|
122
|
+
receipt_day TEXT,
|
|
123
|
+
receipt_at TEXT,
|
|
124
|
+
updated_at TEXT NOT NULL
|
|
125
|
+
);
|
|
126
|
+
CREATE INDEX IF NOT EXISTS lesson_candidates_status ON lesson_candidates (status, offered_day);
|
|
127
|
+
CREATE INDEX IF NOT EXISTS lesson_candidates_class ON lesson_candidates (class, occurred_at);
|
|
128
|
+
CREATE TABLE IF NOT EXISTS eod_curations (
|
|
129
|
+
day TEXT PRIMARY KEY,
|
|
130
|
+
packet_at TEXT,
|
|
131
|
+
offered TEXT NOT NULL DEFAULT '[]',
|
|
132
|
+
new_today TEXT NOT NULL DEFAULT '[]',
|
|
133
|
+
expired TEXT NOT NULL DEFAULT '[]',
|
|
134
|
+
fired_at TEXT,
|
|
135
|
+
receipt_at TEXT,
|
|
136
|
+
receipt TEXT,
|
|
137
|
+
missing_woken_at TEXT,
|
|
138
|
+
-- [{id, why}] adoptions memory does not hold and refused writes
|
|
139
|
+
not_persisted TEXT NOT NULL DEFAULT '[]',
|
|
140
|
+
-- when the list last went from empty to non-empty (the incident's start)
|
|
141
|
+
not_persisted_since TEXT,
|
|
142
|
+
-- the not_persisted items (id + why) a wake has already named
|
|
143
|
+
not_persisted_woken TEXT NOT NULL DEFAULT '[]',
|
|
144
|
+
updated_at TEXT NOT NULL
|
|
145
|
+
);
|
|
146
|
+
CREATE TABLE IF NOT EXISTS learner_marks (
|
|
147
|
+
key TEXT PRIMARY KEY,
|
|
148
|
+
value TEXT,
|
|
149
|
+
at TEXT NOT NULL
|
|
150
|
+
);
|
|
151
|
+
CREATE TABLE IF NOT EXISTS learner_recall_scans (
|
|
152
|
+
pr INTEGER PRIMARY KEY,
|
|
153
|
+
merged_at TEXT NOT NULL,
|
|
154
|
+
base_ref TEXT,
|
|
155
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
156
|
+
last_scan_at TEXT,
|
|
157
|
+
merge_commit TEXT,
|
|
158
|
+
touches INTEGER,
|
|
159
|
+
done INTEGER NOT NULL DEFAULT 0,
|
|
160
|
+
outcome TEXT
|
|
161
|
+
);
|
|
162
|
+
`;
|
|
163
|
+
/** A candidate in one of these is decided: it leaves the not-persisted lists,
|
|
164
|
+
* and a refused write re-opens only an expired one (`applyReceipt`). */
|
|
165
|
+
const SETTLED_STATUSES = ["adopted", "declined", "expired", "withdrawn"];
|
|
166
|
+
const SETTLED_SQL = SETTLED_STATUSES.map((s) => `'${s}'`).join(", ");
|
|
167
|
+
const DAY_MS = 86_400_000;
|
|
168
|
+
/** A lesson written moments before its receipt may not be listed yet. */
|
|
169
|
+
const VERIFY_GRACE_MS = 10 * 60_000;
|
|
170
|
+
/** How long `prepareEod` waits for a mine it had to start itself. */
|
|
171
|
+
const PREPARE_MINE_BUDGET_MS = 60_000;
|
|
172
|
+
/** How long a lesson read for the packet may take. */
|
|
173
|
+
const LESSON_READ_BUDGET_MS = 20_000;
|
|
174
|
+
/** With no adoption waiting, the lessons in force are re-read this often. */
|
|
175
|
+
const LESSON_REFRESH_MS = 30 * 60_000;
|
|
176
|
+
/** How many curation days back the status looks for an unresolved failure. */
|
|
177
|
+
const UNRESOLVED_SCAN_DAYS = 30;
|
|
178
|
+
/** `p`, or "timeout" once `ms` passed. A rejection reads as "timeout" too —
|
|
179
|
+
* the caller's fallback is the same — but its cause goes to `onReject`, so a
|
|
180
|
+
* failure is never mistaken for a slow answer in the log. */
|
|
181
|
+
async function withTimeout(p, ms, onReject) {
|
|
182
|
+
const result = await withinBudget(p.catch((error) => {
|
|
183
|
+
onReject(error);
|
|
184
|
+
return "timeout";
|
|
185
|
+
}), ms);
|
|
186
|
+
return result.kind === "done" ? result.value : "timeout";
|
|
187
|
+
}
|
|
188
|
+
/** The ops day a candidate's expiry clock runs from: the day it was
|
|
189
|
+
* re-opened, else its first offer. */
|
|
190
|
+
function clockDay(c) {
|
|
191
|
+
return c.reopened_day ?? c.offered_day ?? "";
|
|
192
|
+
}
|
|
193
|
+
function writeAtomic(path, body) {
|
|
194
|
+
const tmp = `${path}.tmp-${process.pid}`;
|
|
195
|
+
writeFileSync(tmp, body);
|
|
196
|
+
renameSync(tmp, path);
|
|
197
|
+
}
|
|
198
|
+
/** Shared admission for the status incident and the durable wake. */
|
|
199
|
+
function missingCuration(row, laterReceipt, now, waitMs) {
|
|
200
|
+
const fired = Date.parse(row.fired_at ?? "");
|
|
201
|
+
return (!laterReceipt &&
|
|
202
|
+
row.receipt_at === null &&
|
|
203
|
+
jsonColumn(row.offered, []).length > 0 &&
|
|
204
|
+
Number.isFinite(fired) &&
|
|
205
|
+
(row.missing_woken_at !== null || now - fired >= waitMs));
|
|
206
|
+
}
|
|
207
|
+
export class Learner {
|
|
208
|
+
deps;
|
|
209
|
+
store;
|
|
210
|
+
cfg;
|
|
211
|
+
now;
|
|
212
|
+
log;
|
|
213
|
+
mining = null;
|
|
214
|
+
timer = null;
|
|
215
|
+
ticking = false;
|
|
216
|
+
/** The last complete read of the lessons in force. */
|
|
217
|
+
lessonsRead = null;
|
|
218
|
+
constructor(deps) {
|
|
219
|
+
this.deps = deps;
|
|
220
|
+
this.store = deps.store;
|
|
221
|
+
this.cfg = { ...LEARNER_DEFAULTS, ...(deps.config ?? {}) };
|
|
222
|
+
this.now = deps.now ?? (() => new Date());
|
|
223
|
+
this.log = deps.log ?? (() => { });
|
|
224
|
+
this.store.db.exec(SCHEMA);
|
|
225
|
+
}
|
|
226
|
+
ts() {
|
|
227
|
+
return this.now().toISOString();
|
|
228
|
+
}
|
|
229
|
+
/** The EOD date `now` falls on, in the EOD timezone. */
|
|
230
|
+
today() {
|
|
231
|
+
return zoneDateString(this.now(), this.deps.timeZone);
|
|
232
|
+
}
|
|
233
|
+
mark(key) {
|
|
234
|
+
const row = this.store.db.prepare("SELECT value FROM learner_marks WHERE key = ?").get(key);
|
|
235
|
+
return row ? (row.value ?? "") : null;
|
|
236
|
+
}
|
|
237
|
+
setMark(key, value) {
|
|
238
|
+
this.store.db
|
|
239
|
+
.prepare("INSERT INTO learner_marks (key, value, at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value, at = excluded.at")
|
|
240
|
+
.run(key, value, this.ts());
|
|
241
|
+
}
|
|
242
|
+
// ---- 1. mine ---------------------------------------------------------------
|
|
243
|
+
/** Insert drafts; returns how many were new per source. */
|
|
244
|
+
insert(drafts) {
|
|
245
|
+
const at = this.ts();
|
|
246
|
+
const stmt = this.store.db.prepare(`INSERT OR IGNORE INTO lesson_candidates
|
|
247
|
+
(ref, source, kind, polarity, class, lens_ids, pr, round_no, finding_key, path, line,
|
|
248
|
+
summary, quote, evidence, occurred_at, mined_at, updated_at)
|
|
249
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
250
|
+
const added = {};
|
|
251
|
+
this.store.db.transaction(() => {
|
|
252
|
+
for (const d of drafts) {
|
|
253
|
+
const r = stmt.run(d.ref, d.source, d.kind, d.polarity, d.class, JSON.stringify(d.lens_ids), d.pr, d.round_no, d.finding_key, d.path, d.line, d.summary, d.quote, JSON.stringify(d.evidence), d.occurred_at, at, at);
|
|
254
|
+
if (r.changes > 0)
|
|
255
|
+
added[d.source] = (added[d.source] ?? 0) + 1;
|
|
256
|
+
}
|
|
257
|
+
})();
|
|
258
|
+
return added;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Mine every source once (single-flight: a mine already running is joined,
|
|
262
|
+
* never doubled). A source that throws is reported in `errors`; the others
|
|
263
|
+
* still land.
|
|
264
|
+
*/
|
|
265
|
+
mine() {
|
|
266
|
+
if (this.mining)
|
|
267
|
+
return this.mining;
|
|
268
|
+
this.mining = this.mineOnce().finally(() => {
|
|
269
|
+
this.mining = null;
|
|
270
|
+
});
|
|
271
|
+
return this.mining;
|
|
272
|
+
}
|
|
273
|
+
async mineOnce() {
|
|
274
|
+
const now = this.now();
|
|
275
|
+
const since = this.mineSince(now);
|
|
276
|
+
const report = {
|
|
277
|
+
added: 0,
|
|
278
|
+
seen: {},
|
|
279
|
+
added_by_source: {},
|
|
280
|
+
recall: null,
|
|
281
|
+
digest: null,
|
|
282
|
+
fates: { revised: 0, withdrawn: 0, reinstated: 0 },
|
|
283
|
+
relinked: 0,
|
|
284
|
+
errors: [],
|
|
285
|
+
};
|
|
286
|
+
const drafts = [];
|
|
287
|
+
const run = (name, fn) => {
|
|
288
|
+
try {
|
|
289
|
+
drafts.push(...fn());
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
report.errors.push(`${name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
run("fates", () => mineFates(this.store, since));
|
|
296
|
+
// The ledger before the tagged comments: a [feedback] comment the ledger
|
|
297
|
+
// holds is a `feedback_comment`; only a drained one is a `tagged_comment`.
|
|
298
|
+
run("feedback", () => mineFeedback(this.store, since));
|
|
299
|
+
run("tagged comments", () => mineTaggedComments(this.store, since));
|
|
300
|
+
run("human recall", () => mineHumanRecall(this.store, since, this.deps.botLogin));
|
|
301
|
+
// The recheck's own APPROVE → REQUEST_CHANGES reversals — the reviewer's
|
|
302
|
+
// conclusion, so a candidate only, gated on a standing APPROVE and one per
|
|
303
|
+
// (PR, head) (miner.ts header).
|
|
304
|
+
run("recheck reversals", () => mineRecheckFlips(this.store, since));
|
|
305
|
+
// Post-merge recall stores its candidates as it records each read.
|
|
306
|
+
let recallAdded = 0;
|
|
307
|
+
if (this.deps.git) {
|
|
308
|
+
try {
|
|
309
|
+
const r = await minePostMerge(this.store, {
|
|
310
|
+
...this.recallScope(now, this.deps.git),
|
|
311
|
+
maxPrs: RECALL_SCAN_LIMITS.prsPerMine,
|
|
312
|
+
persist: (d) => {
|
|
313
|
+
recallAdded += this.insert(d).recall ?? 0;
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
drafts.push(...r.drafts);
|
|
317
|
+
report.recall = { scanned: r.scanned, unknown: r.unknown };
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
report.errors.push(`post-merge: ${err instanceof Error ? err.message : String(err)}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
for (const d of drafts)
|
|
324
|
+
report.seen[d.source] = (report.seen[d.source] ?? 0) + 1;
|
|
325
|
+
report.added_by_source = this.insert(drafts);
|
|
326
|
+
if (recallAdded > 0)
|
|
327
|
+
report.added_by_source.recall = (report.added_by_source.recall ?? 0) + recallAdded;
|
|
328
|
+
try {
|
|
329
|
+
const oldest = this.store.db
|
|
330
|
+
.prepare("SELECT MIN(occurred_at) AS at FROM lesson_candidates WHERE status='open' AND source IN ('feedback','tagged-comment')")
|
|
331
|
+
.get();
|
|
332
|
+
const relinkDrafts = oldest.at !== null && oldest.at < since
|
|
333
|
+
? [...mineFeedback(this.store, oldest.at), ...mineTaggedComments(this.store, oldest.at)]
|
|
334
|
+
: drafts;
|
|
335
|
+
report.relinked = this.relink(relinkDrafts);
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
report.errors.push(`relink: ${err instanceof Error ? err.message : String(err)}`);
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
report.fates = this.reviseFates(since);
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
report.errors.push(`fate revision: ${err instanceof Error ? err.message : String(err)}`);
|
|
345
|
+
}
|
|
346
|
+
// The lost digest learnings — once, until every digest of the range was
|
|
347
|
+
// read (a file that could not be read keeps it owed).
|
|
348
|
+
const digestKey = `digest-backfill:${this.cfg.lessons_digest_backfill_from}..${this.cfg.lessons_digest_backfill_to}`;
|
|
349
|
+
if (this.mark(digestKey) === null) {
|
|
350
|
+
try {
|
|
351
|
+
const d = mineDigestBackfill({
|
|
352
|
+
dir: join(this.deps.root, "digest"),
|
|
353
|
+
from: this.cfg.lessons_digest_backfill_from,
|
|
354
|
+
to: this.cfg.lessons_digest_backfill_to,
|
|
355
|
+
});
|
|
356
|
+
const added = this.insert(d.drafts)["digest-backfill"] ?? 0;
|
|
357
|
+
report.digest = { files: d.files, absent: d.absent, unreadable: d.unreadable, added };
|
|
358
|
+
report.added_by_source["digest-backfill"] = added;
|
|
359
|
+
report.seen["digest-backfill"] = d.drafts.length;
|
|
360
|
+
if (d.unreadable === 0)
|
|
361
|
+
this.setMark(digestKey, JSON.stringify(report.digest));
|
|
362
|
+
}
|
|
363
|
+
catch (err) {
|
|
364
|
+
report.errors.push(`digest backfill: ${err instanceof Error ? err.message : String(err)}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
report.added = Object.values(report.added_by_source).reduce((n, v) => n + (v ?? 0), 0);
|
|
368
|
+
this.store.logEvent("lessons_mined", null, report);
|
|
369
|
+
return report;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* An undecided `[feedback]` reply, tagged comment or deleted bot comment
|
|
373
|
+
* takes its class, lens and anchor from the outcome capture's link of the
|
|
374
|
+
* bot comment it answered — a link the reconcile sweep or the case backfill
|
|
375
|
+
* may make only after the candidate was mined, and `INSERT OR IGNORE` never
|
|
376
|
+
* revisits a row, so it would stay `feedback.general` with no lens for good.
|
|
377
|
+
* Every mine re-derives them from today's drafts, as `reviseFates` does for
|
|
378
|
+
* fates. Decided candidates are history. A ref two routes both drafted
|
|
379
|
+
* takes its FIRST draft, as the insert does: the ledger's before the
|
|
380
|
+
* tagged comment's.
|
|
381
|
+
*/
|
|
382
|
+
relink(drafts) {
|
|
383
|
+
const stmt = this.store.db.prepare(`UPDATE lesson_candidates SET class = ?, lens_ids = ?, round_no = ?, finding_key = ?, path = ?,
|
|
384
|
+
line = ?, summary = ?, evidence = ?, updated_at = ?
|
|
385
|
+
WHERE ref = ? AND status = 'open' AND source IN ('feedback', 'tagged-comment')
|
|
386
|
+
AND (class IS NOT ? OR lens_ids IS NOT ? OR round_no IS NOT ? OR finding_key IS NOT ?
|
|
387
|
+
OR path IS NOT ? OR line IS NOT ? OR summary IS NOT ?)`);
|
|
388
|
+
const at = this.ts();
|
|
389
|
+
let n = 0;
|
|
390
|
+
const seen = new Set();
|
|
391
|
+
this.store.db.transaction(() => {
|
|
392
|
+
for (const d of drafts) {
|
|
393
|
+
if (d.source !== "feedback" && d.source !== "tagged-comment")
|
|
394
|
+
continue;
|
|
395
|
+
if (seen.has(d.ref))
|
|
396
|
+
continue;
|
|
397
|
+
seen.add(d.ref);
|
|
398
|
+
const lens = JSON.stringify(d.lens_ids);
|
|
399
|
+
n += stmt.run(d.class, lens, d.round_no, d.finding_key, d.path, d.line, d.summary, JSON.stringify(d.evidence), at, d.ref, d.class, lens, d.round_no, d.finding_key, d.path, d.line, d.summary).changes;
|
|
400
|
+
}
|
|
401
|
+
})();
|
|
402
|
+
return n;
|
|
403
|
+
}
|
|
404
|
+
/** The oldest event a mine reads: `lessons_mine_days` before `now`. */
|
|
405
|
+
mineSince(now) {
|
|
406
|
+
return new Date(now.getTime() - this.cfg.lessons_mine_days * DAY_MS).toISOString();
|
|
407
|
+
}
|
|
408
|
+
/** The start of the recurrence window a cluster counts over. */
|
|
409
|
+
recurrenceSince() {
|
|
410
|
+
return new Date(this.now().getTime() - this.cfg.lessons_recurrence_days * DAY_MS).toISOString();
|
|
411
|
+
}
|
|
412
|
+
/** What post-merge recall reads — the same for the day's mine and the
|
|
413
|
+
* ticks between mines, which differ only in their budgets. */
|
|
414
|
+
recallScope(now, git) {
|
|
415
|
+
return {
|
|
416
|
+
sinceIso: this.mineSince(now),
|
|
417
|
+
now,
|
|
418
|
+
windowDays: this.cfg.lessons_recall_window_days,
|
|
419
|
+
baseBranch: this.deps.baseBranch,
|
|
420
|
+
git,
|
|
421
|
+
log: this.log,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Post-merge recall between mines (`RECALL_SCAN_LIMITS.prsPerTick` PRs and
|
|
426
|
+
* `budgetMs` a tick): the day's mine alone reads too few merged PRs to keep
|
|
427
|
+
* up with the merge rate or drain a backlog. Git only, read-only; what it
|
|
428
|
+
* finds is inserted at once and offered by the next packet. Never throws.
|
|
429
|
+
*/
|
|
430
|
+
async recallStep() {
|
|
431
|
+
const git = this.deps.git;
|
|
432
|
+
if (!git)
|
|
433
|
+
return;
|
|
434
|
+
let added = 0;
|
|
435
|
+
try {
|
|
436
|
+
const r = await minePostMerge(this.store, {
|
|
437
|
+
...this.recallScope(this.now(), git),
|
|
438
|
+
maxPrs: RECALL_SCAN_LIMITS.prsPerTick,
|
|
439
|
+
budgetMs: RECALL_SCAN_LIMITS.budgetMs,
|
|
440
|
+
persist: (d) => {
|
|
441
|
+
added += this.insert(d).recall ?? 0;
|
|
442
|
+
},
|
|
443
|
+
});
|
|
444
|
+
if (r.scanned > 0 || added > 0)
|
|
445
|
+
this.log(`learner: post-merge recall read ${r.scanned} merged PR(s), ${added} new candidate(s)${r.unknown ? `, ${r.unknown} unknown` : ""}`);
|
|
446
|
+
}
|
|
447
|
+
catch (err) {
|
|
448
|
+
this.log("learner: post-merge recall failed", err);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Re-read the undecided fate candidates against the outcome capture's
|
|
453
|
+
* outcomes as they stand (`reviewFateCandidates`): the capture re-decides a
|
|
454
|
+
* fate on every pass and may join a posting to an earlier chain later, so a
|
|
455
|
+
* candidate minted once is never trusted as written. One whose chain still
|
|
456
|
+
* holds a candidate fate is revised in place (its kind, polarity and summary
|
|
457
|
+
* follow the fate); one that no longer does is withdrawn — recorded on the
|
|
458
|
+
* row, in an event and in the mine's report, never deleted; and a withdrawn
|
|
459
|
+
* one whose chain holds a candidate fate again is reinstated (its ref is
|
|
460
|
+
* the same, so the mine's insert could not bring it back). Queued and
|
|
461
|
+
* offered candidates alike; a
|
|
462
|
+
* decided one is history and is left as it is.
|
|
463
|
+
*/
|
|
464
|
+
reviseFates(sinceIso) {
|
|
465
|
+
const db = this.store.db;
|
|
466
|
+
const hasOutcomes = tableExists(this.store, "finding_outcomes");
|
|
467
|
+
const freshOutcome = hasOutcomes
|
|
468
|
+
? "OR pr IN (SELECT pr FROM finding_outcomes WHERE COALESCE(decided_at,fate_changed_at)>=?)"
|
|
469
|
+
: "";
|
|
470
|
+
const rows = this.candidates(`source = 'fate' AND (status='open' OR (status='withdrawn' AND (decided_at>=? ${freshOutcome}))) ORDER BY id`, sinceIso, ...(hasOutcomes ? [sinceIso] : []));
|
|
471
|
+
const out = { revised: 0, withdrawn: 0, reinstated: 0 };
|
|
472
|
+
if (rows.length === 0)
|
|
473
|
+
return out;
|
|
474
|
+
const reviews = reviewFateCandidates(this.store, rows);
|
|
475
|
+
const at = this.ts();
|
|
476
|
+
const day = this.today();
|
|
477
|
+
const changes = [];
|
|
478
|
+
const refresh = (c, d) => [
|
|
479
|
+
d.kind,
|
|
480
|
+
d.polarity,
|
|
481
|
+
d.class,
|
|
482
|
+
JSON.stringify(d.lens_ids),
|
|
483
|
+
d.summary,
|
|
484
|
+
d.quote,
|
|
485
|
+
JSON.stringify(d.evidence),
|
|
486
|
+
d.path,
|
|
487
|
+
d.line,
|
|
488
|
+
// The event's time moves only with its fate: a recurrence window
|
|
489
|
+
// counts the human outcome, not the capture's re-reading of it.
|
|
490
|
+
d.kind !== c.kind ? d.occurred_at : c.occurred_at,
|
|
491
|
+
];
|
|
492
|
+
db.transaction(() => {
|
|
493
|
+
for (const c of rows) {
|
|
494
|
+
const r = reviews.get(c.id);
|
|
495
|
+
if (!r)
|
|
496
|
+
continue;
|
|
497
|
+
if (r.kind === "gone") {
|
|
498
|
+
if (c.status !== "open")
|
|
499
|
+
continue;
|
|
500
|
+
db.prepare(`UPDATE lesson_candidates SET status = 'withdrawn', decided_at = ?, decided_day = ?, reason = ?, updated_at = ?
|
|
501
|
+
WHERE id = ? AND status = 'open'`).run(at, day, `withdrawn: ${r.why}`, at, c.id);
|
|
502
|
+
out.withdrawn += 1;
|
|
503
|
+
changes.push({ id: c.id, change: "withdrawn", why: r.why });
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
const d = r.draft;
|
|
507
|
+
if (c.status === "withdrawn") {
|
|
508
|
+
db.prepare(`UPDATE lesson_candidates SET status = 'open', decided_at = NULL, decided_day = NULL, reason = ?,
|
|
509
|
+
reopened_day = CASE WHEN offered_day IS NULL THEN NULL ELSE ? END,
|
|
510
|
+
kind = ?, polarity = ?, class = ?, lens_ids = ?, summary = ?, quote = ?, evidence = ?,
|
|
511
|
+
path = ?, line = ?, occurred_at = ?, updated_at = ?
|
|
512
|
+
WHERE id = ? AND status = 'withdrawn'`).run(`reinstated: its fate is ${d.kind} again`, day, ...refresh(c, d), at, c.id);
|
|
513
|
+
out.reinstated += 1;
|
|
514
|
+
changes.push({ id: c.id, change: "reinstated" });
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
if (d.kind === c.kind &&
|
|
518
|
+
d.polarity === c.polarity &&
|
|
519
|
+
d.class === c.class &&
|
|
520
|
+
JSON.stringify(d.lens_ids) === c.lens_ids &&
|
|
521
|
+
d.summary === c.summary &&
|
|
522
|
+
d.quote === c.quote &&
|
|
523
|
+
d.path === c.path &&
|
|
524
|
+
d.line === c.line)
|
|
525
|
+
continue;
|
|
526
|
+
db.prepare(`UPDATE lesson_candidates SET kind = ?, polarity = ?, class = ?, lens_ids = ?, summary = ?, quote = ?,
|
|
527
|
+
evidence = ?, path = ?, line = ?, occurred_at = ?, updated_at = ?
|
|
528
|
+
WHERE id = ? AND status = 'open'`).run(...refresh(c, d), at, c.id);
|
|
529
|
+
out.revised += 1;
|
|
530
|
+
changes.push({ id: c.id, change: d.kind !== c.kind ? `${c.kind} → ${d.kind}` : "revised" });
|
|
531
|
+
}
|
|
532
|
+
})();
|
|
533
|
+
if (changes.length > 0)
|
|
534
|
+
this.store.logEvent("lesson_candidates_revised", null, { changes });
|
|
535
|
+
return out;
|
|
536
|
+
}
|
|
537
|
+
// ---- 2. the packet ---------------------------------------------------------
|
|
538
|
+
candidates(where, ...args) {
|
|
539
|
+
return this.store.db
|
|
540
|
+
.prepare(`SELECT * FROM lesson_candidates WHERE ${where}`)
|
|
541
|
+
.all(...args);
|
|
542
|
+
}
|
|
543
|
+
/** Read the lessons in force (experiences/), bounded; null when memory is
|
|
544
|
+
* off, unhealthy or does not answer in time. Remembers a complete read. */
|
|
545
|
+
async readLessons() {
|
|
546
|
+
if (!this.deps.lessons)
|
|
547
|
+
return null;
|
|
548
|
+
if (this.deps.healthy && !this.deps.healthy())
|
|
549
|
+
return null;
|
|
550
|
+
const res = await withTimeout(this.deps.lessons.sweep(), LESSON_READ_BUDGET_MS, (err) => this.log("learner: the lessons read failed", err));
|
|
551
|
+
if (res === "timeout")
|
|
552
|
+
return null;
|
|
553
|
+
const lessons = [];
|
|
554
|
+
for (const e of res.entries) {
|
|
555
|
+
if (areaOfId(e.id) !== EXPERIENCES_AREA)
|
|
556
|
+
continue;
|
|
557
|
+
const p = parseLesson(e.text);
|
|
558
|
+
if (p)
|
|
559
|
+
lessons.push({ ...p, id: e.id });
|
|
560
|
+
}
|
|
561
|
+
// Newest first (ids carry their stamp), so a coverage list leads with the
|
|
562
|
+
// freshest lesson.
|
|
563
|
+
lessons.sort((a, b) => (a.id < b.id ? 1 : a.id > b.id ? -1 : 0));
|
|
564
|
+
const complete = res.unread.length === 0;
|
|
565
|
+
if (complete)
|
|
566
|
+
this.lessonsRead = { lessons, complete, at: this.ts() };
|
|
567
|
+
return { lessons, complete };
|
|
568
|
+
}
|
|
569
|
+
/** Per class, the candidates whose event fell in the window, whatever
|
|
570
|
+
* became of them — offered, queued, decided or expired — except the
|
|
571
|
+
* withdrawn (minted from an outcome that has since changed). */
|
|
572
|
+
recurrence(sinceIso) {
|
|
573
|
+
return new Map(this.store.db
|
|
574
|
+
.prepare("SELECT class, COUNT(*) AS n FROM lesson_candidates WHERE occurred_at >= ? AND status <> 'withdrawn' GROUP BY class")
|
|
575
|
+
.all(sinceIso).map((r) => [r.class, r.n]));
|
|
576
|
+
}
|
|
577
|
+
/** Per class, the posted findings humans fixed and left open in the
|
|
578
|
+
* window — the counterweight a cluster shows. */
|
|
579
|
+
counterweights(sinceIso) {
|
|
580
|
+
const out = new Map();
|
|
581
|
+
if (!tableExists(this.store, "finding_outcomes"))
|
|
582
|
+
return out;
|
|
583
|
+
const prs = this.store.db
|
|
584
|
+
.prepare("SELECT DISTINCT pr FROM finding_outcomes WHERE fate IN ('fixed','open_at_close') AND COALESCE(decided_at,fate_changed_at)>=?")
|
|
585
|
+
.all(sinceIso);
|
|
586
|
+
const finding = this.store.db.prepare("SELECT lens_ids,lens,kind FROM round_findings WHERE pr=? AND round_no=? AND finding_key=?");
|
|
587
|
+
for (const { pr } of prs)
|
|
588
|
+
for (const { root, end } of chainRoots(outcomeRows(this.store, pr))) {
|
|
589
|
+
if (!["fixed", "open_at_close"].includes(end.fate) ||
|
|
590
|
+
(end.decided_at ?? end.fate_changed_at) < sinceIso)
|
|
591
|
+
continue;
|
|
592
|
+
const f = finding.get(pr, root.round_no, root.finding_key);
|
|
593
|
+
if (!f)
|
|
594
|
+
continue;
|
|
595
|
+
const cls = findingClass(lensIdsOf(f.lens_ids, f.lens), f.kind);
|
|
596
|
+
const count = out.get(cls) ?? { fixed: 0, ignored: 0 };
|
|
597
|
+
if (end.fate === "fixed")
|
|
598
|
+
count.fixed++;
|
|
599
|
+
else
|
|
600
|
+
count.ignored++;
|
|
601
|
+
out.set(cls, count);
|
|
602
|
+
}
|
|
603
|
+
return out;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Build and write the packet for EOD day `day`: expire, offer, carry,
|
|
607
|
+
* cluster. Idempotent per day — a second build (a retried fire) offers no
|
|
608
|
+
* more than the day's cap and expires nothing twice.
|
|
609
|
+
*/
|
|
610
|
+
async buildPacket(day) {
|
|
611
|
+
const at = this.ts();
|
|
612
|
+
const db = this.store.db;
|
|
613
|
+
// Expire: offered, undecided, past the window — counted from its first
|
|
614
|
+
// offer, or from the day a refused write or an unfound adoption re-opened
|
|
615
|
+
// it (that candidate was promised the next packet, and gets a full window).
|
|
616
|
+
const expired = [];
|
|
617
|
+
db.transaction(() => {
|
|
618
|
+
for (const c of this.candidates("status = 'open' AND offered_day IS NOT NULL")) {
|
|
619
|
+
if (dayDiff(clockDay(c), day) < this.cfg.lessons_expiry_ops_days)
|
|
620
|
+
continue;
|
|
621
|
+
db.prepare(`UPDATE lesson_candidates SET status = 'expired', decided_at = ?, decided_day = ?, reason = ?, updated_at = ?
|
|
622
|
+
WHERE id = ? AND status = 'open'`).run(at, day, c.reopened_day
|
|
623
|
+
? `undecided ${this.cfg.lessons_expiry_ops_days} ops days after it was re-opened (${c.reopened_day}; first offered ${c.offered_day})`
|
|
624
|
+
: `undecided ${this.cfg.lessons_expiry_ops_days} ops days after it was first offered (${c.offered_day})`, at, c.id);
|
|
625
|
+
expired.push({
|
|
626
|
+
id: c.id,
|
|
627
|
+
label: candidateLabel(c.id),
|
|
628
|
+
class: c.class,
|
|
629
|
+
summary: c.summary,
|
|
630
|
+
offered_day: c.offered_day,
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
if (expired.length > 0)
|
|
634
|
+
this.store.logEvent("lesson_candidates_expired", null, {
|
|
635
|
+
day,
|
|
636
|
+
ids: expired.map((e) => e.id),
|
|
637
|
+
after_ops_days: this.cfg.lessons_expiry_ops_days,
|
|
638
|
+
});
|
|
639
|
+
})();
|
|
640
|
+
// Candidates expired by an earlier build of the same day stay listed —
|
|
641
|
+
// the ones its record lists, and the ones its expiry committed before
|
|
642
|
+
// that build was cut short (the rows say so: expired on this day).
|
|
643
|
+
const prior = this.curation(day);
|
|
644
|
+
const priorExpired = prior ? jsonColumn(prior.expired, []) : [];
|
|
645
|
+
const expiredOnDay = this.candidates("status = 'expired' AND decided_day = ? ORDER BY id", day);
|
|
646
|
+
for (const id of [...priorExpired, ...expiredOnDay.map((c) => c.id)]) {
|
|
647
|
+
if (expired.some((e) => e.id === id))
|
|
648
|
+
continue;
|
|
649
|
+
const c = this.candidates("id = ?", id)[0];
|
|
650
|
+
if (c)
|
|
651
|
+
expired.push({
|
|
652
|
+
id: c.id,
|
|
653
|
+
label: candidateLabel(c.id),
|
|
654
|
+
class: c.class,
|
|
655
|
+
summary: c.summary,
|
|
656
|
+
offered_day: c.offered_day ?? day,
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
// Offer: queued candidates, look-for first, up to the day's cap — the
|
|
660
|
+
// reviewer's own recheck reversals after every other source, so its own
|
|
661
|
+
// conclusions never crowd a person's outcome out of the packet.
|
|
662
|
+
const offeredToday = db.prepare("SELECT COUNT(*) AS n FROM lesson_candidates WHERE offered_day = ?").get(day).n;
|
|
663
|
+
const slots = Math.max(0, this.cfg.lessons_packet_new_max - offeredToday);
|
|
664
|
+
if (slots > 0) {
|
|
665
|
+
const fresh = db
|
|
666
|
+
.prepare(`SELECT id FROM lesson_candidates WHERE status = 'open' AND offered_day IS NULL
|
|
667
|
+
ORDER BY CASE source WHEN 'recheck' THEN 1 ELSE 0 END,
|
|
668
|
+
CASE polarity WHEN 'look-for' THEN 0 ELSE 1 END,
|
|
669
|
+
CASE source WHEN 'recall' THEN 0 WHEN 'fate' THEN 1 WHEN 'feedback' THEN 2
|
|
670
|
+
WHEN 'tagged-comment' THEN 2 ELSE 3 END,
|
|
671
|
+
occurred_at DESC, id
|
|
672
|
+
LIMIT ?`)
|
|
673
|
+
.all(slots);
|
|
674
|
+
const offer = db.prepare("UPDATE lesson_candidates SET offered_day = ?, updated_at = ? WHERE id = ? AND offered_day IS NULL");
|
|
675
|
+
db.transaction(() => {
|
|
676
|
+
for (const f of fresh)
|
|
677
|
+
offer.run(day, at, f.id);
|
|
678
|
+
})();
|
|
679
|
+
}
|
|
680
|
+
// Carry: every offered candidate still undecided rides today's packet.
|
|
681
|
+
db.prepare(`UPDATE lesson_candidates SET offers = offers + 1, last_offered_day = ?, updated_at = ?
|
|
682
|
+
WHERE status = 'open' AND offered_day IS NOT NULL AND (last_offered_day IS NULL OR last_offered_day <> ?)`).run(day, at, day);
|
|
683
|
+
const offered = this.candidates("status = 'open' AND offered_day IS NOT NULL ORDER BY class, occurred_at DESC, id");
|
|
684
|
+
const queued = db
|
|
685
|
+
.prepare("SELECT COUNT(*) AS n FROM lesson_candidates WHERE status = 'open' AND offered_day IS NULL")
|
|
686
|
+
.get().n;
|
|
687
|
+
// Cluster, with recurrence, the counterweight and coverage.
|
|
688
|
+
const since = this.recurrenceSince();
|
|
689
|
+
const recurrence = this.recurrence(since);
|
|
690
|
+
const weights = this.counterweights(since);
|
|
691
|
+
const read = await this.readLessons();
|
|
692
|
+
const byClass = new Map();
|
|
693
|
+
for (const c of offered)
|
|
694
|
+
byClass.set(c.class, [...(byClass.get(c.class) ?? []), c]);
|
|
695
|
+
const toPacket = (c) => ({
|
|
696
|
+
id: c.id,
|
|
697
|
+
label: candidateLabel(c.id),
|
|
698
|
+
kind: c.kind,
|
|
699
|
+
source: c.source,
|
|
700
|
+
polarity: c.polarity,
|
|
701
|
+
class: c.class,
|
|
702
|
+
lens_ids: jsonColumn(c.lens_ids, []),
|
|
703
|
+
pr: c.pr,
|
|
704
|
+
path: c.path,
|
|
705
|
+
line: c.line,
|
|
706
|
+
summary: c.summary,
|
|
707
|
+
quote: c.quote,
|
|
708
|
+
evidence: jsonColumn(c.evidence, []),
|
|
709
|
+
occurred_at: c.occurred_at,
|
|
710
|
+
offered_day: c.offered_day,
|
|
711
|
+
expires_after: addDays(clockDay(c), this.cfg.lessons_expiry_ops_days - 1),
|
|
712
|
+
new: c.offered_day === day,
|
|
713
|
+
});
|
|
714
|
+
// A partial read proves nothing absent: the lessons it found do cover the
|
|
715
|
+
// class, but "none found" is unknown, and a balance over part of memory
|
|
716
|
+
// is no balance at all.
|
|
717
|
+
const coverage = (cls, lensIds) => {
|
|
718
|
+
if (!read)
|
|
719
|
+
return null;
|
|
720
|
+
const found = coveringLessons(read.lessons, cls, lensIds);
|
|
721
|
+
return read.complete || found.length > 0 ? found : null;
|
|
722
|
+
};
|
|
723
|
+
const clusters = [...byClass.entries()].map(([cls, rows]) => {
|
|
724
|
+
const lensIds = [...new Set(rows.flatMap((r) => jsonColumn(r.lens_ids, [])))];
|
|
725
|
+
const w = weights.get(cls) ?? { fixed: 0, ignored: 0 };
|
|
726
|
+
return {
|
|
727
|
+
class: cls,
|
|
728
|
+
polarity: majorityPolarity(rows),
|
|
729
|
+
recurrence: recurrence.get(cls) ?? 0,
|
|
730
|
+
fixed: w.fixed,
|
|
731
|
+
ignored: w.ignored,
|
|
732
|
+
covering: coverage(cls, lensIds),
|
|
733
|
+
candidates: rows.map(toPacket),
|
|
734
|
+
};
|
|
735
|
+
});
|
|
736
|
+
// The reviewer's own recheck reversals after every other cluster —
|
|
737
|
+
// the same demotion as the first offer, because a busy reversal class
|
|
738
|
+
// would otherwise lead the packet on recurrence alone; then misses first,
|
|
739
|
+
// then the busiest classes.
|
|
740
|
+
const reviewerOnly = (c) => c.candidates.every((x) => x.source === "recheck");
|
|
741
|
+
clusters.sort((a, b) => Number(reviewerOnly(a)) - Number(reviewerOnly(b)) ||
|
|
742
|
+
Number(b.polarity === "look-for") - Number(a.polarity === "look-for") ||
|
|
743
|
+
b.recurrence - a.recurrence ||
|
|
744
|
+
a.class.localeCompare(b.class));
|
|
745
|
+
const fresh = offered.filter((c) => c.offered_day === day).length;
|
|
746
|
+
const packet = {
|
|
747
|
+
day,
|
|
748
|
+
generated_at: at,
|
|
749
|
+
expiry_ops_days: this.cfg.lessons_expiry_ops_days,
|
|
750
|
+
recurrence_days: this.cfg.lessons_recurrence_days,
|
|
751
|
+
offered: offered.length,
|
|
752
|
+
new: fresh,
|
|
753
|
+
carried: offered.length - fresh,
|
|
754
|
+
queued,
|
|
755
|
+
expired,
|
|
756
|
+
balance: read?.complete ? lessonBalance(read.lessons) : null,
|
|
757
|
+
lessons_read: !this.deps.lessons
|
|
758
|
+
? "off"
|
|
759
|
+
: read === null
|
|
760
|
+
? "unreadable"
|
|
761
|
+
: read.complete
|
|
762
|
+
? "ok"
|
|
763
|
+
: "partial",
|
|
764
|
+
clusters,
|
|
765
|
+
};
|
|
766
|
+
const dir = join(this.deps.root, packetRelDir(day));
|
|
767
|
+
mkdirSync(dir, { recursive: true });
|
|
768
|
+
writeAtomic(join(dir, "outcomes.json"), `${JSON.stringify(packet, null, 2)}\n`);
|
|
769
|
+
writeAtomic(join(this.deps.root, packetMarkdownRel(day)), renderPacketMarkdown(packet));
|
|
770
|
+
db.prepare(`INSERT INTO eod_curations (day, packet_at, offered, new_today, expired, updated_at)
|
|
771
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
772
|
+
ON CONFLICT(day) DO UPDATE SET packet_at = excluded.packet_at, offered = excluded.offered,
|
|
773
|
+
new_today = excluded.new_today, expired = excluded.expired, updated_at = excluded.updated_at`).run(day, at, JSON.stringify(offered.map((c) => c.id)), JSON.stringify(offered.filter((c) => c.offered_day === day).map((c) => c.id)), JSON.stringify(expired.map((e) => e.id)), at);
|
|
774
|
+
this.store.logEvent("eod_packet_written", null, {
|
|
775
|
+
day,
|
|
776
|
+
offered: packet.offered,
|
|
777
|
+
new: packet.new,
|
|
778
|
+
carried: packet.carried,
|
|
779
|
+
queued,
|
|
780
|
+
expired: expired.length,
|
|
781
|
+
lessons_read: packet.lessons_read,
|
|
782
|
+
});
|
|
783
|
+
return packet;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* The EOD sweep's day context (wire.ts → `dayContext`): mine first when the
|
|
787
|
+
* day's mine has not run (bounded — a slow git read never holds the sweep),
|
|
788
|
+
* then build the packet. `lines` is the pointer the digest carries;
|
|
789
|
+
* `curation` the instructions the prompt renders after the seed.
|
|
790
|
+
*/
|
|
791
|
+
async prepareEod(day) {
|
|
792
|
+
if (this.mark(`mined:${day}`) === null) {
|
|
793
|
+
const r = await withTimeout(this.mine(), PREPARE_MINE_BUDGET_MS, (err) => this.log("learner: the EOD mine failed", err));
|
|
794
|
+
if (r !== "timeout")
|
|
795
|
+
this.setMark(`mined:${day}`, this.ts());
|
|
796
|
+
}
|
|
797
|
+
const packet = await this.buildPacket(day);
|
|
798
|
+
return { lines: packetPointer(packet), curation: renderCurationSection(packet), packet };
|
|
799
|
+
}
|
|
800
|
+
/** The sweep for `day` reached the overseer (`EodTimerDeps.onFire`): the
|
|
801
|
+
* receipt is owed from now. */
|
|
802
|
+
eodFired(day) {
|
|
803
|
+
const at = this.ts();
|
|
804
|
+
this.store.db
|
|
805
|
+
.prepare(`INSERT INTO eod_curations (day, fired_at, updated_at) VALUES (?, ?, ?)
|
|
806
|
+
ON CONFLICT(day) DO UPDATE SET fired_at = excluded.fired_at, updated_at = excluded.updated_at`)
|
|
807
|
+
.run(day, at, at);
|
|
808
|
+
}
|
|
809
|
+
curation(day) {
|
|
810
|
+
return this.store.db.prepare("SELECT * FROM eod_curations WHERE day = ?").get(day);
|
|
811
|
+
}
|
|
812
|
+
// ---- 3. the receipt -----------------------------------------------------------
|
|
813
|
+
/**
|
|
814
|
+
* Apply a validated `eod-curation-receipt`. All or nothing: a day with no
|
|
815
|
+
* packet, a candidate id the learner never minted, or one that day's packet
|
|
816
|
+
* did not offer, refuses the whole receipt (the curator fixes it and writes
|
|
817
|
+
* it again) — a receipt decides what its packet put in front of the
|
|
818
|
+
* curator, never a queued candidate nobody showed it. `adopted` waits for
|
|
819
|
+
* memory to show the lesson (`adopting`);
|
|
820
|
+
* `declined` is final; `refused` keeps the candidate open and wakes
|
|
821
|
+
* `eod_lessons_not_persisted` at once. A candidate already settled since
|
|
822
|
+
* the packet — adopted (memory showed its lesson), withdrawn or expired —
|
|
823
|
+
* keeps its status whatever the receipt says: memory's evidence and the
|
|
824
|
+
* learner's own record outrank a later claim (only `refused` re-opens an
|
|
825
|
+
* expired one, with a fresh clock).
|
|
826
|
+
*/
|
|
827
|
+
applyReceipt(receipt) {
|
|
828
|
+
const row = this.curation(receipt.day);
|
|
829
|
+
if (!row?.packet_at)
|
|
830
|
+
return { ok: false, reason: `no outcomes packet was written for ${receipt.day}` };
|
|
831
|
+
const ids = receipt.decisions.flatMap((d) => d.candidates);
|
|
832
|
+
const offered = new Set(jsonColumn(row.offered, []));
|
|
833
|
+
const known = new Set(ids.length === 0
|
|
834
|
+
? []
|
|
835
|
+
: this.store.db
|
|
836
|
+
.prepare(`SELECT id FROM lesson_candidates WHERE id IN (${ids.map(() => "?").join(",")})`)
|
|
837
|
+
.all(...ids).map((r) => r.id));
|
|
838
|
+
const unknown = ids.filter((id) => !known.has(id));
|
|
839
|
+
if (unknown.length > 0)
|
|
840
|
+
return {
|
|
841
|
+
ok: false,
|
|
842
|
+
reason: `unknown candidate id(s): ${unknown.map(candidateLabel).join(", ")} — nothing was recorded; send the receipt again without them`,
|
|
843
|
+
};
|
|
844
|
+
const notOffered = ids.filter((id) => !offered.has(id));
|
|
845
|
+
if (notOffered.length > 0)
|
|
846
|
+
return {
|
|
847
|
+
ok: false,
|
|
848
|
+
reason: `candidate id(s) the ${receipt.day} packet did not offer: ${notOffered.map(candidateLabel).join(", ")} — nothing was recorded; decide only what that packet offered`,
|
|
849
|
+
};
|
|
850
|
+
const at = this.ts();
|
|
851
|
+
const today = this.today();
|
|
852
|
+
const db = this.store.db;
|
|
853
|
+
const counts = { adopted: 0, declined: 0, refused: 0 };
|
|
854
|
+
const refused = [];
|
|
855
|
+
db.transaction(() => {
|
|
856
|
+
for (const d of receipt.decisions) {
|
|
857
|
+
for (const id of d.candidates) {
|
|
858
|
+
if (d.decision === "adopted") {
|
|
859
|
+
// An adoption memory already showed stands; an undecided one
|
|
860
|
+
// waits for the lesson to be found; a settled one keeps its
|
|
861
|
+
// decision and the reason for it — only the receipt is recorded.
|
|
862
|
+
db.prepare(`UPDATE lesson_candidates SET status = CASE WHEN status IN ('open', 'adopting') THEN 'adopting' ELSE status END,
|
|
863
|
+
claimed_lesson = CASE WHEN status IN ('open', 'adopting') THEN ? ELSE claimed_lesson END,
|
|
864
|
+
reason = CASE WHEN status IN ('open', 'adopting') THEN COALESCE(?, reason) ELSE reason END,
|
|
865
|
+
receipt_day = ?, receipt_at = ?, updated_at = ?
|
|
866
|
+
WHERE id = ?`).run(d.lesson ?? null, d.reason ?? null, receipt.day, at, at, id);
|
|
867
|
+
counts.adopted += 1;
|
|
868
|
+
}
|
|
869
|
+
else if (d.decision === "declined") {
|
|
870
|
+
// Only an undecided candidate is declined: a declination never
|
|
871
|
+
// overwrites a memory-verified adoption, a withdrawal or an expiry.
|
|
872
|
+
db.prepare(`UPDATE lesson_candidates SET status = 'declined', decided_at = ?, decided_day = ?, reason = ?,
|
|
873
|
+
receipt_day = ?, receipt_at = ?, updated_at = ? WHERE id = ? AND status IN ('open', 'adopting')`).run(at, receipt.day, d.reason ?? null, receipt.day, at, at, id);
|
|
874
|
+
db.prepare("UPDATE lesson_candidates SET receipt_day = ?, receipt_at = ?, updated_at = ? WHERE id = ? AND status NOT IN ('open', 'adopting')").run(receipt.day, at, at, id);
|
|
875
|
+
counts.declined += 1;
|
|
876
|
+
}
|
|
877
|
+
else {
|
|
878
|
+
// A refused write puts the candidate back in the packet with a
|
|
879
|
+
// fresh expiry clock (it was promised the next packet); one
|
|
880
|
+
// already adopted, declined or withdrawn stays as it is.
|
|
881
|
+
const before = db.prepare("SELECT status FROM lesson_candidates WHERE id = ?").get(id).status;
|
|
882
|
+
const keep = SETTLED_STATUSES.includes(before) && before !== "expired";
|
|
883
|
+
if (keep)
|
|
884
|
+
db.prepare("UPDATE lesson_candidates SET receipt_day = ?, receipt_at = ?, updated_at = ? WHERE id = ?").run(receipt.day, at, at, id);
|
|
885
|
+
else
|
|
886
|
+
db.prepare(`UPDATE lesson_candidates SET status = 'open', reopened_day = ?, decided_at = NULL, decided_day = NULL,
|
|
887
|
+
reason = ?, receipt_day = ?, receipt_at = ?, updated_at = ? WHERE id = ?`).run(today, `write refused: ${d.reason ?? ""}`, receipt.day, at, at, id);
|
|
888
|
+
counts.refused += 1;
|
|
889
|
+
if (!keep)
|
|
890
|
+
refused.push({
|
|
891
|
+
id,
|
|
892
|
+
why: `the curator reported the write refused: ${d.reason ?? "no reason"}`,
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
db.prepare("UPDATE eod_curations SET receipt_at = ?, receipt = ?, updated_at = ? WHERE day = ?").run(at, JSON.stringify({ ...counts, decisions: receipt.decisions.length }), at, receipt.day);
|
|
898
|
+
this.store.logEvent("eod_curation_receipt", null, { day: receipt.day, ...counts });
|
|
899
|
+
if (refused.length > 0)
|
|
900
|
+
this.notPersisted(receipt.day, refused);
|
|
901
|
+
})();
|
|
902
|
+
return { ok: true, day: receipt.day, ...counts };
|
|
903
|
+
}
|
|
904
|
+
/** Record adoptions memory does not hold / writes refused, and wake when
|
|
905
|
+
* the list names something no earlier wake named. */
|
|
906
|
+
notPersisted(day, items) {
|
|
907
|
+
this.store.db.transaction(() => {
|
|
908
|
+
const row = this.curation(day);
|
|
909
|
+
const prev = jsonColumn(row?.not_persisted, []);
|
|
910
|
+
const merged = [...prev];
|
|
911
|
+
for (const i of items)
|
|
912
|
+
if (!merged.some((m) => m.id === i.id && m.why === i.why))
|
|
913
|
+
merged.push(i);
|
|
914
|
+
const woken = new Set(jsonColumn(row?.not_persisted_woken, []));
|
|
915
|
+
const key = (m) => `${m.id}:${m.why}`;
|
|
916
|
+
const fresh = merged.filter((m) => !woken.has(key(m)));
|
|
917
|
+
const at = this.ts();
|
|
918
|
+
// The incident starts when the day's list goes from empty to non-empty.
|
|
919
|
+
const since = prev.length > 0 && row?.not_persisted_since ? row.not_persisted_since : at;
|
|
920
|
+
this.store.db
|
|
921
|
+
.prepare(`INSERT INTO eod_curations (day, not_persisted, not_persisted_since, not_persisted_woken, updated_at)
|
|
922
|
+
VALUES (?, ?, ?, ?, ?)
|
|
923
|
+
ON CONFLICT(day) DO UPDATE SET not_persisted = excluded.not_persisted,
|
|
924
|
+
not_persisted_since = excluded.not_persisted_since,
|
|
925
|
+
not_persisted_woken = excluded.not_persisted_woken, updated_at = excluded.updated_at`)
|
|
926
|
+
.run(day, JSON.stringify(merged), since, JSON.stringify([...woken, ...fresh.map(key)]), at);
|
|
927
|
+
if (fresh.length === 0)
|
|
928
|
+
return;
|
|
929
|
+
const labels = merged.map((m) => candidateLabel(m.id)).join(", ");
|
|
930
|
+
this.deps.wake?.(LEARNER_WAKE.notPersisted, `EOD ${day}: ${merged.length} lesson(s) not persisted (${labels})`, [
|
|
931
|
+
`EOD LESSONS NOT PERSISTED — the curation of ${day} did not land ${merged.length} lesson(s) in reviewer memory: ${labels}.`,
|
|
932
|
+
...merged.slice(0, 8).map((m) => `- ${candidateLabel(m.id)}: ${m.why.slice(0, 200)}`),
|
|
933
|
+
"The candidates are open again and ride the next outcomes packet. Check memory health (`qcr status`) and the overseer's viking_write answers; a lesson counts only once its typed header cites the candidate (`cand:c<id>`).",
|
|
934
|
+
].join("\n"));
|
|
935
|
+
})();
|
|
936
|
+
}
|
|
937
|
+
// ---- 4. the tick: mine on time, verify, and wake when the receipt is late ----
|
|
938
|
+
/** When today's mine is due: `lessons_mine_lead_min` before the EOD time. */
|
|
939
|
+
mineDueAt() {
|
|
940
|
+
const p = zonedParts(this.now(), this.deps.timeZone);
|
|
941
|
+
const { hour, minute } = parseHHMM(this.deps.eodTime);
|
|
942
|
+
const fire = localWallClockToInstant(p.year, p.month, p.day, hour, minute, this.deps.timeZone);
|
|
943
|
+
return fire.getTime() - this.cfg.lessons_mine_lead_min * 60_000;
|
|
944
|
+
}
|
|
945
|
+
/** One pass: the day's mine when due, the missing-receipt check, and the
|
|
946
|
+
* verification of adoptions against memory. Never throws. */
|
|
947
|
+
async tick() {
|
|
948
|
+
if (this.ticking)
|
|
949
|
+
return;
|
|
950
|
+
this.ticking = true;
|
|
951
|
+
try {
|
|
952
|
+
const day = this.today();
|
|
953
|
+
if (this.now().getTime() >= this.mineDueAt() && this.mark(`mined:${day}`) === null) {
|
|
954
|
+
try {
|
|
955
|
+
const r = await this.mine();
|
|
956
|
+
this.setMark(`mined:${day}`, this.ts());
|
|
957
|
+
this.log(`learner: mined ${r.added} new lesson candidate(s) for ${day}${r.errors.length ? ` (${r.errors.length} source error(s))` : ""}`);
|
|
958
|
+
}
|
|
959
|
+
catch (err) {
|
|
960
|
+
this.log("learner: mine failed", err);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
await this.recallStep();
|
|
964
|
+
try {
|
|
965
|
+
this.checkMissing();
|
|
966
|
+
}
|
|
967
|
+
catch (err) {
|
|
968
|
+
this.log("learner: receipt check failed", err);
|
|
969
|
+
}
|
|
970
|
+
try {
|
|
971
|
+
await this.verify();
|
|
972
|
+
}
|
|
973
|
+
catch (err) {
|
|
974
|
+
this.log("learner: verification failed", err);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
finally {
|
|
978
|
+
this.ticking = false;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
/** Wake `eod_curation_missing` once per day whose delivered sweep offered
|
|
982
|
+
* candidates and drew no receipt within the wait — never for a day a later
|
|
983
|
+
* day's receipt already made good (`unresolved`'s rule: its candidates rode
|
|
984
|
+
* that later packet), and an empty packet, which owes no receipt, never
|
|
985
|
+
* takes one of the checked days' places. */
|
|
986
|
+
checkMissing() {
|
|
987
|
+
const now = this.now().getTime();
|
|
988
|
+
const waitMs = this.cfg.lessons_receipt_wait_min * 60_000;
|
|
989
|
+
const rows = this.store.db
|
|
990
|
+
.prepare(`SELECT * FROM eod_curations WHERE fired_at IS NOT NULL AND receipt_at IS NULL
|
|
991
|
+
AND missing_woken_at IS NULL AND offered <> '[]'
|
|
992
|
+
AND day > COALESCE((SELECT MAX(day) FROM eod_curations WHERE receipt_at IS NOT NULL), '')
|
|
993
|
+
ORDER BY day DESC LIMIT 7`)
|
|
994
|
+
.all();
|
|
995
|
+
for (const r of rows) {
|
|
996
|
+
const offered = jsonColumn(r.offered, []);
|
|
997
|
+
if (offered.length === 0)
|
|
998
|
+
continue;
|
|
999
|
+
if (!missingCuration(r, false, now, waitMs))
|
|
1000
|
+
continue;
|
|
1001
|
+
this.store.db.transaction(() => {
|
|
1002
|
+
const at = this.ts();
|
|
1003
|
+
this.store.db
|
|
1004
|
+
.prepare("UPDATE eod_curations SET missing_woken_at = ?, updated_at = ? WHERE day = ?")
|
|
1005
|
+
.run(at, at, r.day);
|
|
1006
|
+
this.deps.wake?.(LEARNER_WAKE.missing, `EOD ${r.day}: no curation receipt ${this.cfg.lessons_receipt_wait_min} min after the sweep`, [
|
|
1007
|
+
`EOD CURATION MISSING — the EOD sweep for ${r.day} was delivered at ${r.fired_at}, its outcomes packet offered ${offered.length} candidate(s) (\`${packetMarkdownRel(r.day)}\`), and no \`eod-curation-receipt\` arrived within ${this.cfg.lessons_receipt_wait_min} minutes.`,
|
|
1008
|
+
"Nothing says the day's outcomes were curated. The candidates stay open and ride the next packet; undecided, they expire (recorded). Check the overseer session, then curate the packet and write the receipt.",
|
|
1009
|
+
].join("\n"));
|
|
1010
|
+
})();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Check adoptions against memory (only while it reads healthy): a lesson
|
|
1015
|
+
* in `experiences/` whose typed header cites a candidate adopts it — with or
|
|
1016
|
+
* without a receipt. An `adopting` candidate whose receipt is older than the
|
|
1017
|
+
* grace, with memory read in full and no lesson citing it, was not
|
|
1018
|
+
* persisted: it goes back to open and wakes. A partial read proves nothing
|
|
1019
|
+
* absent.
|
|
1020
|
+
*/
|
|
1021
|
+
async verify() {
|
|
1022
|
+
try {
|
|
1023
|
+
await this.verifyAgainstMemory();
|
|
1024
|
+
}
|
|
1025
|
+
finally {
|
|
1026
|
+
// State.db only: a decided candidate leaves the lists even while memory
|
|
1027
|
+
// cannot be read.
|
|
1028
|
+
this.pruneNotPersisted();
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
async verifyAgainstMemory() {
|
|
1032
|
+
const waiting = this.store.db
|
|
1033
|
+
.prepare("SELECT COUNT(*) AS n FROM lesson_candidates WHERE status = 'adopting' OR (status = 'open' AND offered_day IS NOT NULL)")
|
|
1034
|
+
.get().n;
|
|
1035
|
+
// Memory is read every tick while an adoption waits to be checked or an
|
|
1036
|
+
// offered candidate may be adopted by a lesson written without a receipt
|
|
1037
|
+
// (the store's sweep is incremental: an unchanged file is not re-read),
|
|
1038
|
+
// and otherwise every `LESSON_REFRESH_MS`, for the balance metric.
|
|
1039
|
+
const last = this.lessonsRead ? Date.parse(this.lessonsRead.at) : NaN;
|
|
1040
|
+
if (waiting === 0 && Number.isFinite(last) && this.now().getTime() - last < LESSON_REFRESH_MS)
|
|
1041
|
+
return;
|
|
1042
|
+
const pending = this.candidates("status IN ('open', 'adopting')");
|
|
1043
|
+
const read = await this.readLessons();
|
|
1044
|
+
if (!read)
|
|
1045
|
+
return;
|
|
1046
|
+
const cited = new Map();
|
|
1047
|
+
for (const l of read.lessons)
|
|
1048
|
+
for (const id of l.candidates)
|
|
1049
|
+
cited.set(id, [...(cited.get(id) ?? []), l.id]);
|
|
1050
|
+
const at = this.ts();
|
|
1051
|
+
const db = this.store.db;
|
|
1052
|
+
const missingByDay = new Map();
|
|
1053
|
+
// `pending` was read before the memory read awaited: a receipt applied
|
|
1054
|
+
// meanwhile may have settled a candidate or re-dated its adoption, so
|
|
1055
|
+
// every write below holds only against the state it was decided from.
|
|
1056
|
+
db.transaction(() => {
|
|
1057
|
+
for (const c of pending) {
|
|
1058
|
+
const lessons = cited.get(c.id);
|
|
1059
|
+
if (lessons) {
|
|
1060
|
+
db.prepare(`UPDATE lesson_candidates SET status = 'adopted', lesson_ids = ?, decided_at = COALESCE(decided_at, ?),
|
|
1061
|
+
decided_day = COALESCE(decided_day, receipt_day, ?), updated_at = ?
|
|
1062
|
+
WHERE id = ? AND status IN ('open', 'adopting')`).run(JSON.stringify(lessons), at, this.today(), at, c.id);
|
|
1063
|
+
continue;
|
|
1064
|
+
}
|
|
1065
|
+
if (c.status !== "adopting" || !read.complete)
|
|
1066
|
+
continue;
|
|
1067
|
+
const receiptAt = Date.parse(c.receipt_at ?? "");
|
|
1068
|
+
if (!Number.isFinite(receiptAt) || this.now().getTime() - receiptAt < VERIFY_GRACE_MS)
|
|
1069
|
+
continue;
|
|
1070
|
+
// Back to the packet, with a fresh expiry clock: the wake promised the
|
|
1071
|
+
// next packet, and a candidate first offered days ago must not expire
|
|
1072
|
+
// at it.
|
|
1073
|
+
const reopened = db
|
|
1074
|
+
.prepare(`UPDATE lesson_candidates SET status = 'open', reopened_day = ?, reason = ?, updated_at = ?
|
|
1075
|
+
WHERE id = ? AND status = 'adopting' AND receipt_at IS ?`)
|
|
1076
|
+
.run(this.today(), `the receipt of ${c.receipt_day} said adopted, but no lesson in experiences/ cites cand:${candidateLabel(c.id)}`, at, c.id, c.receipt_at);
|
|
1077
|
+
if (reopened.changes === 0)
|
|
1078
|
+
continue;
|
|
1079
|
+
const day = c.receipt_day ?? this.today();
|
|
1080
|
+
missingByDay.set(day, [
|
|
1081
|
+
...(missingByDay.get(day) ?? []),
|
|
1082
|
+
{
|
|
1083
|
+
id: c.id,
|
|
1084
|
+
why: `adopted${c.claimed_lesson ? ` as ${c.claimed_lesson}` : ""}, but no lesson in experiences/ cites cand:${candidateLabel(c.id)}`,
|
|
1085
|
+
},
|
|
1086
|
+
]);
|
|
1087
|
+
}
|
|
1088
|
+
for (const [day, items] of missingByDay)
|
|
1089
|
+
this.notPersisted(day, items);
|
|
1090
|
+
})();
|
|
1091
|
+
}
|
|
1092
|
+
/** A candidate decided since leaves the not-persisted lists it was on: the
|
|
1093
|
+
* lesson landed after all (adopted — a retry, the next day's curation), or
|
|
1094
|
+
* the curator declined it, or it expired (recorded) or was withdrawn. What
|
|
1095
|
+
* stays on a list is still a lesson nobody has made good. */
|
|
1096
|
+
pruneNotPersisted() {
|
|
1097
|
+
const db = this.store.db;
|
|
1098
|
+
const settled = new Set(db
|
|
1099
|
+
.prepare(`SELECT id FROM lesson_candidates WHERE status IN (${SETTLED_SQL})`)
|
|
1100
|
+
.all().map((r) => r.id));
|
|
1101
|
+
const at = this.ts();
|
|
1102
|
+
for (const row of db
|
|
1103
|
+
.prepare("SELECT day, not_persisted FROM eod_curations WHERE not_persisted <> '[]'")
|
|
1104
|
+
.all()) {
|
|
1105
|
+
const list = jsonColumn(row.not_persisted, []);
|
|
1106
|
+
const kept = list.filter((m) => !settled.has(m.id));
|
|
1107
|
+
if (kept.length !== list.length)
|
|
1108
|
+
db.prepare(`UPDATE eod_curations SET not_persisted = ?,
|
|
1109
|
+
not_persisted_since = CASE WHEN ? = 0 THEN NULL ELSE not_persisted_since END, updated_at = ?
|
|
1110
|
+
WHERE day = ?`).run(JSON.stringify(kept), kept.length, at, row.day);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
start(intervalMs = 300_000) {
|
|
1114
|
+
if (this.timer)
|
|
1115
|
+
return;
|
|
1116
|
+
void this.tick();
|
|
1117
|
+
this.timer = setInterval(() => void this.tick(), Math.max(10_000, intervalMs));
|
|
1118
|
+
this.timer.unref?.();
|
|
1119
|
+
}
|
|
1120
|
+
stop() {
|
|
1121
|
+
if (this.timer)
|
|
1122
|
+
clearInterval(this.timer);
|
|
1123
|
+
this.timer = null;
|
|
1124
|
+
}
|
|
1125
|
+
// ---- reading back ------------------------------------------------------------
|
|
1126
|
+
/**
|
|
1127
|
+
* Every curation failure not made good since, newest first, over the last
|
|
1128
|
+
* `UNRESOLVED_SCAN_DAYS` curation days: a `missing` day (the sweep
|
|
1129
|
+
* delivered, candidates offered, no receipt within the wait) until it or a
|
|
1130
|
+
* later day is receipted — its candidates rode the later packet, so that
|
|
1131
|
+
* receipt decided them or carried them on — and a `not_persisted` day until
|
|
1132
|
+
* every candidate on its list is decided (`pruneNotPersisted`). The next
|
|
1133
|
+
* day's packet does not resolve either: a failure stays in front of a
|
|
1134
|
+
* person until something made it good.
|
|
1135
|
+
*/
|
|
1136
|
+
unresolved() {
|
|
1137
|
+
const db = this.store.db;
|
|
1138
|
+
const rows = db
|
|
1139
|
+
.prepare("SELECT * FROM eod_curations ORDER BY day DESC LIMIT ?")
|
|
1140
|
+
.all(UNRESOLVED_SCAN_DAYS);
|
|
1141
|
+
const lists = new Map(rows.map((r) => [r.day, jsonColumn(r.not_persisted, [])]));
|
|
1142
|
+
const ids = [...new Set([...lists.values()].flatMap((l) => l.map((m) => m.id)))];
|
|
1143
|
+
const settled = new Set(ids.length === 0
|
|
1144
|
+
? []
|
|
1145
|
+
: db
|
|
1146
|
+
.prepare(`SELECT id FROM lesson_candidates WHERE status IN (${SETTLED_SQL}) AND id IN (${ids.map(() => "?").join(",")})`)
|
|
1147
|
+
.all(...ids).map((r) => r.id));
|
|
1148
|
+
const now = this.now().getTime();
|
|
1149
|
+
const waitMs = this.cfg.lessons_receipt_wait_min * 60_000;
|
|
1150
|
+
const out = [];
|
|
1151
|
+
let laterReceipt = false;
|
|
1152
|
+
for (const r of rows) {
|
|
1153
|
+
const open = new Set((lists.get(r.day) ?? []).filter((m) => !settled.has(m.id)).map((m) => m.id));
|
|
1154
|
+
if (open.size > 0)
|
|
1155
|
+
out.push({
|
|
1156
|
+
day: r.day,
|
|
1157
|
+
state: "not_persisted",
|
|
1158
|
+
count: open.size,
|
|
1159
|
+
since: r.not_persisted_since ?? r.updated_at,
|
|
1160
|
+
});
|
|
1161
|
+
const offered = jsonColumn(r.offered, []);
|
|
1162
|
+
const fired = Date.parse(r.fired_at ?? "");
|
|
1163
|
+
if (missingCuration(r, laterReceipt, now, waitMs))
|
|
1164
|
+
out.push({
|
|
1165
|
+
day: r.day,
|
|
1166
|
+
state: "missing",
|
|
1167
|
+
count: offered.length,
|
|
1168
|
+
since: r.missing_woken_at ?? new Date(fired + waitMs).toISOString(),
|
|
1169
|
+
});
|
|
1170
|
+
if (r.receipt_at !== null)
|
|
1171
|
+
laterReceipt = true;
|
|
1172
|
+
}
|
|
1173
|
+
return out;
|
|
1174
|
+
}
|
|
1175
|
+
/** The curation for status.json: the newest unresolved failure when there
|
|
1176
|
+
* is one (a missed day stays reported after the next packet is written),
|
|
1177
|
+
* else the latest day's. */
|
|
1178
|
+
status() {
|
|
1179
|
+
const db = this.store.db;
|
|
1180
|
+
const count = (where, ...args) => db.prepare(`SELECT COUNT(*) AS n FROM lesson_candidates WHERE ${where}`).get(...args).n;
|
|
1181
|
+
const open = count("status = 'open' AND offered_day IS NOT NULL");
|
|
1182
|
+
const queued = count("status = 'open' AND offered_day IS NULL");
|
|
1183
|
+
const balance = this.lessonsRead
|
|
1184
|
+
? { ...lessonBalance(this.lessonsRead.lessons), as_of: this.lessonsRead.at }
|
|
1185
|
+
: null;
|
|
1186
|
+
const unresolved = this.unresolved();
|
|
1187
|
+
const head = unresolved[0];
|
|
1188
|
+
const incident = unresolved[unresolved.length - 1] ?? null;
|
|
1189
|
+
const row = head
|
|
1190
|
+
? this.curation(head.day)
|
|
1191
|
+
: db
|
|
1192
|
+
.prepare("SELECT * FROM eod_curations WHERE packet_at IS NOT NULL ORDER BY day DESC LIMIT 1")
|
|
1193
|
+
.get();
|
|
1194
|
+
if (!row)
|
|
1195
|
+
return {
|
|
1196
|
+
day: null,
|
|
1197
|
+
state: "no_packet",
|
|
1198
|
+
offered: 0,
|
|
1199
|
+
adopted: 0,
|
|
1200
|
+
declined: 0,
|
|
1201
|
+
verifying: 0,
|
|
1202
|
+
not_persisted: 0,
|
|
1203
|
+
expired_today: 0,
|
|
1204
|
+
open,
|
|
1205
|
+
queued,
|
|
1206
|
+
receipt_at: null,
|
|
1207
|
+
balance,
|
|
1208
|
+
unresolved,
|
|
1209
|
+
incident,
|
|
1210
|
+
};
|
|
1211
|
+
const offered = jsonColumn(row.offered, []);
|
|
1212
|
+
let state;
|
|
1213
|
+
if (head)
|
|
1214
|
+
state = head.state;
|
|
1215
|
+
else if (row.receipt_at !== null)
|
|
1216
|
+
state = "received";
|
|
1217
|
+
else if (row.fired_at === null)
|
|
1218
|
+
state = "packet_ready";
|
|
1219
|
+
else if (offered.length === 0)
|
|
1220
|
+
state = "nothing";
|
|
1221
|
+
else
|
|
1222
|
+
state = "awaiting";
|
|
1223
|
+
return {
|
|
1224
|
+
day: row.day,
|
|
1225
|
+
state,
|
|
1226
|
+
offered: offered.length,
|
|
1227
|
+
adopted: count("receipt_day = ? AND status = 'adopted'", row.day),
|
|
1228
|
+
declined: count("receipt_day = ? AND status = 'declined'", row.day),
|
|
1229
|
+
verifying: count("receipt_day = ? AND status = 'adopting'", row.day),
|
|
1230
|
+
not_persisted: unresolved.find((u) => u.day === row.day && u.state === "not_persisted")?.count ?? 0,
|
|
1231
|
+
expired_today: jsonColumn(row.expired, []).length,
|
|
1232
|
+
open,
|
|
1233
|
+
queued,
|
|
1234
|
+
receipt_at: row.receipt_at,
|
|
1235
|
+
balance,
|
|
1236
|
+
unresolved,
|
|
1237
|
+
incident,
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
/** Undecided candidates per class, busiest first — `qcr lessons`. */
|
|
1241
|
+
clusters() {
|
|
1242
|
+
const since = this.recurrenceSince();
|
|
1243
|
+
const rows = this.candidates("status = 'open' ORDER BY class, id");
|
|
1244
|
+
const out = new Map();
|
|
1245
|
+
for (const r of rows) {
|
|
1246
|
+
const e = out.get(r.class) ?? { rows: [], queued: 0 };
|
|
1247
|
+
e.rows.push(r);
|
|
1248
|
+
if (r.offered_day === null)
|
|
1249
|
+
e.queued += 1;
|
|
1250
|
+
out.set(r.class, e);
|
|
1251
|
+
}
|
|
1252
|
+
const recurrence = this.recurrence(since);
|
|
1253
|
+
return [...out.entries()]
|
|
1254
|
+
.map(([cls, e]) => ({
|
|
1255
|
+
class: cls,
|
|
1256
|
+
polarity: majorityPolarity(e.rows),
|
|
1257
|
+
open: e.rows.length - e.queued,
|
|
1258
|
+
queued: e.queued,
|
|
1259
|
+
recurrence: recurrence.get(cls) ?? 0,
|
|
1260
|
+
}))
|
|
1261
|
+
.sort((a, b) => b.open + b.queued - (a.open + a.queued) || a.class.localeCompare(b.class));
|
|
1262
|
+
}
|
|
1263
|
+
/** One candidate row (tests, `qcr lessons`). */
|
|
1264
|
+
candidate(id) {
|
|
1265
|
+
return this.candidates("id = ?", id)[0];
|
|
1266
|
+
}
|
|
1267
|
+
/** Every candidate row, oldest first (tests). */
|
|
1268
|
+
allCandidates() {
|
|
1269
|
+
return this.candidates("1 = 1 ORDER BY id");
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
//# sourceMappingURL=learner.js.map
|