[{"data":1,"prerenderedAt":870},["ShallowReactive",2],{"cycle-doc-qnative-c3-guide\u002F02-run-it.md":3},{"cycle":4,"project":7,"path":10,"title":11,"toc":12,"ast":18},{"id":5,"title":6},"c3","Developer Mode",{"id":8,"label":9},"qnative","Qnative (provisional)","guide\u002F02-run-it.md","Run it on your machine",[13,14,15,16,17],"Today: build and run","Today: how the app finds a sensor","Dev › Source (built in Phase 2)","The ladder (built: `nozzle::ladder`)","The doctor (built: `app --check-sensor`)",{"type":19,"children":20},"root",[21,35,41,55,156,161,174,216,221,305,312,317,475,493,525,530,535,576,584,605,618,631,827,832,845,850,860,865],{"type":22,"tag":23,"props":24,"children":25},"element","p",{},[26,33],{"type":22,"tag":27,"props":28,"children":29},"strong",{},[30],{"type":31,"value":32},"text","Standing:",{"type":31,"value":34}," built through Phase 2 (2026-11-11): Dev › Source, the ladder and the doctor. The feed check is Phase 5's.",{"type":22,"tag":36,"props":37,"children":39},"h2",{"id":38},"today-build-and-run",[40],{"type":31,"value":13},{"type":22,"tag":42,"props":43,"children":49},"pre",{"className":44,"code":45,"language":46,"meta":47,"style":48},"language-bash","cargo dev                                              # the alias for the line below\ncargo run -p app --features dev                        # debug: developer pages on, synthetic data\ncargo run -p app --features dev -- --data local        # this machine's sensor\ncargo run --release -p app --features dev -- --dev     # release, developer pages allowed\ncargo run -p app                                       # the lean build: no developer pages at all\n","bash","","undefined",[50],{"type":22,"tag":51,"props":52,"children":53},"code",{"__ignoreMap":47},[54],{"type":31,"value":45},{"type":22,"tag":56,"props":57,"children":58},"ul",{},[59,96,133,151],{"type":22,"tag":60,"props":61,"children":62},"li",{},[63,65,71,73,79,81,87,89,94],{"type":31,"value":64},"Since Phase 0 the default build is lean: developer mode is compiled in only with ",{"type":22,"tag":51,"props":66,"children":68},{"className":67},[],[69],{"type":31,"value":70},"--features dev",{"type":31,"value":72},". In that build it is allowed in debug, and in release with ",{"type":22,"tag":51,"props":74,"children":76},{"className":75},[],[77],{"type":31,"value":78},"--dev",{"type":31,"value":80}," or ",{"type":22,"tag":51,"props":82,"children":84},{"className":83},[],[85],{"type":31,"value":86},"QPOINT_DEV=1",{"type":31,"value":88},"; where it is allowed, the tray menu's ",{"type":22,"tag":27,"props":90,"children":91},{},[92],{"type":31,"value":93},"Developer mode",{"type":31,"value":95}," item turns it off and on, and the choice is remembered.",{"type":22,"tag":60,"props":97,"children":98},{},[99,101,107,109,115,117,123,125,131],{"type":31,"value":100},"The data source is one switch for the whole process: ",{"type":22,"tag":51,"props":102,"children":104},{"className":103},[],[105],{"type":31,"value":106},"--data synthetic|local|plane",{"type":31,"value":108},", or ",{"type":22,"tag":51,"props":110,"children":112},{"className":111},[],[113],{"type":31,"value":114},"QPOINT_DATA",{"type":31,"value":116},". Debug builds default to ",{"type":22,"tag":51,"props":118,"children":120},{"className":119},[],[121],{"type":31,"value":122},"synthetic",{"type":31,"value":124},", release builds to ",{"type":22,"tag":51,"props":126,"children":128},{"className":127},[],[129],{"type":31,"value":130},"local",{"type":31,"value":132},".",{"type":22,"tag":60,"props":134,"children":135},{},[136,142,143,149],{"type":22,"tag":51,"props":137,"children":139},{"className":138},[],[140],{"type":31,"value":141},"--world \u003Cname>",{"type":31,"value":80},{"type":22,"tag":51,"props":144,"children":146},{"className":145},[],[147],{"type":31,"value":148},"QPOINT_WORLD",{"type":31,"value":150}," picks a bundled synthetic world.",{"type":22,"tag":60,"props":152,"children":153},{},[154],{"type":31,"value":155},"The footer of the window always names the source.",{"type":22,"tag":36,"props":157,"children":159},{"id":158},"today-how-the-app-finds-a-sensor",[160],{"type":31,"value":14},{"type":22,"tag":23,"props":162,"children":163},{},[164,166,172],{"type":31,"value":165},"With ",{"type":22,"tag":51,"props":167,"children":169},{"className":168},[],[170],{"type":31,"value":171},"--data local",{"type":31,"value":173}," the app reads one file and then speaks HTTP over loopback.",{"type":22,"tag":175,"props":176,"children":177},"ol",{},[178,198,203],{"type":22,"tag":60,"props":179,"children":180},{},[181,183,189,191,197],{"type":31,"value":182},"It looks for the dashboard's lock file: ",{"type":22,"tag":51,"props":184,"children":186},{"className":185},[],[187],{"type":31,"value":188},"\u003Cdata dir>\u002Fdash\u002Fqdash.sock.lock",{"type":31,"value":190},", or beside the socket named by ",{"type":22,"tag":51,"props":192,"children":194},{"className":193},[],[195],{"type":31,"value":196},"QCONTROL_DASH_SOCKET_PATH",{"type":31,"value":132},{"type":22,"tag":60,"props":199,"children":200},{},[201],{"type":31,"value":202},"The second line of that file is the dashboard's URL. The first line is its pid.",{"type":22,"tag":60,"props":204,"children":205},{},[206,208,214],{"type":31,"value":207},"It then GETs the same ",{"type":22,"tag":51,"props":209,"children":211},{"className":210},[],[212],{"type":31,"value":213},"\u002Fapi\u002F*",{"type":31,"value":215}," routes the dashboard's own UI uses. No credential.",{"type":22,"tag":23,"props":217,"children":218},{},[219],{"type":31,"value":220},"What the sensor must be doing for this to work:",{"type":22,"tag":56,"props":222,"children":223},{},[224,245,258,263],{"type":22,"tag":60,"props":225,"children":226},{},[227,229,235,237,243],{"type":31,"value":228},"The monitor is running, with the dashboard on. ",{"type":22,"tag":51,"props":230,"children":232},{"className":231},[],[233],{"type":31,"value":234},"ui.dashboard",{"type":31,"value":236}," absent means on (",{"type":22,"tag":51,"props":238,"children":240},{"className":239},[],[241],{"type":31,"value":242},"crates\u002Fqconfig\u002Fsrc\u002Ffile.rs",{"type":31,"value":244},").",{"type":22,"tag":60,"props":246,"children":247},{},[248,250,256],{"type":31,"value":249},"The dashboard is the one embedded in the monitor. A static ",{"type":22,"tag":51,"props":251,"children":253},{"className":252},[],[254],{"type":31,"value":255},"qdash serve",{"type":31,"value":257}," has no live hub and answers the stream with 503.",{"type":22,"tag":60,"props":259,"children":260},{},[261],{"type":31,"value":262},"The port is 7878 unless it was taken, in which case it is whatever the lock file says. Do not assume 7878.",{"type":22,"tag":60,"props":264,"children":265},{},[266,268,274,276,282,283,289,291,297,298,304],{"type":31,"value":267},"The server refuses any request whose Host is not ",{"type":22,"tag":51,"props":269,"children":271},{"className":270},[],[272],{"type":31,"value":273},"localhost",{"type":31,"value":275},", ",{"type":22,"tag":51,"props":277,"children":279},{"className":278},[],[280],{"type":31,"value":281},"127.0.0.1",{"type":31,"value":80},{"type":22,"tag":51,"props":284,"children":286},{"className":285},[],[287],{"type":31,"value":288},"[::1]",{"type":31,"value":290}," (",{"type":22,"tag":51,"props":292,"children":294},{"className":293},[],[295],{"type":31,"value":296},"crates\u002Fqdash\u002Fsrc\u002Fweb.rs",{"type":31,"value":275},{"type":22,"tag":51,"props":299,"children":301},{"className":300},[],[302],{"type":31,"value":303},"require_local_host",{"type":31,"value":244},{"type":22,"tag":306,"props":307,"children":309},"h3",{"id":308},"the-data-directory-fixed-on-macos-in-phase-2",[310],{"type":31,"value":311},"The data directory (fixed on macOS in Phase 2)",{"type":22,"tag":23,"props":313,"children":314},{},[315],{"type":31,"value":316},"The app carries its own copy of qcontrol's data-directory rule, so that it compiles without qcontrol.",{"type":22,"tag":318,"props":319,"children":320},"table",{},[321,360],{"type":22,"tag":322,"props":323,"children":324},"thead",{},[325],{"type":22,"tag":326,"props":327,"children":328},"tr",{},[329,335,348],{"type":22,"tag":330,"props":331,"children":332},"th",{},[333],{"type":31,"value":334},"Platform",{"type":22,"tag":330,"props":336,"children":337},{},[338,340,346],{"type":31,"value":339},"qcontrol (",{"type":22,"tag":51,"props":341,"children":343},{"className":342},[],[344],{"type":31,"value":345},"qconfig::data_dir_path",{"type":31,"value":347},")",{"type":22,"tag":330,"props":349,"children":350},{},[351,353,359],{"type":31,"value":352},"The app (",{"type":22,"tag":51,"props":354,"children":356},{"className":355},[],[357],{"type":31,"value":358},"nozzle::data_dir",{"type":31,"value":347},{"type":22,"tag":361,"props":362,"children":363},"tbody",{},[364,394,422],{"type":22,"tag":326,"props":365,"children":366},{},[367,373,382],{"type":22,"tag":368,"props":369,"children":370},"td",{},[371],{"type":31,"value":372},"macOS",{"type":22,"tag":368,"props":374,"children":375},{},[376],{"type":22,"tag":51,"props":377,"children":379},{"className":378},[],[380],{"type":31,"value":381},"~\u002FLibrary\u002FApplication Support\u002Fcom.qpoint.qcontrol",{"type":22,"tag":368,"props":383,"children":384},{},[385,387,393],{"type":31,"value":386},"the same, since Phase 2 (it was ",{"type":22,"tag":51,"props":388,"children":390},{"className":389},[],[391],{"type":31,"value":392},"…\u002Fqcontrol",{"type":31,"value":347},{"type":22,"tag":326,"props":395,"children":396},{},[397,402,411],{"type":22,"tag":368,"props":398,"children":399},{},[400],{"type":31,"value":401},"Linux",{"type":22,"tag":368,"props":403,"children":404},{},[405],{"type":22,"tag":51,"props":406,"children":408},{"className":407},[],[409],{"type":31,"value":410},"~\u002F.local\u002Fshare\u002Fqcontrol",{"type":22,"tag":368,"props":412,"children":413},{},[414,416],{"type":31,"value":415},"the same; it also honours ",{"type":22,"tag":51,"props":417,"children":419},{"className":418},[],[420],{"type":31,"value":421},"XDG_DATA_HOME",{"type":22,"tag":326,"props":423,"children":424},{},[425,430,464],{"type":22,"tag":368,"props":426,"children":427},{},[428],{"type":31,"value":429},"Windows",{"type":22,"tag":368,"props":431,"children":432},{},[433,435,441,443,449,451,457,458],{"type":31,"value":434},"the ",{"type":22,"tag":51,"props":436,"children":438},{"className":437},[],[439],{"type":31,"value":440},"directories",{"type":31,"value":442}," crate's data dir for ",{"type":22,"tag":51,"props":444,"children":446},{"className":445},[],[447],{"type":31,"value":448},"com",{"type":31,"value":450}," \u002F ",{"type":22,"tag":51,"props":452,"children":454},{"className":453},[],[455],{"type":31,"value":456},"qpoint",{"type":31,"value":450},{"type":22,"tag":51,"props":459,"children":461},{"className":460},[],[462],{"type":31,"value":463},"qcontrol",{"type":22,"tag":368,"props":465,"children":466},{},[467,473],{"type":22,"tag":51,"props":468,"children":470},{"className":469},[],[471],{"type":31,"value":472},"%LOCALAPPDATA%\\qcontrol",{"type":31,"value":474},": still different, not yet checked on a Windows machine",{"type":22,"tag":23,"props":476,"children":477},{},[478,484,486,491],{"type":22,"tag":51,"props":479,"children":481},{"className":480},[],[482],{"type":31,"value":483},"QCONTROL_DATA_DIR",{"type":31,"value":485}," moves it, and ",{"type":22,"tag":51,"props":487,"children":489},{"className":488},[],[490],{"type":31,"value":196},{"type":31,"value":492}," moves the socket and its lock file.",{"type":22,"tag":56,"props":494,"children":495},{},[496,506],{"type":22,"tag":60,"props":497,"children":498},{},[499,504],{"type":22,"tag":27,"props":500,"children":501},{},[502],{"type":31,"value":503},"A stale lock file",{"type":31,"value":505}," is caught. When the monitor stopped without cleaning up, the lock file is still there, but its pid no longer runs. The ladder checks the pid before it tries the URL.",{"type":22,"tag":60,"props":507,"children":508},{},[509,514,516,523],{"type":22,"tag":27,"props":510,"children":511},{},[512],{"type":31,"value":513},"The elevated monitor",{"type":31,"value":515}," is still open. If the monitor runs as root, can a user-level app read the lock file? That is a question for the sensor's engineer (",{"type":22,"tag":517,"props":518,"children":520},"a",{"href":519},"\u002Fcycles\u002Fqnative\u002Fc3\u002Fdoc\u002Fguide\u002F04-monitor",[521],{"type":31,"value":522},"Monitor",{"type":31,"value":524},", question 2).",{"type":22,"tag":36,"props":526,"children":528},{"id":527},"dev-source-built-in-phase-2",[529],{"type":31,"value":15},{"type":22,"tag":23,"props":531,"children":532},{},[533],{"type":31,"value":534},"Source is where the data comes from, for the whole app. It sits in the Dev group. \"Sensor\" under This machine is a different page: V1's view of qcontrol itself.",{"type":22,"tag":56,"props":536,"children":537},{},[538,556,566],{"type":22,"tag":60,"props":539,"children":540},{},[541,546,548,554],{"type":22,"tag":27,"props":542,"children":543},{},[544],{"type":31,"value":545},"Synthetic:",{"type":31,"value":547}," a world, a condition (healthy, sensor not running, slow answers, no live stream (503), a shape that does not match, the stream lags then is cut) and a stream (quiet, coding-session, mcp-heavy, file-storm, at the script's rate or 10, 100 or 1,000 a second). See ",{"type":22,"tag":517,"props":549,"children":551},{"href":550},"\u002Fcycles\u002Fqnative\u002Fc3\u002Fdoc\u002Fguide\u002F06-scenarios",[552],{"type":31,"value":553},"Synthetic scenarios",{"type":31,"value":555},". Every condition goes through the real pipes, so each page draws it with its own honest state.",{"type":22,"tag":60,"props":557,"children":558},{},[559,564],{"type":22,"tag":27,"props":560,"children":561},{},[562],{"type":31,"value":563},"This machine:",{"type":31,"value":565}," found through the lock file, with the ladder below.",{"type":22,"tag":60,"props":567,"children":568},{},[569,574],{"type":22,"tag":27,"props":570,"children":571},{},[572],{"type":31,"value":573},"An address:",{"type":31,"value":575}," the near end of an SSH tunnel, with the same ladder from Answering up.",{"type":22,"tag":42,"props":577,"children":579},{"className":44,"code":578,"language":46,"meta":47,"style":48},"ssh -N -L 7878:127.0.0.1:\u003Cthe sensor's port> you@the-box    # the port from the box's lock file\n",[580],{"type":22,"tag":51,"props":581,"children":582},{"__ignoreMap":47},[583],{"type":31,"value":578},{"type":22,"tag":23,"props":585,"children":586},{},[587,589,595,597,603],{"type":31,"value":588},"Then enter ",{"type":22,"tag":51,"props":590,"children":592},{"className":591},[],[593],{"type":31,"value":594},"http:\u002F\u002F127.0.0.1:7878",{"type":31,"value":596}," on Source and press Attach. The footer says ",{"type":22,"tag":51,"props":598,"children":600},{"className":599},[],[601],{"type":31,"value":602},"sensor at http:\u002F\u002F127.0.0.1:7878",{"type":31,"value":604},". The plane transport is no longer the way to do this (ruling 3).",{"type":22,"tag":23,"props":606,"children":607},{},[608,610,616],{"type":31,"value":609},"A choice applies at once. The nozzle is swapped for the process through the one re-open path (",{"type":22,"tag":51,"props":611,"children":613},{"className":612},[],[614],{"type":31,"value":615},"host::reopen",{"type":31,"value":617},", c131 D16), and every page reads again. The choice is saved, and the next start applies it unless a flag or the environment says otherwise. The precedence is flag, then environment, then the saved choice, then the build's default. The lean build has no page and reads this machine's sensor.",{"type":22,"tag":36,"props":619,"children":621},{"id":620},"the-ladder-built-nozzleladder",[622,624,630],{"type":31,"value":623},"The ladder (built: ",{"type":22,"tag":51,"props":625,"children":627},{"className":626},[],[628],{"type":31,"value":629},"nozzle::ladder",{"type":31,"value":347},{"type":22,"tag":318,"props":632,"children":633},{},[634,660],{"type":22,"tag":322,"props":635,"children":636},{},[637],{"type":22,"tag":326,"props":638,"children":639},{},[640,645,650,655],{"type":22,"tag":330,"props":641,"children":642},{},[643],{"type":31,"value":644},"Rung",{"type":22,"tag":330,"props":646,"children":647},{},[648],{"type":31,"value":649},"The check",{"type":22,"tag":330,"props":651,"children":652},{},[653],{"type":31,"value":654},"What it says",{"type":22,"tag":330,"props":656,"children":657},{},[658],{"type":31,"value":659},"If it fails here",{"type":22,"tag":361,"props":661,"children":662},{},[663,686,709,751,774,797],{"type":22,"tag":326,"props":664,"children":665},{},[666,671,676,681],{"type":22,"tag":368,"props":667,"children":668},{},[669],{"type":31,"value":670},"Not found",{"type":22,"tag":368,"props":672,"children":673},{},[674],{"type":31,"value":675},"no lock file in the data dir, or a stale one",{"type":22,"tag":368,"props":677,"children":678},{},[679],{"type":31,"value":680},"no sensor on this machine",{"type":22,"tag":368,"props":682,"children":683},{},[684],{"type":31,"value":685},"is the monitor running; is the data dir the one in the table above",{"type":22,"tag":326,"props":687,"children":688},{},[689,694,699,704],{"type":22,"tag":368,"props":690,"children":691},{},[692],{"type":31,"value":693},"Found",{"type":22,"tag":368,"props":695,"children":696},{},[697],{"type":31,"value":698},"lock file present and its pid alive",{"type":22,"tag":368,"props":700,"children":701},{},[702],{"type":31,"value":703},"installed and running",{"type":22,"tag":368,"props":705,"children":706},{},[707],{"type":31,"value":708},"a dead pid means a stale lock: start the monitor",{"type":22,"tag":326,"props":710,"children":711},{},[712,717,728,740],{"type":22,"tag":368,"props":713,"children":714},{},[715],{"type":31,"value":716},"Answering",{"type":22,"tag":368,"props":718,"children":719},{},[720,726],{"type":22,"tag":51,"props":721,"children":723},{"className":722},[],[724],{"type":31,"value":725},"GET \u002Fapi\u002Fstats",{"type":31,"value":727}," returns 200",{"type":22,"tag":368,"props":729,"children":730},{},[731,733,739],{"type":31,"value":732},"connected; the events it has seen (the version is not served: c131 D17's ",{"type":22,"tag":51,"props":734,"children":736},{"className":735},[],[737],{"type":31,"value":738},"\u002Fapi\u002Fsensor",{"type":31,"value":347},{"type":22,"tag":368,"props":741,"children":742},{},[743,745,750],{"type":31,"value":744},"a refused connection: the dashboard is off (",{"type":22,"tag":51,"props":746,"children":748},{"className":747},[],[749],{"type":31,"value":234},{"type":31,"value":347},{"type":22,"tag":326,"props":752,"children":753},{},[754,759,764,769],{"type":22,"tag":368,"props":755,"children":756},{},[757],{"type":31,"value":758},"Streaming",{"type":22,"tag":368,"props":760,"children":761},{},[762],{"type":31,"value":763},"the event stream opens",{"type":22,"tag":368,"props":765,"children":766},{},[767],{"type":31,"value":768},"live",{"type":22,"tag":368,"props":770,"children":771},{},[772],{"type":31,"value":773},"see Refused",{"type":22,"tag":326,"props":775,"children":776},{},[777,782,787,792],{"type":22,"tag":368,"props":778,"children":779},{},[780],{"type":31,"value":781},"Lost",{"type":22,"tag":368,"props":783,"children":784},{},[785],{"type":31,"value":786},"it was connected and is retrying",{"type":22,"tag":368,"props":788,"children":789},{},[790],{"type":31,"value":791},"reconnecting, with the attempt and the reason",{"type":22,"tag":368,"props":793,"children":794},{},[795],{"type":31,"value":796},"the monitor restarted, or the app fell behind and was cut off",{"type":22,"tag":326,"props":798,"children":799},{},[800,805,810,815],{"type":22,"tag":368,"props":801,"children":802},{},[803],{"type":31,"value":804},"Refused",{"type":22,"tag":368,"props":806,"children":807},{},[808],{"type":31,"value":809},"403 or 503",{"type":22,"tag":368,"props":811,"children":812},{},[813],{"type":31,"value":814},"reachable but not serving",{"type":22,"tag":368,"props":816,"children":817},{},[818,820,825],{"type":31,"value":819},"403: the Host is not local (use a tunnel, not an opened port). 503: a static ",{"type":22,"tag":51,"props":821,"children":823},{"className":822},[],[824],{"type":31,"value":255},{"type":31,"value":826}," with no hub (start the monitor)",{"type":22,"tag":23,"props":828,"children":829},{},[830],{"type":31,"value":831},"At an address the first two rungs do not apply, and the ladder starts at Answering.",{"type":22,"tag":36,"props":833,"children":835},{"id":834},"the-doctor-built-app-check-sensor",[836,838,844],{"type":31,"value":837},"The doctor (built: ",{"type":22,"tag":51,"props":839,"children":841},{"className":840},[],[842],{"type":31,"value":843},"app --check-sensor",{"type":31,"value":347},{"type":22,"tag":23,"props":846,"children":847},{},[848],{"type":31,"value":849},"The same checks from the command line, so a failing rung can be read without opening a window. It exits 0 only when the stream is live. These two are real runs on 2026-11-11:",{"type":22,"tag":42,"props":851,"children":855},{"className":852,"code":854,"language":31,"meta":47},[853],"language-text","$ app --check-sensor\nsensor check: this machine (lock file ~\u002FLibrary\u002FApplication Support\u002Fcom.qpoint.qcontrol\u002Fdash\u002Fqdash.sock.lock)\n  ok   lock file  …\u002Fqdash.sock.lock names http:\u002F\u002F127.0.0.1:7878\n  FAIL running    the lock file names pid 54415, which is not running: a stale lock\nreached: Not found. Start qcontrol's monitor on this machine, or attach to a sensor at an address.\n\n$ app --check-sensor --sensor-url http:\u002F\u002F127.0.0.1:7882\nsensor check: http:\u002F\u002F127.0.0.1:7882\n  --   lock file  this machine only\n  --   running    this machine only\n  ok   answering  GET \u002Fapi\u002Fstats 200: 50730 events seen; the version is not served yet (c131 D17's \u002Fapi\u002Fsensor)\n  FAIL streaming  the sensor has no live stream (503): live stream unavailable: static `qdash serve` has no live hub\nreached: Refused. Reachable but not serving: a 403 means the Host was not local (use an SSH tunnel, not an opened port); a 503 means a static `qdash serve` (start the monitor instead).\n",[856],{"type":22,"tag":51,"props":857,"children":858},{"__ignoreMap":47},[859],{"type":31,"value":854},{"type":22,"tag":23,"props":861,"children":862},{},[863],{"type":31,"value":864},"Still to come: listing each feed the pages need as served, missing or mismatched, once the Monitor's routes exist (Phase 5).",{"type":22,"tag":866,"props":867,"children":868},"style",{},[869],{"type":31,"value":47},1794599452906]