@askexenow/exe-os 0.9.372 → 0.9.374
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/deploy/compose/.env.customer.example +45 -10
- package/deploy/compose/.env.example +46 -9
- package/deploy/compose/docker-compose.yml +136 -18
- package/deploy/compose/generate-env.ts +142 -34
- package/deploy/compose/sso-edge/default.conf.template +78 -7
- package/deploy/compose/sso-edge/sso-redirect.conf +109 -13
- package/deploy/stack-manifests/v0.9.30-apps.json +1 -1
- package/deploy/stack-manifests/v0.9.json +4 -4
- package/dist/.dist-verified.json +3 -3
- package/dist/{active-agent-GRT5MKD5.js → active-agent-ONPPEWQV.js} +7 -6
- package/dist/{active-agent-L2ZSSXDK.js → active-agent-UJKMG7LJ.js} +7 -6
- package/dist/{agent-defs-generator-M4ZNYIVX.js → agent-defs-generator-ZWI6DXOE.js} +6 -5
- package/dist/{agent-loop-FOK2IRZQ.js → agent-loop-OYHJKNYH.js} +1 -1
- package/dist/{agentic-ontology-DMPRDEUX.js → agentic-ontology-WHFJ3QFS.js} +1 -1
- package/dist/{artifact-backup-767STHSW.js → artifact-backup-WXZNB7KE.js} +2 -1
- package/dist/{backfill-gate-VX2RZTQV.js → backfill-gate-KWJQ35YX.js} +3 -2
- package/dist/{backfill-metadata-ZMEHJQ5M.js → backfill-metadata-3OUSQD5V.js} +8 -7
- package/dist/{background-jobs-LTPWCMA3.js → background-jobs-6VMD55PK.js} +3 -2
- package/dist/{backup-verify-EX2K732J.js → backup-verify-ZKTUYLTA.js} +4 -3
- package/dist/{behavior-injection-22AGMS25.js → behavior-injection-M6UYZCMW.js} +17 -15
- package/dist/{behaviors-DVFXAWF5.js → behaviors-ZJ45TFBJ.js} +21 -13
- package/dist/bin/age-ontology-load.js +3 -2
- package/dist/bin/agentic-ontology-backfill.js +10 -9
- package/dist/bin/agentic-reflection-backfill.js +11 -10
- package/dist/bin/agentic-semantic-label.js +10 -9
- package/dist/bin/backfill-conversations.js +13 -11
- package/dist/bin/backfill-responses.js +13 -11
- package/dist/bin/backfill-vectors.js +17 -15
- package/dist/bin/bulk-sync-postgres.js +22 -20
- package/dist/bin/cc-doctor.js +10 -9
- package/dist/bin/cleanup-stale-review-tasks.js +29 -26
- package/dist/bin/cli.js +36 -26
- package/dist/bin/deferred-daemon-restart.js +114 -110
- package/dist/bin/exe-agent-config.js +6 -5
- package/dist/bin/exe-agent.js +127 -33
- package/dist/bin/exe-assign.js +15 -13
- package/dist/bin/exe-boot.js +57 -54
- package/dist/bin/exe-call.js +8 -7
- package/dist/bin/exe-cloud.js +24 -22
- package/dist/bin/exe-config-dump.js +6 -5
- package/dist/bin/exe-dispatch.js +30 -27
- package/dist/bin/exe-doctor.js +14 -10
- package/dist/bin/exe-export-behaviors.js +19 -17
- package/dist/bin/exe-forget.js +10 -9
- package/dist/bin/exe-gateway.js +199 -19
- package/dist/bin/exe-grant.js +5 -5
- package/dist/bin/exe-healthcheck.js +10 -9
- package/dist/bin/exe-heartbeat.js +35 -32
- package/dist/bin/exe-kill.js +34 -31
- package/dist/bin/exe-launch-agent.js +126 -54
- package/dist/bin/exe-mcp.js +6 -5
- package/dist/bin/exe-memory-reads.js +8 -7
- package/dist/bin/exe-new-employee.js +12 -11
- package/dist/bin/exe-os-mcp-proxy.js +6 -5
- package/dist/bin/exe-pending-messages.js +30 -27
- package/dist/bin/exe-pending-notifications.js +29 -26
- package/dist/bin/exe-pending-reviews.js +30 -27
- package/dist/bin/exe-rename.js +8 -7
- package/dist/bin/exe-repo-truth.js +1 -1
- package/dist/bin/exe-review.js +33 -30
- package/dist/bin/exe-search.js +9 -8
- package/dist/bin/exe-session-cleanup.js +35 -32
- package/dist/bin/exe-settings.js +24 -22
- package/dist/bin/exe-start-codex.js +137 -55
- package/dist/bin/exe-start-opencode.js +121 -23
- package/dist/bin/exe-status.js +31 -28
- package/dist/bin/exe-support.js +5 -4
- package/dist/bin/exe-team.js +7 -6
- package/dist/bin/exe-watchdog.js +31 -11
- package/dist/bin/generate-hook-manifest.js +44 -7
- package/dist/bin/git-sweep.js +31 -28
- package/dist/bin/graph-backfill.js +89 -35
- package/dist/bin/graph-export.js +9 -8
- package/dist/bin/import-history.js +14 -13
- package/dist/bin/install.js +137 -113
- package/dist/bin/intercom-check.js +5 -5
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +7 -6
- package/dist/bin/postgres-agentic-reflection-backfill.js +5 -4
- package/dist/bin/postgres-agentic-semantic-backfill.js +4 -3
- package/dist/bin/pre-publish.js +1 -1
- package/dist/bin/reconcile-backlog.js +2 -2
- package/dist/bin/registry-proxy.js +1 -1
- package/dist/bin/scan-tasks.js +29 -26
- package/dist/bin/setup.js +5 -4
- package/dist/bin/shard-migrate.js +9 -8
- package/dist/bin/stack-update.js +40 -9
- package/dist/bin/verify-stack.js +2 -2
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/{boot-generation-OHXH4YC5.js → boot-generation-JKVZ4ZAT.js} +6 -5
- package/dist/{boot-review-sections-N5IXIGSS.js → boot-review-sections-2M6BTG73.js} +28 -25
- package/dist/{branch-hygiene-KCGXRAWP.js → branch-hygiene-U5GFRSTP.js} +31 -7
- package/dist/{branding-GH43W3PU.js → branding-I6KIMB7F.js} +3 -2
- package/dist/budget-fallback-XJRPMP2D.js +11 -0
- package/dist/build-manifest.json +1318 -1233
- package/dist/{capability-cards-4PXVLIVS.js → capability-cards-5IMJT6J7.js} +5 -4
- package/dist/{capacity-monitor-FKMQXORX.js → capacity-monitor-SAXCQK7O.js} +30 -27
- package/dist/{catchup-brief-SN5EKO4N.js → catchup-brief-U2TXBLHD.js} +34 -31
- package/dist/{chunk-CNC57JCS.js → chunk-23MVDXLY.js} +4 -4
- package/dist/{chunk-V4XAKXXF.js → chunk-2AJGV5UL.js} +1 -1
- package/dist/{chunk-FBYAXTDM.js → chunk-2ZOEC4KC.js} +10 -2
- package/dist/{chunk-ELXFSIIM.js → chunk-32YV32VA.js} +2 -2
- package/dist/{chunk-44C7QNZS.js → chunk-3KDCORDO.js} +1 -1
- package/dist/{chunk-JTB5V6BV.js → chunk-3SXHEQ7X.js} +1 -1
- package/dist/{chunk-HDW4XPDV.js → chunk-3UUX5OY4.js} +1 -1
- package/dist/{chunk-7PSLK36P.js → chunk-44TLJZJ5.js} +1 -1
- package/dist/{chunk-JTWTBX2M.js → chunk-4EN3IZ3Q.js} +2 -1
- package/dist/{chunk-KPMC7PY7.js → chunk-4HKTO2SV.js} +1 -1
- package/dist/{chunk-CDUB5Q6J.js → chunk-4IK2K3B3.js} +1 -1
- package/dist/{chunk-GH6YJOOC.js → chunk-4SJ4LK4V.js} +6 -6
- package/dist/{chunk-PVEM537A.js → chunk-4YLBKEL5.js} +2 -2
- package/dist/chunk-4YNA3CM6.js +872 -0
- package/dist/{chunk-KYFFVTGO.js → chunk-55BEFF4V.js} +3 -3
- package/dist/{chunk-SEP5ITFQ.js → chunk-636LKCKE.js} +2 -2
- package/dist/{chunk-QTI4QAWA.js → chunk-6EZQUNE6.js} +338 -5
- package/dist/{chunk-WAEKYKTK.js → chunk-6RKKVPYF.js} +1 -1
- package/dist/{chunk-VX2F4ZUY.js → chunk-6SCGLHJ7.js} +3 -3
- package/dist/{chunk-MEGRQ53A.js → chunk-6VHOQ3IM.js} +51 -6
- package/dist/{chunk-HIIXCAEE.js → chunk-6YVUR3OU.js} +3 -3
- package/dist/{chunk-L6ZNURWN.js → chunk-7GE2EQ23.js} +1 -1
- package/dist/{chunk-2CWS374F.js → chunk-7RI2CNXJ.js} +1 -1
- package/dist/{chunk-OL3QP3AU.js → chunk-7TSBV3SD.js} +1 -1
- package/dist/{chunk-DSOQUQTV.js → chunk-A27Q27CT.js} +27 -0
- package/dist/{chunk-5AHRZI3R.js → chunk-AETLDRZB.js} +1 -1
- package/dist/{chunk-RNLF3CBB.js → chunk-AKLJ4JH3.js} +1 -1
- package/dist/{chunk-XHYHX6F7.js → chunk-AKLQSC6W.js} +329 -164
- package/dist/chunk-ANLFH23R.js +261 -0
- package/dist/{chunk-QLA3RTH4.js → chunk-AWWKRZMB.js} +5 -5
- package/dist/{chunk-ERVQTR7P.js → chunk-BBSIEYF5.js} +17 -3
- package/dist/{chunk-IPMUWYRQ.js → chunk-BJ7AVSY6.js} +2 -2
- package/dist/{chunk-HV6Y6F4X.js → chunk-C2L622QJ.js} +89 -3
- package/dist/{chunk-TX3Q2GIL.js → chunk-C5HUMAA7.js} +24 -1
- package/dist/{chunk-QTYJPWJN.js → chunk-CBCGDEJA.js} +7 -7
- package/dist/{chunk-XXSNLM6R.js → chunk-DB55JZHU.js} +1 -1
- package/dist/{chunk-LAZKEJMS.js → chunk-DIXXEE3S.js} +840 -607
- package/dist/{chunk-FB343XQX.js → chunk-DJ7YXOTU.js} +2 -2
- package/dist/{chunk-YFCNWQAM.js → chunk-DJOIMFKV.js} +2 -2
- package/dist/{chunk-UTDMTQNH.js → chunk-DSJI76XL.js} +92 -14
- package/dist/{chunk-EEXX4UMQ.js → chunk-DZKPOSFD.js} +1 -1
- package/dist/{chunk-WSOA3WMC.js → chunk-E426DOSY.js} +161 -4
- package/dist/{chunk-ZISQOOER.js → chunk-EKE37MO4.js} +3 -3
- package/dist/{chunk-RIECV7SR.js → chunk-EKYYMIVT.js} +1 -1
- package/dist/{chunk-HIVZ53YB.js → chunk-EXTZSNWL.js} +2 -2
- package/dist/{chunk-YYA5LXCT.js → chunk-FNEZ4BWT.js} +1 -1
- package/dist/chunk-FTZET5YX.js +313 -0
- package/dist/chunk-GHR4ZPJ7.js +70 -0
- package/dist/{chunk-MINXPXAB.js → chunk-GJI77VDO.js} +3 -3
- package/dist/{chunk-AAMGHW5W.js → chunk-GLQEJOXE.js} +1 -0
- package/dist/{chunk-ADNBOKYZ.js → chunk-GM7TLYOK.js} +60 -18
- package/dist/{chunk-RUWWES2K.js → chunk-GNUAL43X.js} +2 -2
- package/dist/{chunk-QZL6E4UB.js → chunk-GOMQ7PVQ.js} +2 -2
- package/dist/{chunk-GB3AHV5F.js → chunk-GQOEWNVM.js} +1 -1
- package/dist/{chunk-NQZUSEAR.js → chunk-GS7LIT34.js} +246 -17
- package/dist/{chunk-XTWHNLGD.js → chunk-GZOG2MAX.js} +1 -1
- package/dist/{chunk-E5HAY3DQ.js → chunk-HDLAB7W3.js} +1 -1
- package/dist/{chunk-E5QQZDQN.js → chunk-HNWS7YHN.js} +358 -136
- package/dist/{chunk-VV5EZZNT.js → chunk-HTBEVCO2.js} +1 -1
- package/dist/{chunk-OZBII5E3.js → chunk-I4DNJFDR.js} +4 -4
- package/dist/{chunk-SI5SZAJA.js → chunk-IBS2FAI4.js} +21 -4
- package/dist/{chunk-J5EYOBFF.js → chunk-IHXW4VUI.js} +1 -1
- package/dist/{chunk-RUVO3NJC.js → chunk-IN6CAM4F.js} +9 -3
- package/dist/{chunk-53PYNYTW.js → chunk-IRVOXUSK.js} +5 -5
- package/dist/{chunk-THM7J6UI.js → chunk-JHI5WMK5.js} +5 -5
- package/dist/{chunk-3KTQWMHI.js → chunk-JSMDRKPJ.js} +12 -4
- package/dist/chunk-JTVIANUB.js +131 -0
- package/dist/{chunk-2ADYTOHQ.js → chunk-K4ESASPL.js} +1 -1
- package/dist/{chunk-YWUQVHDL.js → chunk-KTCXJWJG.js} +1 -1
- package/dist/{chunk-RGUDGC6A.js → chunk-KTU3EAWK.js} +5 -5
- package/dist/{chunk-DKBPCOU4.js → chunk-L6RXG36J.js} +2 -2
- package/dist/{chunk-T4EK56WI.js → chunk-LDNYSMPZ.js} +1 -1
- package/dist/{chunk-RIK5GRWI.js → chunk-LGS2V2XD.js} +3 -3
- package/dist/{chunk-JKXZGRWR.js → chunk-LP4GB656.js} +2 -2
- package/dist/{chunk-H74466TM.js → chunk-M7O7TGGU.js} +1 -1
- package/dist/chunk-MJCSEIFI.js +54 -0
- package/dist/{chunk-IDZPQG2D.js → chunk-MOGA4Q7F.js} +2 -2
- package/dist/{chunk-OYQNNKNS.js → chunk-MXPNVSXI.js} +37 -14
- package/dist/{chunk-UVW7YFAF.js → chunk-N7VEP5B3.js} +4 -4
- package/dist/{chunk-HHE2HV3V.js → chunk-NBXDXKLC.js} +1 -1
- package/dist/{chunk-LDL3S7AC.js → chunk-NKETJCB5.js} +7 -3
- package/dist/{chunk-ECHLVLA7.js → chunk-NMH5ZQPU.js} +1 -1
- package/dist/{chunk-U3XLRMJD.js → chunk-NT7W4RXD.js} +1 -1
- package/dist/{chunk-UQUUNGTP.js → chunk-NUK7EEN5.js} +11 -9
- package/dist/{chunk-GBNB4EWD.js → chunk-ORM7ZFKC.js} +16 -0
- package/dist/{chunk-O4ZFRK6W.js → chunk-OVEQE6YS.js} +244 -49
- package/dist/{chunk-4ZJ5BPY6.js → chunk-PB5S7YOF.js} +2 -2
- package/dist/{chunk-JR23BL74.js → chunk-PDVXWXTL.js} +4 -4
- package/dist/{chunk-3CIMDFXG.js → chunk-PFQ3VEEM.js} +1 -1
- package/dist/{chunk-SBJV2PCU.js → chunk-PHBU4LGO.js} +1 -1
- package/dist/{chunk-W25RLOQ2.js → chunk-PLZSZOZN.js} +3 -3
- package/dist/{chunk-THIJIOE2.js → chunk-PY3FOMRN.js} +18 -6
- package/dist/{chunk-AAUWFXOX.js → chunk-Q3AXXKDF.js} +3 -3
- package/dist/{chunk-VKXS2YGN.js → chunk-QHJR7IMX.js} +2 -2
- package/dist/chunk-QLZ46RCK.js +45 -0
- package/dist/{chunk-UHPMK6QZ.js → chunk-R3CZWFFC.js} +10 -2
- package/dist/{chunk-6XEYELCA.js → chunk-R4CBHKZ2.js} +1 -1
- package/dist/{chunk-5APCDDJZ.js → chunk-R522MWAR.js} +9 -9
- package/dist/chunk-RH4AH3YB.js +80 -0
- package/dist/{chunk-AMKSDKMK.js → chunk-S2WBS6BG.js} +22 -35
- package/dist/{chunk-WUKQVNLP.js → chunk-SEQIPGLU.js} +1 -1
- package/dist/{chunk-7WQRFSZI.js → chunk-SL6KQYDU.js} +26 -6
- package/dist/chunk-SLLLOOEI.js +103 -0
- package/dist/{chunk-5N4SG5NB.js → chunk-T35RCQFE.js} +3 -3
- package/dist/{chunk-7V6M3QUS.js → chunk-T3QUKNLI.js} +1 -1
- package/dist/{chunk-CW2UCKHS.js → chunk-TADAO3HV.js} +2 -2
- package/dist/{chunk-5DCCKHDY.js → chunk-TAMDAOCU.js} +109 -13
- package/dist/{chunk-ZXB56YR2.js → chunk-TFKCERAK.js} +101 -23
- package/dist/{chunk-RBYHJDAT.js → chunk-TQAZTRQ3.js} +3 -3
- package/dist/{chunk-OKGIOWOB.js → chunk-U6SUKSZR.js} +2 -2
- package/dist/{chunk-23QKEUF6.js → chunk-U73AC5AN.js} +34 -12
- package/dist/{chunk-PM6WSWVU.js → chunk-UBK7HK3J.js} +3 -3
- package/dist/{chunk-H37FSTF2.js → chunk-UBMZ3YQU.js} +1 -1
- package/dist/{chunk-JJUGI2YL.js → chunk-UCFC2AEI.js} +1 -1
- package/dist/{chunk-6IWLAQ7O.js → chunk-UCUOGVDX.js} +4 -0
- package/dist/{chunk-E7UCDSUE.js → chunk-UKLN57Q5.js} +2 -2
- package/dist/{chunk-ZYCLSEZT.js → chunk-ULIBLJ6W.js} +33 -11
- package/dist/{chunk-RLR6VVKV.js → chunk-UM3N6VND.js} +4 -4
- package/dist/{chunk-ZNUJFX7L.js → chunk-UQGSBM3U.js} +1 -1
- package/dist/{chunk-ZZXMB5F2.js → chunk-UZDF6FLJ.js} +1 -1
- package/dist/{chunk-LNOS24GV.js → chunk-V3WLC5TJ.js} +2 -95
- package/dist/{chunk-UXLO7VHX.js → chunk-VI4ATC6I.js} +1 -1
- package/dist/{chunk-77JP3LK4.js → chunk-VKJGHAZT.js} +92 -21
- package/dist/{chunk-7R73IAHU.js → chunk-VMTZ4RUW.js} +67 -150
- package/dist/{chunk-TGPQMMQP.js → chunk-VYQ7B7DI.js} +30 -17
- package/dist/{chunk-E2WEFZOR.js → chunk-W75GTHR3.js} +1 -1
- package/dist/{chunk-UKLF7F3Z.js → chunk-WJG344NC.js} +9 -9
- package/dist/{chunk-MBNIJXKI.js → chunk-WMEYJT4R.js} +18 -4
- package/dist/{chunk-R6FLELV6.js → chunk-XFTEX77S.js} +3 -3
- package/dist/{chunk-MDGYXUOV.js → chunk-XH7YL7JM.js} +1 -1
- package/dist/{chunk-JOO35RHR.js → chunk-XL5MFGMR.js} +3 -3
- package/dist/{chunk-OW5RZIDW.js → chunk-XNNECNDL.js} +95 -33
- package/dist/{chunk-5AHDQCTB.js → chunk-XXFKSJYA.js} +6 -6
- package/dist/{chunk-TGEPLJ66.js → chunk-XXOPG4BW.js} +3 -3
- package/dist/{chunk-PGLPUP37.js → chunk-XZ65ST2I.js} +1 -1
- package/dist/{chunk-3TTKAT6V.js → chunk-YKC7QDZH.js} +9 -4
- package/dist/{chunk-KXYFBBZR.js → chunk-YMP2QSOP.js} +20 -3
- package/dist/{chunk-TK4MI6F6.js → chunk-YSLGFPWX.js} +6 -6
- package/dist/{chunk-X2P43TB2.js → chunk-YTSXPJUQ.js} +1 -1
- package/dist/{chunk-HECXZGGZ.js → chunk-ZCERWHY2.js} +33 -35
- package/dist/{chunk-IVU3WN7S.js → chunk-ZG62LIK3.js} +74 -4
- package/dist/{chunk-GU62SNDH.js → chunk-ZGYNKA3O.js} +744 -111
- package/dist/{chunk-QMSEL5YS.js → chunk-ZIG7VPJV.js} +28 -76
- package/dist/{chunk-WZJVGA5I.js → chunk-ZL4AGWAH.js} +258 -13
- package/dist/{chunk-QR624DER.js → chunk-ZSODLMFV.js} +2 -2
- package/dist/{cleanup-graph-garbage-IPYDS5OX.js → cleanup-graph-garbage-DPJGO52H.js} +11 -10
- package/dist/{cloud-sync-command-JLNVG7H4.js → cloud-sync-command-JPNTT4OQ.js} +2 -2
- package/dist/{cloud-sync-db-init-JXUF6GI3.js → cloud-sync-db-init-V2LWIUQU.js} +1 -1
- package/dist/{cloud-sync-shutdown-Z4SBP6PL.js → cloud-sync-shutdown-BNALPWGX.js} +5 -4
- package/dist/{co-activation-74RDFTKS.js → co-activation-CMNSWS6B.js} +5 -4
- package/dist/{co-occurrence-CN3TBYVR.js → co-occurrence-WRI2NAN6.js} +9 -8
- package/dist/{code-context-index-D4MJ4VFX.js → code-context-index-NOJSHLPN.js} +12 -6
- package/dist/code-context-watcher-VZNZU3BO.js +118 -0
- package/dist/{codex-consolidation-PPXNBXCV.js → codex-consolidation-SH4UKFBQ.js} +2 -1
- package/dist/{conversation-entity-extractor-QGTLH4BP.js → conversation-entity-extractor-74252CAO.js} +4 -4
- package/dist/{conversation-wiki-populator-EBUZXYEU.js → conversation-wiki-populator-OS4C6W54.js} +1 -1
- package/dist/conversations-retention-C4BLKFEL.js +54 -0
- package/dist/coordinator-notice-MHUY7AQB.js +55 -0
- package/dist/{crdt-sync-7T4WCOKD.js → crdt-sync-B3JN6AIV.js} +1 -1
- package/dist/{crm-webhook-FTW3XZTO.js → crm-webhook-GYWQRFET.js} +2 -2
- package/dist/{cto-delegation-gate-SZCE34LB.js → cto-delegation-gate-LQHVLEMW.js} +29 -26
- package/dist/{daemon-auth-SSPY5ODS.js → daemon-auth-QZHEO7IQ.js} +3 -2
- package/dist/{daemon-orchestration-IGPHVNFR.js → daemon-orchestration-5HIQALZH.js} +36 -34
- package/dist/{daemon-ready-OT2VQLS7.js → daemon-ready-P2BR2XP5.js} +1 -1
- package/dist/{db-integrity-events-5DTASXJF.js → db-integrity-events-2DTFO37N.js} +3 -2
- package/dist/{db-restore-events-2FI4ZMKA.js → db-restore-events-G6NOQOVE.js} +2 -1
- package/dist/{destructive-data-guard-6I5MDFVD.js → destructive-data-guard-BVFWPPIS.js} +1 -1
- package/dist/doc-graph-extractor-PQHDHQPQ.js +367 -0
- package/dist/{documents-URULIXGM.js → documents-C4SSPJMC.js} +15 -13
- package/dist/{dreaming-VIZO3QDO.js → dreaming-XAO3FCBV.js} +33 -30
- package/dist/{employee-boot-brief-XLOG4ULP.js → employee-boot-brief-W4OHUMRQ.js} +37 -34
- package/dist/{exe-drift-TLQM3IHD.js → exe-drift-AG2KMKD5.js} +6 -5
- package/dist/{exe-export-7YWYWJHY.js → exe-export-IC5BT335.js} +17 -15
- package/dist/{exe-import-DW6VAUKW.js → exe-import-A35ZLDPG.js} +17 -15
- package/dist/{exe-key-TLJP2B4Y.js → exe-key-TCMJNYLA.js} +116 -112
- package/dist/{exe-org-LU46N36E.js → exe-org-JXCR3JYZ.js} +24 -23
- package/dist/{exe-snapshot-QHUZRS62.js → exe-snapshot-SV6SRIG6.js} +36 -33
- package/dist/{fast-db-init-SCTOOIUT.js → fast-db-init-L2RGKJWH.js} +1 -1
- package/dist/{founder-context-ZFZC4UHO.js → founder-context-D4HFIESJ.js} +4 -3
- package/dist/{founder-monitor-envelope-5KTKNL5G.js → founder-monitor-envelope-TFKRGCFE.js} +5 -4
- package/dist/{fts-integrity-LKAZEZJE.js → fts-integrity-4YB34KWX.js} +3 -2
- package/dist/gateway/index.js +19 -17
- package/dist/{git-main-guard-TN27QBAI.js → git-main-guard-VTW4N3CM.js} +7 -1
- package/dist/{git-staleness-GSGP344N.js → git-staleness-TN7CYGFG.js} +5 -4
- package/dist/{global-procedures-YAR7G4C6.js → global-procedures-YFDEIOG7.js} +7 -6
- package/dist/{graph-auto-extract-GNQS64F5.js → graph-auto-extract-3YR3TYRW.js} +9 -8
- package/dist/{graph-rag-RMSFLUOB.js → graph-rag-Z2KCJTPK.js} +6 -4
- package/dist/{hook-integrity-CF567MVN.js → hook-integrity-KGAV6ZC2.js} +14 -4
- package/dist/{hook-prefetch-36BK4F7U.js → hook-prefetch-K5DN3TOQ.js} +29 -26
- package/dist/hooks/bug-report-worker.js +34 -30
- package/dist/hooks/codex-stop-task-finalizer.js +36 -32
- package/dist/hooks/commit-complete.js +33 -30
- package/dist/hooks/error-recall.js +12 -11
- package/dist/hooks/exe-heartbeat-hook.js +8 -7
- package/dist/hooks/ingest-worker.js +23 -11
- package/dist/hooks/ingest.js +18 -17
- package/dist/hooks/instructions-loaded.js +10 -9
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +9 -8
- package/dist/hooks/post-compact.js +8 -7
- package/dist/hooks/post-tool-combined.js +26 -15
- package/dist/hooks/pre-compact.js +33 -30
- package/dist/hooks/pre-tool-use.js +404 -46
- package/dist/hooks/prompt-submit.js +57 -47
- package/dist/hooks/session-end.js +40 -41
- package/dist/hooks/session-start.js +21 -20
- package/dist/hooks/stop.js +40 -37
- package/dist/hooks/subagent-stop.js +38 -35
- package/dist/hooks/summary-worker.js +39 -36
- package/dist/hyde-MP4QNMU5.js +80 -0
- package/dist/index.js +44 -39
- package/dist/{installer-LUN4HQIC.js → installer-54HTN5RE.js} +8 -7
- package/dist/{installer-OC5VXNC7.js → installer-LK35OX6R.js} +8 -7
- package/dist/{installer-MPRFUQJE.js → installer-LLWKZI2S.js} +8 -7
- package/dist/intercom-ack-VCW755TN.js +13 -0
- package/dist/{intercom-queue-6DZ7BANV.js → intercom-queue-5NOT2RKI.js} +28 -25
- package/dist/{key-backup-status-6L2ARCXW.js → key-backup-status-LQPINQ3W.js} +2 -1
- package/dist/lib/agent-config.js +3 -2
- package/dist/lib/cloud-sync.js +26 -20
- package/dist/lib/config.js +2 -1
- package/dist/lib/consolidation.js +17 -10
- package/dist/lib/database.js +7 -4
- package/dist/lib/db-backup.js +17 -2
- package/dist/lib/db-daemon-client.js +8 -6
- package/dist/lib/db-write-worker-client.js +3 -1
- package/dist/lib/db-write-worker.js +20 -3
- package/dist/lib/db.js +7 -4
- package/dist/lib/device-registry.js +3 -2
- package/dist/lib/embed-worker.js +2 -1
- package/dist/lib/embedder.js +8 -6
- package/dist/lib/employee-templates.js +8 -7
- package/dist/lib/employees.js +5 -4
- package/dist/lib/exe-daemon-client.js +7 -5
- package/dist/lib/exe-daemon.js +467 -221
- package/dist/lib/hybrid-search.js +11 -8
- package/dist/lib/identity.js +5 -4
- package/dist/lib/license.js +4 -3
- package/dist/lib/messaging.js +29 -26
- package/dist/lib/post-tool-memory.js +16 -2
- package/dist/lib/registry-proxy.js +3 -1
- package/dist/lib/reminders.js +6 -5
- package/dist/lib/schedules.js +9 -8
- package/dist/lib/session-registry.js +7 -6
- package/dist/lib/skill-learning.js +16 -14
- package/dist/lib/stack-invariants.js +17 -1
- package/dist/lib/status-brief.js +5 -4
- package/dist/lib/store.js +10 -7
- package/dist/lib/task-router.js +6 -5
- package/dist/lib/tasks.js +31 -27
- package/dist/lib/tmux-routing.js +40 -25
- package/dist/lib/tmux-status.js +3 -1
- package/dist/lib/tmux-transport.js +2 -1
- package/dist/lib/token-spend.js +6 -5
- package/dist/lib/transport.js +3 -2
- package/dist/{license-gate-ESER24PJ.js → license-gate-JVMB6OFD.js} +5 -4
- package/dist/{license-sync-JVG5KNIY.js → license-sync-5VYS2F2W.js} +4 -3
- package/dist/mcp/register-tools.js +113 -109
- package/dist/mcp/server.js +118 -114
- package/dist/mcp/tools/complete-reminder.js +7 -6
- package/dist/mcp/tools/create-reminder.js +7 -6
- package/dist/mcp/tools/create-task.js +34 -30
- package/dist/mcp/tools/deactivate-behavior.js +18 -16
- package/dist/mcp/tools/list-reminders.js +7 -6
- package/dist/mcp/tools/list-tasks.js +34 -30
- package/dist/mcp/tools/send-message.js +32 -29
- package/dist/mcp/tools/update-task.js +32 -28
- package/dist/mcp-child-registry-OTG4MWO7.js +25 -0
- package/dist/{mcp-http-config-6K6IKH5F.js → mcp-http-config-DQWL7U2Z.js} +6 -5
- package/dist/{mcp-session-identity-LRC6WJSD.js → mcp-session-identity-277GASTQ.js} +28 -25
- package/dist/{memory-cards-V3OZHIYP.js → memory-cards-3S2ZQPR7.js} +17 -8
- package/dist/{memory-graph-extractor-JC2Z64L4.js → memory-graph-extractor-A6DFEFIN.js} +10 -9
- package/dist/{memory-poisoning-defense-YM4QJHCX.js → memory-poisoning-defense-ZVP4H6DY.js} +5 -4
- package/dist/{memory-pressure-watchdog-6F6KEQHN.js → memory-pressure-watchdog-6W5F6R7H.js} +29 -26
- package/dist/{memory-queue-QJNWKWKG.js → memory-queue-YF7IDSFY.js} +3 -2
- package/dist/{memory-queue-client-COA4ABEV.js → memory-queue-client-ADSDP6OX.js} +9 -7
- package/dist/{memory-reflection-QXHJPYPC.js → memory-reflection-BKB2YOE6.js} +52 -6
- package/dist/{monitor-grants-BW2WL4IU.js → monitor-grants-EV747HMW.js} +4 -3
- package/dist/{notification-ledger-6QRLQW4Q.js → notification-ledger-CLGM7ODF.js} +30 -27
- package/dist/{notifications-7B6D7Y5C.js → notifications-MACUZPYP.js} +28 -25
- package/dist/{oauth-server-TZFNQAFS.js → oauth-server-AYM37SQ4.js} +25 -4
- package/dist/{orchestration-events-GY5VP5LU.js → orchestration-events-N7LYMUGA.js} +6 -5
- package/dist/{orchestration-phase-UDS24CVQ.js → orchestration-phase-T2WD45UA.js} +3 -2
- package/dist/{orchestrator-JVPVOYWA.js → orchestrator-4X24EWHV.js} +30 -27
- package/dist/{org-brief-session-GRV5R5E3.js → org-brief-session-FZOFMO5U.js} +13 -12
- package/dist/{org-consent-policy-3FHHSYXV.js → org-consent-policy-O5E6HXBL.js} +1 -1
- package/dist/{org-join-BY4PV6UO.js → org-join-POWUG25F.js} +8 -7
- package/dist/{org-key-admin-WSCPT2CZ.js → org-key-admin-E7EMDOZZ.js} +9 -8
- package/dist/{org-key-pin-5WUSPGVN.js → org-key-pin-WHWHVWUO.js} +4 -3
- package/dist/{org-membership-ESALTLLN.js → org-membership-WRT2IHJK.js} +5 -4
- package/dist/{org-partner-config-YKHPDPZR.js → org-partner-config-B7T4CL2T.js} +7 -6
- package/dist/{org-partner-runtime-UJDGECZ4.js → org-partner-runtime-FODONVTM.js} +13 -12
- package/dist/{org-row-visibility-V5DXIHTE.js → org-row-visibility-VX4AVV5Q.js} +1 -1
- package/dist/{pipeline-router-YY5FQKTY.js → pipeline-router-6GGT2ZW3.js} +6 -5
- package/dist/{plan-limits-OVX6SN6B.js → plan-limits-FUN76LYY.js} +8 -7
- package/dist/{platform-procedures-I57ITMDC.js → platform-procedures-7YSCLF4Z.js} +1 -1
- package/dist/{postinstall-failure-B2JHNFPM.js → postinstall-failure-O6TSSNJB.js} +3 -2
- package/dist/{project-boot-LXLU2J32.js → project-boot-3Q65LCIP.js} +2 -1
- package/dist/project-name-LJVFMYTQ.js +30 -0
- package/dist/{projection-worker-D2472IOD.js → projection-worker-4OANGP5K.js} +5 -4
- package/dist/{prospective-memory-JXO2A6PL.js → prospective-memory-KR3P4T6N.js} +5 -4
- package/dist/{push-notifications-HR3FZRDI.js → push-notifications-NCZLH6DI.js} +29 -26
- package/dist/ref-provenance-gate-M4AQO4OT.js +269 -0
- package/dist/{reproject-worktree-memories-OSS3PGRF.js → reproject-worktree-memories-PWYKPB2U.js} +106 -23
- package/dist/{reranker-IMZRPYJ2.js → reranker-6V3C2AO4.js} +3 -2
- package/dist/resolve-image-labels-ZI6UBW5W.js +15 -0
- package/dist/{retrieval-health-W7OD44FE.js → retrieval-health-5D7O6VH6.js} +4 -3
- package/dist/{review-polling-2INP7H6M.js → review-polling-QW3LJ4KN.js} +29 -26
- package/dist/runtime/index.js +38 -34
- package/dist/{session-events-G4XUPVWV.js → session-events-T45SSTMF.js} +31 -26
- package/dist/{session-kill-telemetry-W7MHWJTQ.js → session-kill-telemetry-QSPVJGBF.js} +29 -26
- package/dist/{session-mcp-config-F7KATWOF.js → session-mcp-config-SC5BLWZG.js} +3 -2
- package/dist/{session-scope-LG2J4EMQ.js → session-scope-KRWE54C4.js} +28 -25
- package/dist/{setup-wizard-YQJI3SVM.js → setup-wizard-GP3TBTPF.js} +5 -4
- package/dist/{shard-manager-UROHZE46.js → shard-manager-OE36A4MY.js} +3 -2
- package/dist/{skill-refinement-RA37U756.js → skill-refinement-C7JTMLJG.js} +6 -5
- package/dist/stack-generate-manifest-MFMDWRUP.js +810 -0
- package/dist/{stack-promote-IYBRXHTA.js → stack-promote-EKSCYY63.js} +8 -6
- package/dist/{stack-release-OXWLVVG6.js → stack-release-2GZAAFO4.js} +8 -6
- package/dist/{stack-update-2CZEROPK.js → stack-update-J6JXSTAZ.js} +51 -5
- package/dist/{steward-gate-LTNFB3FY.js → steward-gate-BFCCMCSW.js} +6 -5
- package/dist/{subagent-brief-injection-OHLWLECQ.js → subagent-brief-injection-ED36PLYY.js} +44 -36
- package/dist/{subagent-spawn-ledger-USYZXU3M.js → subagent-spawn-ledger-E6U3OY6Z.js} +3 -2
- package/dist/{supervisor-handoff-CSJQMI53.js → supervisor-handoff-SGLEPOCY.js} +12 -3
- package/dist/{support-inbox-4KCEPAZQ.js → support-inbox-YW47SYJF.js} +20 -5
- package/dist/{task-enforcement-LGXWXGVZ.js → task-enforcement-CECTQX4U.js} +29 -26
- package/dist/{task-request-inbox-WHCOSUCP.js → task-request-inbox-Q5T4N5K7.js} +1 -1
- package/dist/{task-scope-KXF7Y6KA.js → task-scope-ERVEUEYU.js} +28 -25
- package/dist/{tasks-crud-5EM55WRZ.js → tasks-crud-ZRQNJXQ2.js} +28 -25
- package/dist/{tasks-notify-VFMAURTN.js → tasks-notify-MIZH4C2O.js} +29 -26
- package/dist/{tasks-review-MHGMBHUZ.js → tasks-review-Z7J2P6DG.js} +28 -25
- package/dist/{telemetry-upload-6NRTN7QJ.js → telemetry-upload-LVQUQYFP.js} +10 -9
- package/dist/{token-budget-LZPOYTRP.js → token-budget-BU4NOVZF.js} +6 -5
- package/dist/{tool-capability-index-ED5OAPMW.js → tool-capability-index-7F42MOJT.js} +1 -1
- package/dist/{tool-gates-7PLIOLAL.js → tool-gates-JWVSAYTW.js} +1 -1
- package/dist/{tool-gates-2OZY3GZM.js → tool-gates-VXITVRFQ.js} +1 -1
- package/dist/{tool-telemetry-ZX7VSAXK.js → tool-telemetry-O27EVMBR.js} +1 -1
- package/dist/tui/App.js +43 -40
- package/dist/{tui-data-CC5POSUV.js → tui-data-TPWWBIUQ.js} +28 -25
- package/dist/{update-support-KH6NSQON.js → update-support-F2F5537B.js} +22 -20
- package/dist/{whatsapp-QW3X7OCN.js → whatsapp-YM4A2CSK.js} +3 -1
- package/dist/{work-claims-MNK7PEPW.js → work-claims-B73X5NE7.js} +6 -5
- package/dist/{work-state-heartbeat-YEWT5NMZ.js → work-state-heartbeat-P4YX6E2R.js} +1 -1
- package/dist/{worker-gate-BOQSIU2Z.js → worker-gate-BEEIIVWA.js} +3 -2
- package/dist/{workflow-engine-MUUD7ZEX.js → workflow-engine-5X46PFCW.js} +4 -2
- package/dist/{worktree-GOGT2LZP.js → worktree-W47CIMJ6.js} +9 -6
- package/dist/worktree-ownership-guard-OUWJROW2.js +88 -0
- package/dist/{worktree-sweep-46VWPVQT.js → worktree-sweep-BNBD4RFX.js} +8 -7
- package/package.json +14 -5
- package/release-notes.json +5 -5
- package/src/commands/exe/call.md +1 -1
- package/stack.release.json +6 -0
- package/dist/chunk-KZXMP6JG.js +0 -319
- package/dist/chunk-TCTED52S.js +0 -120
- package/dist/chunk-W2IRQJ6R.js +0 -67
- package/dist/doc-graph-extractor-VPTRIEKN.js +0 -149
- package/dist/project-name-ILJTETUE.js +0 -14
- /package/dist/{chunk-3Y5THOU6.js → chunk-6WIFPD2P.js} +0 -0
- /package/dist/{chunk-7XGXRD22.js → chunk-AISULNGL.js} +0 -0
- /package/dist/{chunk-3F2UB4IQ.js → chunk-DN4YVV4Z.js} +0 -0
- /package/dist/{chunk-WV3TOOL7.js → chunk-KQ6RJWRW.js} +0 -0
- /package/dist/{chunk-HR2R2QER.js → chunk-M4IRPXSZ.js} +0 -0
- /package/dist/{chunk-ORA5BWCV.js → chunk-NRG7KZIP.js} +0 -0
- /package/dist/{chunk-7UTJA6HF.js → chunk-VZAFWPAY.js} +0 -0
- /package/dist/{chunk-VJSDGDNS.js → chunk-WSQASFLP.js} +0 -0
- /package/dist/{chunk-FZQWVQJG.js → chunk-YO4BO2CL.js} +0 -0
- /package/dist/{core-memory-6WBNT2HL.js → core-memory-7I7RE2SJ.js} +0 -0
- /package/dist/{entity-boost-MT336PI3.js → entity-boost-3UWGXG5O.js} +0 -0
- /package/dist/{memory-isolation-EJ45IXBH.js → memory-isolation-2TUZ7Z4K.js} +0 -0
- /package/dist/{message-queue-client-MVBTYCSV.js → message-queue-client-XQN7QABL.js} +0 -0
- /package/dist/{webhook-pipe-UQSEHFPO.js → webhook-pipe-W2FVXY7M.js} +0 -0
- /package/dist/{wiki-acl-WXRJGZ5Q.js → wiki-acl-IBQLLBTS.js} +0 -0
- /package/dist/{wiki-client-AXNM5FWY.js → wiki-client-W65IOSWF.js} +0 -0
|
@@ -0,0 +1,872 @@
|
|
|
1
|
+
// src/lib/verification-evidence.ts
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
|
+
|
|
4
|
+
// src/shared/attribution.ts
|
|
5
|
+
var ok = { ok: true, code: "ok", message: "attributed" };
|
|
6
|
+
function deny(code, message) {
|
|
7
|
+
return { ok: false, code, message };
|
|
8
|
+
}
|
|
9
|
+
function isRecord(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
function str(value) {
|
|
13
|
+
return typeof value === "string" ? value.trim() : "";
|
|
14
|
+
}
|
|
15
|
+
var PLACEHOLDER_IDENTITIES = /* @__PURE__ */ new Set([
|
|
16
|
+
"me",
|
|
17
|
+
"self",
|
|
18
|
+
"myself",
|
|
19
|
+
"i",
|
|
20
|
+
"agent",
|
|
21
|
+
"the agent",
|
|
22
|
+
"an agent",
|
|
23
|
+
"assistant",
|
|
24
|
+
"ai",
|
|
25
|
+
"an ai",
|
|
26
|
+
"the ai",
|
|
27
|
+
"bot",
|
|
28
|
+
"chatbot",
|
|
29
|
+
"llm",
|
|
30
|
+
"model",
|
|
31
|
+
"admin",
|
|
32
|
+
"administrator",
|
|
33
|
+
"support",
|
|
34
|
+
"askexe",
|
|
35
|
+
"exe-os",
|
|
36
|
+
"system",
|
|
37
|
+
"automated",
|
|
38
|
+
"auto",
|
|
39
|
+
"user",
|
|
40
|
+
"someone",
|
|
41
|
+
"somebody",
|
|
42
|
+
"team",
|
|
43
|
+
"staff",
|
|
44
|
+
"n/a",
|
|
45
|
+
"na",
|
|
46
|
+
"none",
|
|
47
|
+
"null",
|
|
48
|
+
"unknown",
|
|
49
|
+
"tbd",
|
|
50
|
+
"todo",
|
|
51
|
+
"test",
|
|
52
|
+
"testing",
|
|
53
|
+
"claude",
|
|
54
|
+
"gpt",
|
|
55
|
+
"openai",
|
|
56
|
+
"anthropic"
|
|
57
|
+
]);
|
|
58
|
+
function isPlaceholderIdentity(name) {
|
|
59
|
+
return PLACEHOLDER_IDENTITIES.has(name.trim().toLowerCase());
|
|
60
|
+
}
|
|
61
|
+
var UNRESOLVED_IDENTITIES = /* @__PURE__ */ new Set(["default"]);
|
|
62
|
+
function isUnresolvedIdentity(name) {
|
|
63
|
+
return UNRESOLVED_IDENTITIES.has(name.trim().toLowerCase());
|
|
64
|
+
}
|
|
65
|
+
var MODEL_FAMILIES = [
|
|
66
|
+
"claude",
|
|
67
|
+
"gpt",
|
|
68
|
+
"o1",
|
|
69
|
+
"o3",
|
|
70
|
+
"o4",
|
|
71
|
+
"codex",
|
|
72
|
+
"gemini",
|
|
73
|
+
"glm",
|
|
74
|
+
"minimax",
|
|
75
|
+
"qwen",
|
|
76
|
+
"llama",
|
|
77
|
+
"mistral",
|
|
78
|
+
"mixtral",
|
|
79
|
+
"deepseek",
|
|
80
|
+
"grok",
|
|
81
|
+
"kimi",
|
|
82
|
+
"command",
|
|
83
|
+
"phi",
|
|
84
|
+
"nova",
|
|
85
|
+
"sonar"
|
|
86
|
+
];
|
|
87
|
+
var MODEL_SHAPE = /^[a-z][a-z0-9]*(?:[-._][a-z0-9]+)*$/i;
|
|
88
|
+
var HAS_VERSION = /\d/;
|
|
89
|
+
function assessModel(raw) {
|
|
90
|
+
const model = str(raw).toLowerCase();
|
|
91
|
+
if (!model) {
|
|
92
|
+
return deny("attribution_model_missing", "attribution requires the model that produced this record");
|
|
93
|
+
}
|
|
94
|
+
if (isPlaceholderIdentity(model)) {
|
|
95
|
+
return deny(
|
|
96
|
+
"attribution_model_placeholder",
|
|
97
|
+
`"${model}" names a vendor or a category, not a model. Give the model id, e.g. claude-opus-5, gpt-5.5, glm-5.2`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (!MODEL_SHAPE.test(model)) {
|
|
101
|
+
return deny("attribution_model_unrecognised", `"${model}" is not a model id`);
|
|
102
|
+
}
|
|
103
|
+
const family = MODEL_FAMILIES.find((f) => model === f || model.startsWith(`${f}-`) || model.startsWith(`${f}.`));
|
|
104
|
+
if (!family) {
|
|
105
|
+
return deny(
|
|
106
|
+
"attribution_model_unrecognised",
|
|
107
|
+
`"${model}" does not name a known model family (${MODEL_FAMILIES.slice(0, 6).join(", ")}, \u2026). If this is a new family, add it to MODEL_FAMILIES rather than weakening the check`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
if (!HAS_VERSION.test(model)) {
|
|
111
|
+
return deny(
|
|
112
|
+
"attribution_model_unrecognised",
|
|
113
|
+
`"${model}" names a family but not a version \u2014 "claude" is not a model, "claude-opus-5" is`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return ok;
|
|
117
|
+
}
|
|
118
|
+
var FUTURE_SKEW_MS = 5 * 60 * 1e3;
|
|
119
|
+
function assessObservedAt(raw, now) {
|
|
120
|
+
const text = str(raw);
|
|
121
|
+
if (!text) {
|
|
122
|
+
return deny(
|
|
123
|
+
"attribution_observed_at_missing",
|
|
124
|
+
"attribution requires observed_at: when the behaviour or evidence was ACTUALLY SEEN, which is not necessarily now"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const ms = Date.parse(text);
|
|
128
|
+
if (!Number.isFinite(ms)) {
|
|
129
|
+
return deny("attribution_observed_at_invalid", `observed_at "${text}" is not a parseable timestamp`);
|
|
130
|
+
}
|
|
131
|
+
if (ms > now + FUTURE_SKEW_MS) {
|
|
132
|
+
return deny("attribution_observed_at_in_future", "observed_at is in the future \u2014 nothing was observed then");
|
|
133
|
+
}
|
|
134
|
+
return ok;
|
|
135
|
+
}
|
|
136
|
+
var HEX_SHA = /^[0-9a-f]{7,64}$/i;
|
|
137
|
+
function assessAttribution(raw, purpose, context = {}) {
|
|
138
|
+
if (raw === void 0 || raw === null || raw === "") {
|
|
139
|
+
return deny(
|
|
140
|
+
"attribution_missing",
|
|
141
|
+
`this ${purpose} requires attribution: which agent produced it, with which model, and when the evidence was observed`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
let attribution = raw;
|
|
145
|
+
if (typeof raw === "string") {
|
|
146
|
+
try {
|
|
147
|
+
attribution = JSON.parse(raw);
|
|
148
|
+
} catch {
|
|
149
|
+
return deny("attribution_malformed", "attribution must be valid JSON");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (!isRecord(attribution)) {
|
|
153
|
+
return deny("attribution_malformed", "attribution must be an object");
|
|
154
|
+
}
|
|
155
|
+
const agent = str(attribution.agent);
|
|
156
|
+
if (!agent) {
|
|
157
|
+
return deny("attribution_agent_missing", "attribution requires the agent identity that produced this record");
|
|
158
|
+
}
|
|
159
|
+
if (isPlaceholderIdentity(agent)) {
|
|
160
|
+
return deny(
|
|
161
|
+
"attribution_agent_placeholder",
|
|
162
|
+
`"${agent}" is a role, not an identity. Records attributed to "admin" are exactly why past verdicts cannot be traced to anyone \u2014 name the actual agent`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
if (purpose === "verdict" && isUnresolvedIdentity(agent)) {
|
|
166
|
+
return deny(
|
|
167
|
+
"attribution_agent_placeholder",
|
|
168
|
+
`"${agent}" is the identity resolver's fallback, not an agent \u2014 it is what a call from the launchd daemon carries when there is no active-agent marker, no tmux session and no AGENT_ID. A verdict signed with it is signed by nobody. Pass the real employee name of whoever made this call`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
const modelResult = assessModel(attribution.model);
|
|
172
|
+
if (!modelResult.ok) return modelResult;
|
|
173
|
+
const now = context.now ?? Date.now();
|
|
174
|
+
const observedResult = assessObservedAt(attribution.observed_at, now);
|
|
175
|
+
if (!observedResult.ok) return observedResult;
|
|
176
|
+
if (purpose === "verdict") {
|
|
177
|
+
const ref = str(attribution.evidence_ref);
|
|
178
|
+
if (!ref) {
|
|
179
|
+
return deny(
|
|
180
|
+
"attribution_evidence_ref_missing",
|
|
181
|
+
"a verdict requires evidence_ref: the commit you actually read the evidence at. main moves several times a day, so a verdict against an unnamed ref cannot be checked or reproduced"
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
if (!HEX_SHA.test(ref)) {
|
|
185
|
+
return deny("attribution_evidence_ref_invalid", `evidence_ref "${ref}" is not a commit sha`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const second = attribution.second_opinion;
|
|
189
|
+
if (second !== void 0 && second !== null && second !== "") {
|
|
190
|
+
if (!isRecord(second)) {
|
|
191
|
+
return deny("second_opinion_malformed", "second_opinion must be an object with model and verdict");
|
|
192
|
+
}
|
|
193
|
+
const secondModel = assessModel(second.model);
|
|
194
|
+
if (!secondModel.ok) {
|
|
195
|
+
return deny("second_opinion_malformed", `second_opinion model: ${secondModel.message}`);
|
|
196
|
+
}
|
|
197
|
+
const verdict = str(second.verdict);
|
|
198
|
+
if (verdict !== "confirmed" && verdict !== "refuted") {
|
|
199
|
+
return deny("second_opinion_malformed", "second_opinion.verdict must be 'confirmed' or 'refuted'");
|
|
200
|
+
}
|
|
201
|
+
if (str(second.model).toLowerCase() === str(attribution.model).toLowerCase()) {
|
|
202
|
+
return deny(
|
|
203
|
+
"second_opinion_same_model",
|
|
204
|
+
"second_opinion.model must differ from the model that produced the record \u2014 a model confirming itself is not an adversarial review"
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
if (verdict === "refuted") {
|
|
208
|
+
return deny(
|
|
209
|
+
"second_opinion_refuted",
|
|
210
|
+
"the second opinion REFUTED this verdict \u2014 resolve the disagreement before recording it, or record the refutation as a note instead"
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return ok;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/shared/verification-artifact.ts
|
|
218
|
+
var VERIFIER_BACKED_DISPOSITIONS = /* @__PURE__ */ new Set(["not_a_defect", "superseded"]);
|
|
219
|
+
var MIN_DISPOSITION_REASON_CHARS = 40;
|
|
220
|
+
var MIN_WONTFIX_REASON_CHARS = 120;
|
|
221
|
+
var MIN_COVERAGE_EVIDENCE_CHARS = 20;
|
|
222
|
+
var ok2 = { ok: true, code: "ok", message: "verified" };
|
|
223
|
+
function deny2(code, message) {
|
|
224
|
+
return { ok: false, code, message };
|
|
225
|
+
}
|
|
226
|
+
var HEX_SHA2 = /^[0-9a-f]{7,64}$/i;
|
|
227
|
+
var MIN_OBSERVATION_CHARS = 40;
|
|
228
|
+
function isRecord2(value) {
|
|
229
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
230
|
+
}
|
|
231
|
+
function str2(value) {
|
|
232
|
+
return typeof value === "string" ? value.trim() : "";
|
|
233
|
+
}
|
|
234
|
+
function num(value) {
|
|
235
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
236
|
+
}
|
|
237
|
+
function isSubstantiveCommit(substance) {
|
|
238
|
+
if (!isRecord2(substance)) return false;
|
|
239
|
+
const added = num(substance.added);
|
|
240
|
+
const deleted = num(substance.deleted);
|
|
241
|
+
const substantive = num(substance.substantive_added);
|
|
242
|
+
const sourceFiles = num(substance.source_files);
|
|
243
|
+
if (added === null || deleted === null || substantive === null || sourceFiles === null) return false;
|
|
244
|
+
if (added < 0 || deleted < 0 || substantive < 0 || sourceFiles < 0) return false;
|
|
245
|
+
if (substantive > added) return false;
|
|
246
|
+
if (sourceFiles < 1) return false;
|
|
247
|
+
if (substantive < 1 && deleted < 1) return false;
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
function isSubstantiveTestFix(substance) {
|
|
251
|
+
if (!isRecord2(substance)) return false;
|
|
252
|
+
const added = num(substance.added);
|
|
253
|
+
const deleted = num(substance.deleted);
|
|
254
|
+
const testFiles = num(substance.test_files);
|
|
255
|
+
const testSubstantive = num(substance.test_substantive_added);
|
|
256
|
+
if (added === null || deleted === null || testFiles === null || testSubstantive === null) return false;
|
|
257
|
+
if (added < 0 || deleted < 0 || testFiles < 0 || testSubstantive < 0) return false;
|
|
258
|
+
if (testSubstantive > added) return false;
|
|
259
|
+
if (testFiles < 1) return false;
|
|
260
|
+
if (testSubstantive < 1 && deleted < 1) return false;
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
var VERDICT_ONLY_OBSERVATION = /^(?:it(?:'s| is)? |the bug (?:is|was) |this (?:is|was) )?(?:fixed|resolved|working|done|good|ok|verified|closed)\b/i;
|
|
264
|
+
var HEDGED_OBSERVATION = /\b(?:looks?|look|seems?|appears?)\s+(?:to\s+be\s+)?(?:fine|good|ok|okay|right|healthy|correct|normal)\b|\ball\s+(?:good|fine|clear)\b|\bno\s+issues\b|\bseems?\s+fine\b/i;
|
|
265
|
+
function assessObservation(raw) {
|
|
266
|
+
const observation = str2(raw).replace(/\s+/g, " ");
|
|
267
|
+
if (observation.length < MIN_OBSERVATION_CHARS) {
|
|
268
|
+
return deny2(
|
|
269
|
+
"manual_observation_too_thin",
|
|
270
|
+
"verification requires an observation describing the defect's absence"
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
if (VERDICT_ONLY_OBSERVATION.test(observation) || HEDGED_OBSERVATION.test(observation)) {
|
|
274
|
+
return deny2(
|
|
275
|
+
"observation_not_absence",
|
|
276
|
+
"the observation must report what was OBSERVED that shows the defect is absent \u2014 a verdict ('it is fixed') or a hedge ('looks fine') is not an observation"
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
return ok2;
|
|
280
|
+
}
|
|
281
|
+
function assessVerifier(raw, context) {
|
|
282
|
+
const verifier = str2(raw);
|
|
283
|
+
if (!verifier) {
|
|
284
|
+
return deny2("manual_verifier_missing", "this close requires a named verifier");
|
|
285
|
+
}
|
|
286
|
+
if (isPlaceholderIdentity(verifier)) {
|
|
287
|
+
return deny2(
|
|
288
|
+
"manual_verifier_placeholder",
|
|
289
|
+
`"${verifier}" is a role, not an identity. Records attested by "admin" are exactly why past verdicts cannot be traced to anyone \u2014 name the actual person or employee`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
const authors = (context.authorIdentities ?? []).map((a) => str2(a).toLowerCase()).filter(Boolean);
|
|
293
|
+
if (authors.includes(verifier.toLowerCase())) {
|
|
294
|
+
return deny2(
|
|
295
|
+
"manual_verifier_is_author",
|
|
296
|
+
"verification must be attested by someone other than the record's author or assignee"
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
return ok2;
|
|
300
|
+
}
|
|
301
|
+
function parseTimestamp(raw) {
|
|
302
|
+
const text = str2(raw);
|
|
303
|
+
if (!text) return null;
|
|
304
|
+
const ms = Date.parse(text);
|
|
305
|
+
return Number.isFinite(ms) ? ms : null;
|
|
306
|
+
}
|
|
307
|
+
function assessProbes(raw, claimType) {
|
|
308
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
309
|
+
return deny2(
|
|
310
|
+
"ops_probe_missing",
|
|
311
|
+
"ops_transcript requires at least one probe: the verbatim command, its verbatim output, the host it ran against, and when it ran"
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
const timestamps = [];
|
|
315
|
+
for (let i = 0; i < raw.length; i += 1) {
|
|
316
|
+
const probe = raw[i];
|
|
317
|
+
const where = `probe ${i + 1}`;
|
|
318
|
+
if (!isRecord2(probe)) {
|
|
319
|
+
return deny2("ops_probe_malformed", `${where} is not an object`);
|
|
320
|
+
}
|
|
321
|
+
if (!str2(probe.command)) {
|
|
322
|
+
return deny2("ops_probe_malformed", `${where} has no command \u2014 record the command verbatim, as typed`);
|
|
323
|
+
}
|
|
324
|
+
if (!str2(probe.output)) {
|
|
325
|
+
return deny2(
|
|
326
|
+
"ops_probe_malformed",
|
|
327
|
+
`${where} has no command output \u2014 paste the output verbatim; a probe with nothing to show is a summary, not evidence`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
if (!str2(probe.host)) {
|
|
331
|
+
return deny2("ops_probe_malformed", `${where} does not name the host or system it ran against`);
|
|
332
|
+
}
|
|
333
|
+
const ts = parseTimestamp(probe.ran_at);
|
|
334
|
+
if (ts === null) {
|
|
335
|
+
return deny2("ops_probe_malformed", `${where} has no valid ran_at timestamp`);
|
|
336
|
+
}
|
|
337
|
+
timestamps.push(ts);
|
|
338
|
+
}
|
|
339
|
+
if (claimType === "ongoing_state") {
|
|
340
|
+
const distinct = new Set(timestamps);
|
|
341
|
+
if (raw.length < 2 || distinct.size < 2) {
|
|
342
|
+
return deny2(
|
|
343
|
+
"ops_claim_needs_multiple_probes",
|
|
344
|
+
"a claim about ONGOING state needs at least two probes taken at two distinct times \u2014 one sample cannot evidence a continuing condition"
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return ok2;
|
|
349
|
+
}
|
|
350
|
+
function assessVerificationArtifact(raw, context = {}) {
|
|
351
|
+
if (raw === void 0 || raw === null || raw === "") {
|
|
352
|
+
return deny2("artifact_missing", "closing requires a verification artifact showing the defect is absent");
|
|
353
|
+
}
|
|
354
|
+
let artifact = raw;
|
|
355
|
+
if (typeof raw === "string") {
|
|
356
|
+
try {
|
|
357
|
+
artifact = JSON.parse(raw);
|
|
358
|
+
} catch {
|
|
359
|
+
return deny2("artifact_malformed", "verification artifact must be valid JSON");
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (!isRecord2(artifact)) {
|
|
363
|
+
return deny2("artifact_malformed", "verification artifact must be an object");
|
|
364
|
+
}
|
|
365
|
+
const kind = str2(artifact.kind);
|
|
366
|
+
if (kind !== "regression_test" && kind !== "manual" && kind !== "ops_transcript") {
|
|
367
|
+
return deny2("artifact_unknown_kind", "verification artifact kind must be regression_test, manual or ops_transcript");
|
|
368
|
+
}
|
|
369
|
+
if (kind === "ops_transcript") {
|
|
370
|
+
return assessOpsTranscript(artifact, context);
|
|
371
|
+
}
|
|
372
|
+
const declaredLayer = str2(artifact.defect_layer) || "production";
|
|
373
|
+
if (declaredLayer !== "production" && declaredLayer !== "test_harness") {
|
|
374
|
+
return deny2("artifact_malformed", "defect_layer must be production or test_harness");
|
|
375
|
+
}
|
|
376
|
+
if (declaredLayer === "test_harness") {
|
|
377
|
+
if (!isSubstantiveTestFix(artifact.substance)) {
|
|
378
|
+
return deny2(
|
|
379
|
+
"test_fix_not_substantive",
|
|
380
|
+
"defect_layer=test_harness was declared, but the fix commit changes no executable test/harness code (comment-only, whitespace-only or docs-only diffs are not fixes at any layer)"
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
if (!str2(artifact.test_id)) {
|
|
384
|
+
return deny2(
|
|
385
|
+
"test_fix_missing_assertion",
|
|
386
|
+
"defect_layer=test_harness requires test_id \u2014 name the test whose behaviour is the evidence"
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
if (str2(artifact.reverted_result) !== "fail") {
|
|
390
|
+
return deny2(
|
|
391
|
+
"test_fix_missing_assertion",
|
|
392
|
+
"defect_layer=test_harness requires reverted_result='fail' \u2014 the observed result of re-running the named test with the fix reverted. A test-only diff that does not go red when removed evidences nothing"
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
} else if (!isSubstantiveCommit(artifact.substance)) {
|
|
396
|
+
return deny2(
|
|
397
|
+
"commit_not_substantive",
|
|
398
|
+
"the fix commit changes no executable production source (comment-only, whitespace-only, or test-only diffs are not fixes). If the DEFECT ITSELF is in the test/harness layer, declare defect_layer='test_harness' and supply test_id and reverted_result"
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
if (kind === "regression_test") {
|
|
402
|
+
const testId = str2(artifact.test_id);
|
|
403
|
+
const fixCommit = str2(artifact.fix_commit);
|
|
404
|
+
const parentCommit = str2(artifact.parent_commit);
|
|
405
|
+
if (!testId || !HEX_SHA2.test(fixCommit) || !HEX_SHA2.test(parentCommit)) {
|
|
406
|
+
return deny2("artifact_malformed", "regression_test requires test_id, fix_commit and parent_commit");
|
|
407
|
+
}
|
|
408
|
+
if (fixCommit.toLowerCase() === parentCommit.toLowerCase()) {
|
|
409
|
+
return deny2("parent_equals_fix", "parent_commit must be the commit BEFORE the fix");
|
|
410
|
+
}
|
|
411
|
+
if (str2(artifact.parent_result) !== "fail") {
|
|
412
|
+
return deny2(
|
|
413
|
+
"test_did_not_fail_at_parent",
|
|
414
|
+
"the named test must FAIL at the parent commit \u2014 a test that already passed does not detect the defect"
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
if (str2(artifact.fix_result) !== "pass") {
|
|
418
|
+
return deny2("test_did_not_pass_at_fix", "the named test must PASS at the fix commit");
|
|
419
|
+
}
|
|
420
|
+
return ok2;
|
|
421
|
+
}
|
|
422
|
+
const verifierResult = assessVerifier(artifact.verifier, context);
|
|
423
|
+
if (!verifierResult.ok) return verifierResult;
|
|
424
|
+
if (!str2(artifact.method)) {
|
|
425
|
+
return deny2("artifact_malformed", "manual verification requires a method");
|
|
426
|
+
}
|
|
427
|
+
const observationResult = assessObservation(artifact.observation);
|
|
428
|
+
if (!observationResult.ok) return observationResult;
|
|
429
|
+
if (!HEX_SHA2.test(str2(artifact.fix_commit))) {
|
|
430
|
+
return deny2("artifact_malformed", "manual verification requires a fix_commit");
|
|
431
|
+
}
|
|
432
|
+
return ok2;
|
|
433
|
+
}
|
|
434
|
+
function assessOpsTranscript(artifact, context) {
|
|
435
|
+
const verifierResult = assessVerifier(artifact.verifier, context);
|
|
436
|
+
if (!verifierResult.ok) return verifierResult;
|
|
437
|
+
const claimType = str2(artifact.claim_type);
|
|
438
|
+
if (claimType !== "point_in_time" && claimType !== "ongoing_state") {
|
|
439
|
+
return deny2(
|
|
440
|
+
"artifact_malformed",
|
|
441
|
+
"ops_transcript requires claim_type: 'point_in_time' for a fact true when observed, 'ongoing_state' for a claim that a condition holds"
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
const probeResult = assessProbes(artifact.probes, claimType);
|
|
445
|
+
if (!probeResult.ok) return probeResult;
|
|
446
|
+
const observationResult = assessObservation(artifact.observation);
|
|
447
|
+
if (!observationResult.ok) return observationResult;
|
|
448
|
+
const fixCommit = str2(artifact.fix_commit);
|
|
449
|
+
if (fixCommit && !HEX_SHA2.test(fixCommit)) {
|
|
450
|
+
return deny2("artifact_malformed", "ops_transcript fix_commit, when supplied, must be a commit sha");
|
|
451
|
+
}
|
|
452
|
+
return ok2;
|
|
453
|
+
}
|
|
454
|
+
function assessDisposition(disposition, input) {
|
|
455
|
+
const reason = str2(input.disposition_reason).replace(/\s+/g, " ");
|
|
456
|
+
if (!reason) {
|
|
457
|
+
return deny2(
|
|
458
|
+
"disposition_reason_missing",
|
|
459
|
+
`closing as ${disposition} requires disposition_reason \u2014 state why this record has nothing to fix`
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
if (reason.length < MIN_DISPOSITION_REASON_CHARS) {
|
|
463
|
+
return deny2(
|
|
464
|
+
"disposition_reason_too_thin",
|
|
465
|
+
`closing as ${disposition} requires a reason that explains the call, not a label`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
if (VERDICT_ONLY_OBSERVATION.test(reason) || HEDGED_OBSERVATION.test(reason)) {
|
|
469
|
+
return deny2(
|
|
470
|
+
"observation_not_absence",
|
|
471
|
+
"the disposition reason must explain what makes this a non-defect \u2014 a verdict or a hedge is not a reason"
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
if (disposition === "wontfix" && reason.length < MIN_WONTFIX_REASON_CHARS) {
|
|
475
|
+
return deny2(
|
|
476
|
+
"wontfix_reason_omits_live_behaviour",
|
|
477
|
+
"closing as wontfix requires the reason to describe the LIVE BEHAVIOUR the user will still hit, not only the decision to decline. One honest sentence naming what stays broken is enough \u2014 but it has to be there, because this record is about to stop being read"
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
if (disposition === "superseded") {
|
|
481
|
+
if (!str2(input.superseded_by)) {
|
|
482
|
+
return deny2(
|
|
483
|
+
"superseded_by_missing",
|
|
484
|
+
"closing as superseded requires superseded_by \u2014 name the record that replaces this one, so the claim is checkable"
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
const coverage = assessSupersedingCoverage(input);
|
|
488
|
+
if (!coverage.ok) return coverage;
|
|
489
|
+
}
|
|
490
|
+
if (VERIFIER_BACKED_DISPOSITIONS.has(disposition)) {
|
|
491
|
+
const verifierResult = assessVerifier(input.disposition_verifier, input.context ?? {});
|
|
492
|
+
if (!verifierResult.ok) return verifierResult;
|
|
493
|
+
}
|
|
494
|
+
return ok2;
|
|
495
|
+
}
|
|
496
|
+
function assessSupersedingCoverage(input) {
|
|
497
|
+
const declared = parseSymptomIds(input.symptoms);
|
|
498
|
+
if (declared.length === 0) {
|
|
499
|
+
return deny2(
|
|
500
|
+
"superseded_symptoms_not_enumerated",
|
|
501
|
+
"closing as superseded requires the record's symptoms to be enumerated, so coverage by the superseding record can be checked one by one. An unenumerated record cannot be shown to be fully covered"
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
const entries = parseCoverageEntries(input.superseded_coverage);
|
|
505
|
+
const thin = entries.filter(
|
|
506
|
+
(e) => declared.includes(e.id) && e.evidence.length < MIN_COVERAGE_EVIDENCE_CHARS
|
|
507
|
+
);
|
|
508
|
+
if (thin.length > 0) {
|
|
509
|
+
return deny2(
|
|
510
|
+
"superseded_coverage_evidence_missing",
|
|
511
|
+
`${thin.length} symptom(s) are listed as covered with no evidence naming WHERE ${str2(input.superseded_by)} covers them: ${thin.map((e) => e.id).join(", ")}`
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
const covered = new Set(entries.map((e) => e.id));
|
|
515
|
+
const survivors = declared.filter((id) => !covered.has(id));
|
|
516
|
+
if (survivors.length > 0) {
|
|
517
|
+
return deny2(
|
|
518
|
+
"superseded_coverage_incomplete",
|
|
519
|
+
`${survivors.length} of ${declared.length} symptoms are NOT covered by ${str2(input.superseded_by)}: ${survivors.join(", ")}. Partial coverage supersedes nothing \u2014 keep this record open with those symptoms as its remaining scope, or supply coverage evidence for each`
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
return ok2;
|
|
523
|
+
}
|
|
524
|
+
function parseCoverageEntries(raw) {
|
|
525
|
+
let value = raw;
|
|
526
|
+
if (typeof raw === "string") {
|
|
527
|
+
if (!raw.trim()) return [];
|
|
528
|
+
try {
|
|
529
|
+
value = JSON.parse(raw);
|
|
530
|
+
} catch {
|
|
531
|
+
return [];
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (!Array.isArray(value)) return [];
|
|
535
|
+
const entries = [];
|
|
536
|
+
for (const entry of value) {
|
|
537
|
+
if (!isRecord2(entry)) continue;
|
|
538
|
+
const id = str2(entry.id);
|
|
539
|
+
if (!id) continue;
|
|
540
|
+
entries.push({ id, evidence: str2(entry.evidence) });
|
|
541
|
+
}
|
|
542
|
+
return entries;
|
|
543
|
+
}
|
|
544
|
+
function parseSymptomIds(raw) {
|
|
545
|
+
let value = raw;
|
|
546
|
+
if (typeof raw === "string") {
|
|
547
|
+
if (!raw.trim()) return [];
|
|
548
|
+
try {
|
|
549
|
+
value = JSON.parse(raw);
|
|
550
|
+
} catch {
|
|
551
|
+
return [];
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (!Array.isArray(value)) return [];
|
|
555
|
+
const ids = [];
|
|
556
|
+
for (const entry of value) {
|
|
557
|
+
if (typeof entry === "string" && entry.trim()) ids.push(entry.trim());
|
|
558
|
+
else if (isRecord2(entry) && str2(entry.id)) ids.push(str2(entry.id));
|
|
559
|
+
}
|
|
560
|
+
return ids;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/lib/verification-evidence.ts
|
|
564
|
+
var TEST_PATH = /(?:^|\/)(?:tests?|__tests__|__mocks__|e2e|fixtures)\//i;
|
|
565
|
+
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/i;
|
|
566
|
+
var NON_SOURCE_FILE = /\.(?:md|mdx|txt|rst|adoc|snap|lock)$/i;
|
|
567
|
+
var COMMENT_LINE = /^(?:\/\/|\/\*|\*\/|\*(?!\/)|#|--|<!--|-->)/;
|
|
568
|
+
function isTestPath(path) {
|
|
569
|
+
return TEST_PATH.test(path) || TEST_FILE.test(path);
|
|
570
|
+
}
|
|
571
|
+
function isNonSourcePath(path) {
|
|
572
|
+
return NON_SOURCE_FILE.test(path);
|
|
573
|
+
}
|
|
574
|
+
function isCommentOrBlank(line) {
|
|
575
|
+
const trimmed = line.trim();
|
|
576
|
+
if (!trimmed) return true;
|
|
577
|
+
return COMMENT_LINE.test(trimmed);
|
|
578
|
+
}
|
|
579
|
+
function measureUnifiedDiff(diff) {
|
|
580
|
+
let added = 0;
|
|
581
|
+
let deleted = 0;
|
|
582
|
+
let substantiveAdded = 0;
|
|
583
|
+
let testSubstantiveAdded = 0;
|
|
584
|
+
const sourceFiles = /* @__PURE__ */ new Set();
|
|
585
|
+
const testFiles = /* @__PURE__ */ new Set();
|
|
586
|
+
let currentPath = "";
|
|
587
|
+
let currentIsSource = false;
|
|
588
|
+
let currentIsTest = false;
|
|
589
|
+
for (const line of diff.split(/\r?\n/)) {
|
|
590
|
+
if (line.startsWith("+++ ")) {
|
|
591
|
+
const path = line.slice(4).replace(/^b\//, "").trim();
|
|
592
|
+
currentPath = path === "/dev/null" ? "" : path;
|
|
593
|
+
const isDocs = Boolean(currentPath) && isNonSourcePath(currentPath);
|
|
594
|
+
currentIsSource = Boolean(currentPath) && !isTestPath(currentPath) && !isDocs;
|
|
595
|
+
currentIsTest = Boolean(currentPath) && isTestPath(currentPath) && !isDocs;
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
if (line.startsWith("--- ") || line.startsWith("diff ") || line.startsWith("index ") || line.startsWith("@@")) {
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
if (line.startsWith("+")) {
|
|
602
|
+
added += 1;
|
|
603
|
+
const content = line.slice(1);
|
|
604
|
+
if (currentIsSource) {
|
|
605
|
+
if (!isCommentOrBlank(content)) {
|
|
606
|
+
substantiveAdded += 1;
|
|
607
|
+
sourceFiles.add(currentPath);
|
|
608
|
+
}
|
|
609
|
+
} else if (currentIsTest) {
|
|
610
|
+
if (!isCommentOrBlank(content)) {
|
|
611
|
+
testSubstantiveAdded += 1;
|
|
612
|
+
testFiles.add(currentPath);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
} else if (line.startsWith("-")) {
|
|
616
|
+
deleted += 1;
|
|
617
|
+
const content = line.slice(1);
|
|
618
|
+
if (currentIsSource) {
|
|
619
|
+
if (!isCommentOrBlank(content)) sourceFiles.add(currentPath);
|
|
620
|
+
} else if (currentIsTest) {
|
|
621
|
+
if (!isCommentOrBlank(content)) testFiles.add(currentPath);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
added,
|
|
627
|
+
deleted,
|
|
628
|
+
substantive_added: substantiveAdded,
|
|
629
|
+
source_files: sourceFiles.size,
|
|
630
|
+
test_files: testFiles.size,
|
|
631
|
+
test_substantive_added: testSubstantiveAdded
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
function measureCommitSubstance(sha, cwd) {
|
|
635
|
+
if (!/^[0-9a-f]{7,64}$/i.test(sha)) return null;
|
|
636
|
+
try {
|
|
637
|
+
const diff = execFileSync(
|
|
638
|
+
"git",
|
|
639
|
+
["show", "--format=", "--unified=0", "--no-color", sha],
|
|
640
|
+
{ cwd, encoding: "utf8", timeout: 15e3, maxBuffer: 32 * 1024 * 1024 }
|
|
641
|
+
);
|
|
642
|
+
return measureUnifiedDiff(diff);
|
|
643
|
+
} catch {
|
|
644
|
+
return null;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function resolveParentCommit(sha, cwd) {
|
|
648
|
+
if (!/^[0-9a-f]{7,64}$/i.test(sha)) return null;
|
|
649
|
+
try {
|
|
650
|
+
const out = execFileSync("git", ["rev-parse", `${sha}^`], {
|
|
651
|
+
cwd,
|
|
652
|
+
encoding: "utf8",
|
|
653
|
+
timeout: 1e4
|
|
654
|
+
});
|
|
655
|
+
const parent = out.trim();
|
|
656
|
+
return /^[0-9a-f]{7,64}$/i.test(parent) ? parent : null;
|
|
657
|
+
} catch {
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
function fail(code, message) {
|
|
662
|
+
return { ok: false, code, message };
|
|
663
|
+
}
|
|
664
|
+
var PLACEHOLDER_VERIFIERS = /* @__PURE__ */ new Set([
|
|
665
|
+
"me",
|
|
666
|
+
"self",
|
|
667
|
+
"myself",
|
|
668
|
+
"i",
|
|
669
|
+
"agent",
|
|
670
|
+
"the agent",
|
|
671
|
+
"assistant",
|
|
672
|
+
"ai",
|
|
673
|
+
"bot",
|
|
674
|
+
"n/a",
|
|
675
|
+
"na",
|
|
676
|
+
"none",
|
|
677
|
+
"unknown",
|
|
678
|
+
"tbd",
|
|
679
|
+
"todo",
|
|
680
|
+
"system",
|
|
681
|
+
"automated",
|
|
682
|
+
"auto",
|
|
683
|
+
"claude",
|
|
684
|
+
"user",
|
|
685
|
+
"test",
|
|
686
|
+
"someone",
|
|
687
|
+
"team"
|
|
688
|
+
]);
|
|
689
|
+
var LOW_CONTENT_OBSERVATION = /^(?:it(?:'s| is)? |the bug (?:is|was) |this (?:is|was) )?(?:fixed|resolved|working|done|good|ok|verified|closed)\b/i;
|
|
690
|
+
function resolveCommit(sha, cwd) {
|
|
691
|
+
if (!/^[0-9a-f]{7,64}$/i.test(sha)) return null;
|
|
692
|
+
try {
|
|
693
|
+
const out = execFileSync("git", ["rev-parse", "--verify", `${sha}^{commit}`], {
|
|
694
|
+
cwd,
|
|
695
|
+
encoding: "utf8",
|
|
696
|
+
timeout: 1e4
|
|
697
|
+
}).trim();
|
|
698
|
+
return /^[0-9a-f]{40}$/i.test(out) ? out : null;
|
|
699
|
+
} catch {
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function checkVerifierName(raw) {
|
|
704
|
+
const verifier = (raw ?? "").trim();
|
|
705
|
+
if (!verifier) {
|
|
706
|
+
return { ok: false, result: fail("manual_verifier_missing", "verification requires a named verifier") };
|
|
707
|
+
}
|
|
708
|
+
if (PLACEHOLDER_VERIFIERS.has(verifier.toLowerCase())) {
|
|
709
|
+
return {
|
|
710
|
+
ok: false,
|
|
711
|
+
result: fail(
|
|
712
|
+
"manual_verifier_placeholder",
|
|
713
|
+
`"${verifier}" is not an identity. Name the person or employee who confirmed the defect is gone.`
|
|
714
|
+
)
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
return { ok: true, verifier };
|
|
718
|
+
}
|
|
719
|
+
function buildOpsTranscript(request, context) {
|
|
720
|
+
const verifierCheck = checkVerifierName(request.verifier);
|
|
721
|
+
if (!verifierCheck.ok) return verifierCheck.result;
|
|
722
|
+
const claimType = (request.claim_type ?? "").trim();
|
|
723
|
+
if (claimType !== "point_in_time" && claimType !== "ongoing_state") {
|
|
724
|
+
return fail(
|
|
725
|
+
"artifact_malformed",
|
|
726
|
+
"ops_transcript requires claim_type: 'point_in_time' for a fact true when observed, 'ongoing_state' for a claim that a condition holds (needs 2+ probes at distinct times)"
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
const probes = Array.isArray(request.probes) ? request.probes : [];
|
|
730
|
+
if (probes.length === 0) {
|
|
731
|
+
return fail(
|
|
732
|
+
"ops_probe_missing",
|
|
733
|
+
"ops_transcript requires at least one probe: {command, output, host, ran_at}, all verbatim"
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
const observation = (request.observation ?? "").replace(/\s+/g, " ").trim();
|
|
737
|
+
if (LOW_CONTENT_OBSERVATION.test(observation)) {
|
|
738
|
+
return fail(
|
|
739
|
+
"manual_observation_too_thin",
|
|
740
|
+
"the observation must describe what the output SHOWS that makes the defect absent \u2014 not that the bug is 'fixed'"
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
const artifact = {
|
|
744
|
+
kind: "ops_transcript",
|
|
745
|
+
verifier: verifierCheck.verifier,
|
|
746
|
+
claim_type: claimType,
|
|
747
|
+
probes: probes.map((p) => ({
|
|
748
|
+
command: (p?.command ?? "").trim(),
|
|
749
|
+
output: (p?.output ?? "").trim(),
|
|
750
|
+
host: (p?.host ?? "").trim(),
|
|
751
|
+
ran_at: (p?.ran_at ?? "").trim()
|
|
752
|
+
})),
|
|
753
|
+
observation,
|
|
754
|
+
...request.fix_commit?.trim() ? { fix_commit: request.fix_commit.trim() } : {}
|
|
755
|
+
};
|
|
756
|
+
const assessed = assessVerificationArtifact(artifact, context);
|
|
757
|
+
if (!assessed.ok) return fail(assessed.code, assessed.message);
|
|
758
|
+
return {
|
|
759
|
+
ok: true,
|
|
760
|
+
artifact,
|
|
761
|
+
substance: { added: 0, deleted: 0, substantive_added: 0, source_files: 0 }
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
function buildVerificationArtifact(request, context = {}) {
|
|
765
|
+
if (request.kind === "ops_transcript") {
|
|
766
|
+
return buildOpsTranscript(request, context);
|
|
767
|
+
}
|
|
768
|
+
const declaredLayer = (request.defect_layer ?? "").trim() || "production";
|
|
769
|
+
if (declaredLayer !== "production" && declaredLayer !== "test_harness") {
|
|
770
|
+
return fail("artifact_malformed", "defect_layer must be production or test_harness");
|
|
771
|
+
}
|
|
772
|
+
const defectLayer = declaredLayer;
|
|
773
|
+
let revertedResult;
|
|
774
|
+
if (defectLayer === "test_harness") {
|
|
775
|
+
const observed = (request.reverted_result ?? "").trim();
|
|
776
|
+
if (observed !== "fail" && observed !== "pass" && observed !== "error") {
|
|
777
|
+
return fail(
|
|
778
|
+
"test_fix_missing_assertion",
|
|
779
|
+
"defect_layer=test_harness requires reverted_result: the result you OBSERVED re-running the named test with the fix reverted. It must be 'fail' \u2014 a test-only diff that does not go red when removed evidences nothing."
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
revertedResult = observed;
|
|
783
|
+
}
|
|
784
|
+
const repo = request.repo_path;
|
|
785
|
+
if (!repo || !repo.trim()) {
|
|
786
|
+
return fail("repo_path_missing", "repo_path is required: the fix commit must be measured in the repository that contains it");
|
|
787
|
+
}
|
|
788
|
+
const fixCommit = resolveCommit(request.fix_commit ?? "", repo);
|
|
789
|
+
if (!fixCommit) {
|
|
790
|
+
return fail(
|
|
791
|
+
"fix_commit_unresolvable",
|
|
792
|
+
`fix_commit ${request.fix_commit} is not a commit in ${repo} \u2014 verification evidence cannot be measured, and will not be guessed`
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
const substance = measureCommitSubstance(fixCommit, repo);
|
|
796
|
+
if (!substance) {
|
|
797
|
+
return fail("commit_not_measurable", `git could not diff ${fixCommit} in ${repo}`);
|
|
798
|
+
}
|
|
799
|
+
let artifact;
|
|
800
|
+
if (request.kind === "regression_test") {
|
|
801
|
+
const parentCommit = resolveParentCommit(fixCommit, repo);
|
|
802
|
+
if (!parentCommit) {
|
|
803
|
+
return fail(
|
|
804
|
+
"parent_commit_unresolvable",
|
|
805
|
+
`could not resolve the first parent of ${fixCommit} \u2014 a regression_test artifact needs the tree WITHOUT the fix`
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
const testId = (request.test_id ?? "").trim();
|
|
809
|
+
if (!testId) return fail("artifact_malformed", "regression_test requires test_id (e.g. 'tests/foo.test.ts::rejects empty scope')");
|
|
810
|
+
const parentResult = (request.parent_result ?? "").trim();
|
|
811
|
+
const fixResult = (request.fix_result ?? "").trim();
|
|
812
|
+
if (parentResult !== "fail" && parentResult !== "pass" && parentResult !== "error") {
|
|
813
|
+
return fail("artifact_malformed", "parent_result must be the result you OBSERVED running the test at the parent commit: fail, pass or error");
|
|
814
|
+
}
|
|
815
|
+
if (fixResult !== "fail" && fixResult !== "pass" && fixResult !== "error") {
|
|
816
|
+
return fail("artifact_malformed", "fix_result must be the result you OBSERVED running the test at the fix commit: fail, pass or error");
|
|
817
|
+
}
|
|
818
|
+
const regression = {
|
|
819
|
+
kind: "regression_test",
|
|
820
|
+
test_id: testId,
|
|
821
|
+
fix_commit: fixCommit,
|
|
822
|
+
parent_commit: parentCommit,
|
|
823
|
+
parent_result: parentResult,
|
|
824
|
+
fix_result: fixResult,
|
|
825
|
+
substance,
|
|
826
|
+
...defectLayer === "test_harness" ? { defect_layer: defectLayer, reverted_result: revertedResult } : {}
|
|
827
|
+
};
|
|
828
|
+
artifact = regression;
|
|
829
|
+
} else if (request.kind === "manual") {
|
|
830
|
+
const verifierCheck = checkVerifierName(request.verifier);
|
|
831
|
+
if (!verifierCheck.ok) return verifierCheck.result;
|
|
832
|
+
const verifier = verifierCheck.verifier;
|
|
833
|
+
const method = (request.method ?? "").trim();
|
|
834
|
+
if (!method) return fail("artifact_malformed", "manual verification requires a method someone else could repeat");
|
|
835
|
+
const observation = (request.observation ?? "").replace(/\s+/g, " ").trim();
|
|
836
|
+
if (LOW_CONTENT_OBSERVATION.test(observation)) {
|
|
837
|
+
return fail(
|
|
838
|
+
"manual_observation_too_thin",
|
|
839
|
+
"the observation must describe what you saw that shows the DEFECT IS ABSENT \u2014 not that the bug is 'fixed'"
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
if (observation.toLowerCase() === method.toLowerCase()) {
|
|
843
|
+
return fail("manual_observation_too_thin", "the observation must say what you saw, not repeat the method");
|
|
844
|
+
}
|
|
845
|
+
const manual = {
|
|
846
|
+
kind: "manual",
|
|
847
|
+
verifier,
|
|
848
|
+
method,
|
|
849
|
+
observation,
|
|
850
|
+
fix_commit: fixCommit,
|
|
851
|
+
substance,
|
|
852
|
+
...defectLayer === "test_harness" ? { defect_layer: defectLayer, test_id: (request.test_id ?? "").trim(), reverted_result: revertedResult } : {}
|
|
853
|
+
};
|
|
854
|
+
artifact = manual;
|
|
855
|
+
} else {
|
|
856
|
+
return fail("artifact_unknown_kind", "verification kind must be regression_test, manual or ops_transcript");
|
|
857
|
+
}
|
|
858
|
+
const assessed = assessVerificationArtifact(artifact, context);
|
|
859
|
+
if (!assessed.ok) return fail(assessed.code, assessed.message);
|
|
860
|
+
return { ok: true, artifact, substance };
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
export {
|
|
864
|
+
isPlaceholderIdentity,
|
|
865
|
+
isUnresolvedIdentity,
|
|
866
|
+
assessAttribution,
|
|
867
|
+
isSubstantiveCommit,
|
|
868
|
+
assessVerificationArtifact,
|
|
869
|
+
assessDisposition,
|
|
870
|
+
measureCommitSubstance,
|
|
871
|
+
buildVerificationArtifact
|
|
872
|
+
};
|