Compound Labs
Get the newsletter
THE STANDUPAnthropic fixes Claude 5.1 error spikesERROR SPIKES, FIX DEPLOYEDCOMPOUND MASTODONSkillWorks records inactive files beside their roster status22 INACTIVE FILES STILL LOADCTXWINDOWContext Window tracks AI lab changes and filters their evidenceFILTERS KEEP EVIDENCE TOGETHERAGENTWIREmicrosoft/agent-governance-toolkit - AI Agent Governance ToolkitPOLICY ENFORCEMENT FOR AI AGENTSCOMPOUND FACEBOOKCompound Portfolio restores its sweep after a missing module stops desk dataSWEEP RESTORED, DESK DATA WRITTENBLOCKDEXBlockDex shows no destination for captured rows with rejected slash names31 ROWS, NO DESTINATIONCONTEXT WINDOWOpenAI adds 1024p image pricing: $0.50 and $0.251024P IMAGE, $0.50 AND $0.25COMPOUND BLUESKYCompound Labs renamed job labels so job-run finds breaker stateBREAKER STATE, NOW FINDABLECTXWINDOWContext Window tracks document changes but failed mobileMOBILE WORKFLOW, ONE COLUMNAGENTWIREMineDojo Voyager: Open-Ended Embodied AgentOPEN-ENDED EMBODIED AGENTFOUNDER BLUESKYdeploy.sh now fails false Vercel production landingsFALSE LANDINGS NOW FAILCOMPOUNDlast known fixes redirect tracking after migrationSTUDIO SOURCES NOW SAY COMPOUNDCONTEXT WINDOWOpenAI adds sora-2-pro pricing720P VIDEO, $0.15, $0.30FOUNDER LINKEDINdeploy.sh now stops failed promotes from marking production landedFAILED PROMOTES NO LONGER LANDUSINGITUPUsing It Up records a receipt fixing a wobbling wooden tableONE RECEIPT, TABLE STAYED LEVELCOMPOUNDpnpm v12.4.2POSIX BIN SHIMS REPLACEDFOUNDER PEERLISTCompound Labs' deploy runner rejects failed promotesFAILED PROMOTES NO LONGER LANDTRUSTDESKTrustDesk fixes host migration redirects while keeping /api/ outOLD HOST, 308; API STAYS LIVE
Independent product R&D labFounded and run by Isaiah Kim, @kyisaiah47Newest commit Sep 16, 2026, AgentwireNewest writing Sep 16, 2026Site changelog Sep 16, 2026
ShipWallAug 30, 20263 min read

ShipWall's morning pass reported success to the scheduler on every morning it had not run

We have a morning pass that dates the day's launches, freezes yesterday's ranking so it can never move again, and mails that ranking out. For a stretch of mornings it did none of those things, and the one thing watching it said it had finished fine, every day.

ShipWall is a launch board for products built with AI coding tools, the Lovable and v0 and Bolt and Cursor end of the world. The morning pass runs five steps in a fixed order: schedule, board, digest, badge, mailer. The order is load-bearing, because a digest sent before the freeze would quote a ranking that is still moving, and a maker's badge would then disagree with their own email.

launchd only keeps one number about a job

The scheduler running it is launchd, and what it records about a run is the exit code, the single number a program hands back when it stops. Zero means success. It has no opinion about whether the work happened, and it does not know what the work was.

It also hands a job less than you would assume. A launchd agent starts with a near empty PATH, so anything the script shells out to is not found, and it starts with no HOME, which is where every run script here resolves the shared job ledger from. With HOME unset, the ledger path does not exist, the reporting call is skipped without a word, and a job that died leaves no failure row at all.

ShipWall morning pass
ShipWall morning pass

The gate probed a name that was never a table

We added a preflight gate so a scheduled job would not fire into a stalled shared database and compete with its own recovery. The gate reads one row before the pass is allowed to start. The name we pointed it at was shipwall_board, which is the function that renders the ranking, and a function is not something you can select a row from. The database's REST layer answers that with 404, instantly, on a completely healthy instance.

The gate had one rule for anything that was not a 200: wait, then give up and exit 0, on the reasoning that a skipped night costs nothing. So every morning it waited, gave up, and reported success. Zero was the number in two places at once. It was the status handed back to launchd, and it was the number of mornings the pass had actually run since the gate landed.

How the night endedWhat launchd recordsWhat the shared job ledger records
All five steps clean0ok, with the number of rows touched
One or more steps failed0, so launchd does not throttle the job over a slow badge crawlfail, naming the steps
Database still refusing after 60, 180 and 420 seconds0fail, skipped after backoff, rows 0
401, 403 or 404 on the products table1fail, configuration fault rather than backpressure
No credentials in the environment file1fail, no credentials

What changed

We now probe a real table, and we exit non-zero on 401, 403 and 404, because a bad key or a missing name will be just as wrong in seven minutes as it is now. Backing off 60, 180 and 420 seconds is reserved for the failures a wait can fix. Every terminal path in that script writes a ledger row carrying the number of rows the night touched, so a morning that dated nobody, froze nothing and sent nothing reads as a zero instead of as silence.

ShipWall is live if you want to see the board the freeze produces.

<caption>The job checked a name that did not exist, quit, and still reported success, so now it has to say what it did.</caption>

---

One shipped product, taken apart, once a month. What it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did, read off the repository and the live site, not written from memory. Join the list.

All writing