app
DEPRECATED: Bridge SDK (moved into Adom Bridge)
Public Made by Adomby adom
Bridge SDK guide: bridge.json schema, kind:python/node/exe, hello-python + hello-rust reference templates, packaging + lifecycle commands.
← Commit history
SDK: invite bug reports in verb output (#35), file AD-core issues on the right repo (#29), logging ownership + volume (bridges#3)
3 files changed
+273
README.md+91@@ -323,6 +323,73 @@ This SDK evolves. When it does, AD posts a re-audit notice to **YOUR bridge's wi --- +## Ask the AI to report bugs, in the OUTPUT, not the skill file++You cannot reproduce every environment. Your bridge runs on machines with browser installs, OS versions, security policies, hardware and concurrency patterns you will never have locally. **The AI driving your bridge is standing on exactly that machine.** It is the only party holding the failing response, and the moment it holds it is the only moment it will file anything.++So make the invitation part of your verb output, the same way `_hint` is. This is THE ONE PRINCIPLE at the top of this page applied to feedback: the AI almost never reads your on-disk SKILL.md, and it ALWAYS reads the output of a CLI call.++**The evidence that this channel works.** In roughly two days, wiki issues filed against the puppeteer bridge produced: a CPU-pegging orphaned-renderer bug that froze a laptop and forced a reboot (#14, #21), a respawn failure that broke the bridge on every idle cycle (#15), a session-tracking bug where windows were open and drivable but reported as zero (#16), a repo-versus-release divergence that would have silently reverted five releases (#19), and a concurrency and readiness report that caught a live blocking regression shipped hours earlier (#22). **Not one of those would have been found on a maintainer's machine.** They came from real installs: different Chrome and Edge combinations, different AD versions, concurrent agents, a macOS box, a stalled download.++**Return a `_reportIssues` field naming YOUR page's issue list, with the exact commands:**++```jsonc+{+ "success": false,+ "errorCode": "…",+ "_hint": "…",+ "_reportIssues": "THIS MAY BE A <BRIDGE> BUG. PLEASE REPORT IT. Check for a duplicate with `adom-wiki issue list adom/<your-slug>`, then file: `adom-wiki issue create adom/<your-slug> --title \"<one-line symptom>\" --category bug-report --body \"<what you ran, what you expected, what happened, the VERBATIM response JSON, the bridge version from bridge_list, and the OS>\"`. Reports from real machines are the only way this bridge gets correct. (An AD-core problem, such as the relay, bridge lifecycle or caller identity, belongs on adom/adom-desktop instead.)"+}+```++**When to attach it. Throttle it, or the AI learns to skip it:**++| Moment | Why |+|---|---|+| **Always on a failure** | The highest-value moment: a bug just happened and the evidence is still in the response. |+| **Once per bridge process, on the first verb** | Orientation, so the AI knows where to report *before* anything breaks. |+| **Occasionally after that** (e.g. every ~40th call) | A quiet reminder on a long-running session without taxing every response. |++A line on **every** response is noise that trains the caller to ignore the field. A line on every **failure** is a bug report waiting to be filed.++**Make it actionable, not a slogan.** "Report bugs" produces nothing. Give the AI the exact `adom-wiki issue create` command, your slug, a `--category`, and the list of evidence to include (the verbatim response JSON and your bridge version are the two that make a report reproducible). Tell it to check for a duplicate first: an `issue list` call costs nothing and keeps your page clean.++**Route the report to the repo that owns the code.** Say explicitly, in the same string, that AD-core problems (the relay and `/command` passthrough, spawn and provisioning, bridge lifecycle, caller identity) go to **`adom/adom-desktop`**, not to your page. Authors get this wrong in the other direction too, which is the next section: a misfiled issue is a note to yourself that the people who can fix it never read.++**Let the user turn it off.** Ship a settings toggle (pup uses `browser_configure {reportIssues:"off"}`) so a user who finds it noisy can silence it without losing functionality. Default it **on**: the cost is a few tokens on failures, and the benefit is the bug class you would otherwise ship to every user.++**Reference implementation:** the puppeteer bridge does this at its single `sendJSON` chokepoint (v1.9.95), so all ~155 response sites are covered from one place, and it never overwrites a `_hint` a handler already set.++---++## Filing issues against AD (and the other repos you depend on)++You WILL find AD-core bugs and gaps while building your bridge. That is expected and useful. But file them in the RIGHT repo's issue list, or the people who can fix them never see it.++**The rule: an issue lives on the issue list of the repo that OWNS the code that must change.**++- A bug in YOUR bridge's verb / hint / self-heal / status chip goes to **YOUR page's issue list** (or you just fix it, since you own it).+- A missing or broken **AD-CORE** capability (a lifecycle verb, a spawn / provision / bind behavior, the relay passthrough dropping a field, a manifest field AD must honor, the status-chip contract) goes to **`adom/adom-desktop`**, NOT your own page. AD-core's maintainers and AI watch `adom/adom-desktop`; they do NOT read your bridge page's issues. **An AD ask filed on your own page is a note to yourself.**+- A **wiki or CLI** bug goes to `adom/wiki`. A **sibling bridge's** bug goes to that bridge's page.++**How (the CLI):**++```bash+adom-wiki issue list adom/adom-desktop # FIRST: skim for a dup, comment if one exists+adom-wiki issue create adom/adom-desktop \+ --title "<verb or subsystem>: <the gap in one line>" \+ --category bug-report \+ --body "$(cat your-writeup.md)"+```++**Write the body like a good bug report:** what you hit live (with the date and the AD version), the measured behavior, the AD-owned root cause if you found one, and a concrete ask. Separate clearly what is AD-core's to fix from what is yours, and say so explicitly, so the two are never conflated.++**After you file:** the AD-core thread replies on that issue. Read the reply, it may change your plan (for example "fixed in AD X.Y, bump your pin"). That issue thread is the cross-repo channel; keep the loop closed there.++**Why this matters most for AD:** AD-core spawns you, provisions your runtime, relays your verbs, and installs you, so AD is the repo you will file against most often. Get the destination right the first time. The established precedent all sits on `adom/adom-desktop`: #26 and #27 (pup to AD, Chrome for Testing), #16 (pup to AD, window-verb interception), #3 / #20 / #21 (Bridge SDK asks).++---+ ## Self-audit checklist — run this when asked to "audit against the SDK" When a maintainer says *"audit your code, skills, README, and wiki page against the Bridge SDK,"* **this is the checklist.** Each item names its section below; fix every miss, then re-check.@@ -701,6 +768,30 @@ Your `/health` (200) makes the chip green. Optionally return `led` (`green`/`yel **"My bridge keeps exiting and I can't see why" (read this).** Your own stdout log truncates on every respawn, so a crash-then-restart erases its own cause. `bridge_log_read` therefore also tails **AD's lifecycle audit log** for your bridge, a separate append-only file (`~/.adom/bridge-logs/<name>.ad.log`) that survives respawns, shown under an `===== AD bridge lifecycle =====` header. It records every spawn, reap, duplicate-collapse, and `bridge_kill` with the reason, so you can tell "AD reaped it as a duplicate" or "the `bridge_kill` verb stopped it" or "it was reaped before a fresh spawn" apart from "it crashed on its own." If the audit log shows AD never stopped it, the exit is inside your process. +## Logging: AD owns the FILE, you own the VOLUME++Every bridge writes to stdout, AD captures it, and nobody asks the volume question until someone's log is a firehose. The split:++- **AD owns the FILE.** AD spawns you and captures stdout/stderr, so the file and its rotation are AD's. A bridge cannot rotate a file another process holds open, and bounded logs have to be a platform guarantee rather than per-author boilerplate.+- **You own the VOLUME.** How much you emit is the half a tidy platform cannot fix for you.++*(READING the log is the section immediately above: `bridge_log_read` plus AD's separate lifecycle audit. This section is about what you WRITE.)*++**Do NOT write your own parallel log file.** Two log files means two sources of truth and double the disk for the same bytes. pup built one (a rotated `pup.log`) and deliberately reverted it. If you think you need your own log, what you probably want is for AD to scope `bridge_log_read` to your bridge: file that against `adom/adom-desktop` (see "Filing issues against AD" above) instead of forking the log.++**The five patterns that keep a bridge out of firehose territory:**++1. **Never log per-item inside a loop over live state.** This is the single biggest source of volume. A drag-detection check logged one line PER TAB per check, all of them saying "(same)", so a 12-tab window emitted 12 useless lines every time the check fired. **Log the exception (the tab that moved), never the roll call.**+2. **Collapse consecutive identical lines.** Wrap `console.log` once, hold the last message, and emit `^ last line repeated Nx` when it changes. A retry loop then costs 2 lines instead of 200. Collapse only EXACT consecutive repeats, so no distinct event is lost. About 15 lines of code.+3. **Log static facts once per session, not per call.** "no favicon on this page" was emitted on every taskbar-badge update. It is a property of the page, not an event, and because the repeats were not consecutive the collapser could not catch them. Gate it behind a per-session flag.+4. **DO log every incoming verb, one compact line.** This is the one place to ADD volume. A log that records what the bridge DID (park, identity, overlay) but never WHAT WAS ASKED of it cannot answer "what foregrounded this window?" after the fact. Include only the args that change behavior, and skip your own log-read verb so reading the log does not pollute it. Put the caller thread on this line too (the shape is in "Caller provenance" above):++ ```+ [verb] browser_open_window session=parkedge url=https://example.com owner=parktest+ ```++5. **Never let logging throw.** Wrap the whole path in try/catch. A logging failure must not take the bridge down.+ --- ## Publish checklist (the whole modern flow)
SKILL.md+91@@ -323,6 +323,73 @@ This SDK evolves. When it does, AD posts a re-audit notice to **YOUR bridge's wi --- +## Ask the AI to report bugs, in the OUTPUT, not the skill file++You cannot reproduce every environment. Your bridge runs on machines with browser installs, OS versions, security policies, hardware and concurrency patterns you will never have locally. **The AI driving your bridge is standing on exactly that machine.** It is the only party holding the failing response, and the moment it holds it is the only moment it will file anything.++So make the invitation part of your verb output, the same way `_hint` is. This is THE ONE PRINCIPLE at the top of this page applied to feedback: the AI almost never reads your on-disk SKILL.md, and it ALWAYS reads the output of a CLI call.++**The evidence that this channel works.** In roughly two days, wiki issues filed against the puppeteer bridge produced: a CPU-pegging orphaned-renderer bug that froze a laptop and forced a reboot (#14, #21), a respawn failure that broke the bridge on every idle cycle (#15), a session-tracking bug where windows were open and drivable but reported as zero (#16), a repo-versus-release divergence that would have silently reverted five releases (#19), and a concurrency and readiness report that caught a live blocking regression shipped hours earlier (#22). **Not one of those would have been found on a maintainer's machine.** They came from real installs: different Chrome and Edge combinations, different AD versions, concurrent agents, a macOS box, a stalled download.++**Return a `_reportIssues` field naming YOUR page's issue list, with the exact commands:**++```jsonc+{+ "success": false,+ "errorCode": "…",+ "_hint": "…",+ "_reportIssues": "THIS MAY BE A <BRIDGE> BUG. PLEASE REPORT IT. Check for a duplicate with `adom-wiki issue list adom/<your-slug>`, then file: `adom-wiki issue create adom/<your-slug> --title \"<one-line symptom>\" --category bug-report --body \"<what you ran, what you expected, what happened, the VERBATIM response JSON, the bridge version from bridge_list, and the OS>\"`. Reports from real machines are the only way this bridge gets correct. (An AD-core problem, such as the relay, bridge lifecycle or caller identity, belongs on adom/adom-desktop instead.)"+}+```++**When to attach it. Throttle it, or the AI learns to skip it:**++| Moment | Why |+|---|---|+| **Always on a failure** | The highest-value moment: a bug just happened and the evidence is still in the response. |+| **Once per bridge process, on the first verb** | Orientation, so the AI knows where to report *before* anything breaks. |+| **Occasionally after that** (e.g. every ~40th call) | A quiet reminder on a long-running session without taxing every response. |++A line on **every** response is noise that trains the caller to ignore the field. A line on every **failure** is a bug report waiting to be filed.++**Make it actionable, not a slogan.** "Report bugs" produces nothing. Give the AI the exact `adom-wiki issue create` command, your slug, a `--category`, and the list of evidence to include (the verbatim response JSON and your bridge version are the two that make a report reproducible). Tell it to check for a duplicate first: an `issue list` call costs nothing and keeps your page clean.++**Route the report to the repo that owns the code.** Say explicitly, in the same string, that AD-core problems (the relay and `/command` passthrough, spawn and provisioning, bridge lifecycle, caller identity) go to **`adom/adom-desktop`**, not to your page. Authors get this wrong in the other direction too, which is the next section: a misfiled issue is a note to yourself that the people who can fix it never read.++**Let the user turn it off.** Ship a settings toggle (pup uses `browser_configure {reportIssues:"off"}`) so a user who finds it noisy can silence it without losing functionality. Default it **on**: the cost is a few tokens on failures, and the benefit is the bug class you would otherwise ship to every user.++**Reference implementation:** the puppeteer bridge does this at its single `sendJSON` chokepoint (v1.9.95), so all ~155 response sites are covered from one place, and it never overwrites a `_hint` a handler already set.++---++## Filing issues against AD (and the other repos you depend on)++You WILL find AD-core bugs and gaps while building your bridge. That is expected and useful. But file them in the RIGHT repo's issue list, or the people who can fix them never see it.++**The rule: an issue lives on the issue list of the repo that OWNS the code that must change.**++- A bug in YOUR bridge's verb / hint / self-heal / status chip goes to **YOUR page's issue list** (or you just fix it, since you own it).+- A missing or broken **AD-CORE** capability (a lifecycle verb, a spawn / provision / bind behavior, the relay passthrough dropping a field, a manifest field AD must honor, the status-chip contract) goes to **`adom/adom-desktop`**, NOT your own page. AD-core's maintainers and AI watch `adom/adom-desktop`; they do NOT read your bridge page's issues. **An AD ask filed on your own page is a note to yourself.**+- A **wiki or CLI** bug goes to `adom/wiki`. A **sibling bridge's** bug goes to that bridge's page.++**How (the CLI):**++```bash+adom-wiki issue list adom/adom-desktop # FIRST: skim for a dup, comment if one exists+adom-wiki issue create adom/adom-desktop \+ --title "<verb or subsystem>: <the gap in one line>" \+ --category bug-report \+ --body "$(cat your-writeup.md)"+```++**Write the body like a good bug report:** what you hit live (with the date and the AD version), the measured behavior, the AD-owned root cause if you found one, and a concrete ask. Separate clearly what is AD-core's to fix from what is yours, and say so explicitly, so the two are never conflated.++**After you file:** the AD-core thread replies on that issue. Read the reply, it may change your plan (for example "fixed in AD X.Y, bump your pin"). That issue thread is the cross-repo channel; keep the loop closed there.++**Why this matters most for AD:** AD-core spawns you, provisions your runtime, relays your verbs, and installs you, so AD is the repo you will file against most often. Get the destination right the first time. The established precedent all sits on `adom/adom-desktop`: #26 and #27 (pup to AD, Chrome for Testing), #16 (pup to AD, window-verb interception), #3 / #20 / #21 (Bridge SDK asks).++---+ ## Self-audit checklist — run this when asked to "audit against the SDK" When a maintainer says *"audit your code, skills, README, and wiki page against the Bridge SDK,"* **this is the checklist.** Each item names its section below; fix every miss, then re-check.@@ -701,6 +768,30 @@ Your `/health` (200) makes the chip green. Optionally return `led` (`green`/`yel **"My bridge keeps exiting and I can't see why" (read this).** Your own stdout log truncates on every respawn, so a crash-then-restart erases its own cause. `bridge_log_read` therefore also tails **AD's lifecycle audit log** for your bridge, a separate append-only file (`~/.adom/bridge-logs/<name>.ad.log`) that survives respawns, shown under an `===== AD bridge lifecycle =====` header. It records every spawn, reap, duplicate-collapse, and `bridge_kill` with the reason, so you can tell "AD reaped it as a duplicate" or "the `bridge_kill` verb stopped it" or "it was reaped before a fresh spawn" apart from "it crashed on its own." If the audit log shows AD never stopped it, the exit is inside your process. +## Logging: AD owns the FILE, you own the VOLUME++Every bridge writes to stdout, AD captures it, and nobody asks the volume question until someone's log is a firehose. The split:++- **AD owns the FILE.** AD spawns you and captures stdout/stderr, so the file and its rotation are AD's. A bridge cannot rotate a file another process holds open, and bounded logs have to be a platform guarantee rather than per-author boilerplate.+- **You own the VOLUME.** How much you emit is the half a tidy platform cannot fix for you.++*(READING the log is the section immediately above: `bridge_log_read` plus AD's separate lifecycle audit. This section is about what you WRITE.)*++**Do NOT write your own parallel log file.** Two log files means two sources of truth and double the disk for the same bytes. pup built one (a rotated `pup.log`) and deliberately reverted it. If you think you need your own log, what you probably want is for AD to scope `bridge_log_read` to your bridge: file that against `adom/adom-desktop` (see "Filing issues against AD" above) instead of forking the log.++**The five patterns that keep a bridge out of firehose territory:**++1. **Never log per-item inside a loop over live state.** This is the single biggest source of volume. A drag-detection check logged one line PER TAB per check, all of them saying "(same)", so a 12-tab window emitted 12 useless lines every time the check fired. **Log the exception (the tab that moved), never the roll call.**+2. **Collapse consecutive identical lines.** Wrap `console.log` once, hold the last message, and emit `^ last line repeated Nx` when it changes. A retry loop then costs 2 lines instead of 200. Collapse only EXACT consecutive repeats, so no distinct event is lost. About 15 lines of code.+3. **Log static facts once per session, not per call.** "no favicon on this page" was emitted on every taskbar-badge update. It is a property of the page, not an event, and because the repeats were not consecutive the collapser could not catch them. Gate it behind a per-session flag.+4. **DO log every incoming verb, one compact line.** This is the one place to ADD volume. A log that records what the bridge DID (park, identity, overlay) but never WHAT WAS ASKED of it cannot answer "what foregrounded this window?" after the fact. Include only the args that change behavior, and skip your own log-read verb so reading the log does not pollute it. Put the caller thread on this line too (the shape is in "Caller provenance" above):++ ```+ [verb] browser_open_window session=parkedge url=https://example.com owner=parktest+ ```++5. **Never let logging throw.** Wrap the whole path in try/catch. A logging failure must not take the bridge down.+ --- ## Publish checklist (the whole modern flow)
bridges-SDK.md+91@@ -323,6 +323,73 @@ This SDK evolves. When it does, AD posts a re-audit notice to **YOUR bridge's wi --- +## Ask the AI to report bugs, in the OUTPUT, not the skill file++You cannot reproduce every environment. Your bridge runs on machines with browser installs, OS versions, security policies, hardware and concurrency patterns you will never have locally. **The AI driving your bridge is standing on exactly that machine.** It is the only party holding the failing response, and the moment it holds it is the only moment it will file anything.++So make the invitation part of your verb output, the same way `_hint` is. This is THE ONE PRINCIPLE at the top of this page applied to feedback: the AI almost never reads your on-disk SKILL.md, and it ALWAYS reads the output of a CLI call.++**The evidence that this channel works.** In roughly two days, wiki issues filed against the puppeteer bridge produced: a CPU-pegging orphaned-renderer bug that froze a laptop and forced a reboot (#14, #21), a respawn failure that broke the bridge on every idle cycle (#15), a session-tracking bug where windows were open and drivable but reported as zero (#16), a repo-versus-release divergence that would have silently reverted five releases (#19), and a concurrency and readiness report that caught a live blocking regression shipped hours earlier (#22). **Not one of those would have been found on a maintainer's machine.** They came from real installs: different Chrome and Edge combinations, different AD versions, concurrent agents, a macOS box, a stalled download.++**Return a `_reportIssues` field naming YOUR page's issue list, with the exact commands:**++```jsonc+{+ "success": false,+ "errorCode": "…",+ "_hint": "…",+ "_reportIssues": "THIS MAY BE A <BRIDGE> BUG. PLEASE REPORT IT. Check for a duplicate with `adom-wiki issue list adom/<your-slug>`, then file: `adom-wiki issue create adom/<your-slug> --title \"<one-line symptom>\" --category bug-report --body \"<what you ran, what you expected, what happened, the VERBATIM response JSON, the bridge version from bridge_list, and the OS>\"`. Reports from real machines are the only way this bridge gets correct. (An AD-core problem, such as the relay, bridge lifecycle or caller identity, belongs on adom/adom-desktop instead.)"+}+```++**When to attach it. Throttle it, or the AI learns to skip it:**++| Moment | Why |+|---|---|+| **Always on a failure** | The highest-value moment: a bug just happened and the evidence is still in the response. |+| **Once per bridge process, on the first verb** | Orientation, so the AI knows where to report *before* anything breaks. |+| **Occasionally after that** (e.g. every ~40th call) | A quiet reminder on a long-running session without taxing every response. |++A line on **every** response is noise that trains the caller to ignore the field. A line on every **failure** is a bug report waiting to be filed.++**Make it actionable, not a slogan.** "Report bugs" produces nothing. Give the AI the exact `adom-wiki issue create` command, your slug, a `--category`, and the list of evidence to include (the verbatim response JSON and your bridge version are the two that make a report reproducible). Tell it to check for a duplicate first: an `issue list` call costs nothing and keeps your page clean.++**Route the report to the repo that owns the code.** Say explicitly, in the same string, that AD-core problems (the relay and `/command` passthrough, spawn and provisioning, bridge lifecycle, caller identity) go to **`adom/adom-desktop`**, not to your page. Authors get this wrong in the other direction too, which is the next section: a misfiled issue is a note to yourself that the people who can fix it never read.++**Let the user turn it off.** Ship a settings toggle (pup uses `browser_configure {reportIssues:"off"}`) so a user who finds it noisy can silence it without losing functionality. Default it **on**: the cost is a few tokens on failures, and the benefit is the bug class you would otherwise ship to every user.++**Reference implementation:** the puppeteer bridge does this at its single `sendJSON` chokepoint (v1.9.95), so all ~155 response sites are covered from one place, and it never overwrites a `_hint` a handler already set.++---++## Filing issues against AD (and the other repos you depend on)++You WILL find AD-core bugs and gaps while building your bridge. That is expected and useful. But file them in the RIGHT repo's issue list, or the people who can fix them never see it.++**The rule: an issue lives on the issue list of the repo that OWNS the code that must change.**++- A bug in YOUR bridge's verb / hint / self-heal / status chip goes to **YOUR page's issue list** (or you just fix it, since you own it).+- A missing or broken **AD-CORE** capability (a lifecycle verb, a spawn / provision / bind behavior, the relay passthrough dropping a field, a manifest field AD must honor, the status-chip contract) goes to **`adom/adom-desktop`**, NOT your own page. AD-core's maintainers and AI watch `adom/adom-desktop`; they do NOT read your bridge page's issues. **An AD ask filed on your own page is a note to yourself.**+- A **wiki or CLI** bug goes to `adom/wiki`. A **sibling bridge's** bug goes to that bridge's page.++**How (the CLI):**++```bash+adom-wiki issue list adom/adom-desktop # FIRST: skim for a dup, comment if one exists+adom-wiki issue create adom/adom-desktop \+ --title "<verb or subsystem>: <the gap in one line>" \+ --category bug-report \+ --body "$(cat your-writeup.md)"+```++**Write the body like a good bug report:** what you hit live (with the date and the AD version), the measured behavior, the AD-owned root cause if you found one, and a concrete ask. Separate clearly what is AD-core's to fix from what is yours, and say so explicitly, so the two are never conflated.++**After you file:** the AD-core thread replies on that issue. Read the reply, it may change your plan (for example "fixed in AD X.Y, bump your pin"). That issue thread is the cross-repo channel; keep the loop closed there.++**Why this matters most for AD:** AD-core spawns you, provisions your runtime, relays your verbs, and installs you, so AD is the repo you will file against most often. Get the destination right the first time. The established precedent all sits on `adom/adom-desktop`: #26 and #27 (pup to AD, Chrome for Testing), #16 (pup to AD, window-verb interception), #3 / #20 / #21 (Bridge SDK asks).++---+ ## Self-audit checklist — run this when asked to "audit against the SDK" When a maintainer says *"audit your code, skills, README, and wiki page against the Bridge SDK,"* **this is the checklist.** Each item names its section below; fix every miss, then re-check.@@ -701,6 +768,30 @@ Your `/health` (200) makes the chip green. Optionally return `led` (`green`/`yel **"My bridge keeps exiting and I can't see why" (read this).** Your own stdout log truncates on every respawn, so a crash-then-restart erases its own cause. `bridge_log_read` therefore also tails **AD's lifecycle audit log** for your bridge, a separate append-only file (`~/.adom/bridge-logs/<name>.ad.log`) that survives respawns, shown under an `===== AD bridge lifecycle =====` header. It records every spawn, reap, duplicate-collapse, and `bridge_kill` with the reason, so you can tell "AD reaped it as a duplicate" or "the `bridge_kill` verb stopped it" or "it was reaped before a fresh spawn" apart from "it crashed on its own." If the audit log shows AD never stopped it, the exit is inside your process. +## Logging: AD owns the FILE, you own the VOLUME++Every bridge writes to stdout, AD captures it, and nobody asks the volume question until someone's log is a firehose. The split:++- **AD owns the FILE.** AD spawns you and captures stdout/stderr, so the file and its rotation are AD's. A bridge cannot rotate a file another process holds open, and bounded logs have to be a platform guarantee rather than per-author boilerplate.+- **You own the VOLUME.** How much you emit is the half a tidy platform cannot fix for you.++*(READING the log is the section immediately above: `bridge_log_read` plus AD's separate lifecycle audit. This section is about what you WRITE.)*++**Do NOT write your own parallel log file.** Two log files means two sources of truth and double the disk for the same bytes. pup built one (a rotated `pup.log`) and deliberately reverted it. If you think you need your own log, what you probably want is for AD to scope `bridge_log_read` to your bridge: file that against `adom/adom-desktop` (see "Filing issues against AD" above) instead of forking the log.++**The five patterns that keep a bridge out of firehose territory:**++1. **Never log per-item inside a loop over live state.** This is the single biggest source of volume. A drag-detection check logged one line PER TAB per check, all of them saying "(same)", so a 12-tab window emitted 12 useless lines every time the check fired. **Log the exception (the tab that moved), never the roll call.**+2. **Collapse consecutive identical lines.** Wrap `console.log` once, hold the last message, and emit `^ last line repeated Nx` when it changes. A retry loop then costs 2 lines instead of 200. Collapse only EXACT consecutive repeats, so no distinct event is lost. About 15 lines of code.+3. **Log static facts once per session, not per call.** "no favicon on this page" was emitted on every taskbar-badge update. It is a property of the page, not an event, and because the repeats were not consecutive the collapser could not catch them. Gate it behind a per-session flag.+4. **DO log every incoming verb, one compact line.** This is the one place to ADD volume. A log that records what the bridge DID (park, identity, overlay) but never WHAT WAS ASKED of it cannot answer "what foregrounded this window?" after the fact. Include only the args that change behavior, and skip your own log-read verb so reading the log does not pollute it. Put the caller thread on this line too (the shape is in "Caller provenance" above):++ ```+ [verb] browser_open_window session=parkedge url=https://example.com owner=parktest+ ```++5. **Never let logging throw.** Wrap the whole path in try/catch. A logging failure must not take the bridge down.+ --- ## Publish checklist (the whole modern flow)