Skip to content

update io.pilot.bowmark v1.0.1: attributable app-store traffic, and a demo that fits a small context - #99

Merged
Alexgodoroja merged 3 commits into
pilot-protocol:mainfrom
Metroxe:bowmark-channel-header
Aug 5, 2026
Merged

update io.pilot.bowmark v1.0.1: attributable app-store traffic, and a demo that fits a small context#99
Alexgodoroja merged 3 commits into
pilot-protocol:mainfrom
Metroxe:bowmark-channel-header

Conversation

@Metroxe

@Metroxe Metroxe commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

One file, submissions/io.pilot.bowmark/submission.json, version 1.0.0 → 1.0.1.

Thanks for the e2e writeup on #97: the broker detail in it is what made this PR possible, and what made me throw away my first attempt.

1. Attribution, via the method path

We cannot currently tell Pilot-driven traffic apart from anyone else's. Our MCP endpoint carries the installing directory in the URL (/mcp/registry, /mcp/smithery), but the two REST routes the adapter fronts are the plain published ones, so an app-store arrival is indistinguishable from someone who pasted the endpoint by hand.

"path": "/v1/library"   ->  "/v1/pilot-app/library"
"path": "/v1/run"       ->  "/v1/pilot-app/run"

pilot-app is a registered destination on our side, live in production now. An unrecognised segment falls through to normal handling rather than 404ing, so this cannot break in the direction that matters.

My first attempt was a second backend.headers[] entry, and it would have silently done nothing. Submission.BrokerEntry takes the first non-empty header as AuthHeader and breaks, so a second entry never reaches broker.AppEntry; and broker.go builds a fresh upstream request carrying only Content-Type and the injected key, exactly as its comment says. I ran your broker locally against an echo upstream to be sure:

UPSTREAM RECEIVED GET /v1/pilot-app/library?query=flights
   header: Authorization: Bearer <injected>
   header: Content-Type: application/json

The path survives, no custom header does. So the header is gone from this PR and the path carries it. Nothing changes on your side: allow is derived from the same http.path values, so registration and forwarding stay consistent by construction.

If arbitrary header pass-through is ever interesting to you as a feature, we would use it, but the path works today and needs nothing from you.

2. The demo now scores 100.0, from 90.0

demo-score put us at 90.0 on #97, and the whole 10 points were brevity: the rendered SKILL was 5145 bytes against the 3000 target. Since that skill is injected into a small-context agent's window, that is a real cost and not just a number.

#97 this PR
Score 90.0 100.0
Rendered SKILL 5145 bytes 2982
First-call proxy 1.00 1.00
Examples 5 3

The counter-intuitive part, for anyone reading this later: cutting two examples cost nothing. The rubric bands examples at 2 to 6, so 3 and 5 score identically, and the two we dropped were a second fan-out that duplicated the first and a Promise.all whose lesson the remaining drill-down example already teaches. What is left covers the three genuinely different shapes: a capability that fans out across sites, reading an arbitrary page, and calling one named provider with two dependent calls in a single script.

3. One line that would have failed your validator

next_steps.edges[2].then[0].why had grown to 242 chars against your 160 limit, from a copy change we made after #97 merged. TestAllSubmissionNextStepsValid caught it. Fixed here.

Validated

go test ./internal/publish/ ./internal/demo/ ./internal/demoeval/ ./internal/nextsteps/ all pass off current main, and demo-score reports 100.0 / ok.

Changelog

  • Route the app's two methods through /v1/pilot-app/*, so calls arriving from the Pilot Protocol app store are attributable. No change to method names, parameters, or behaviour.
  • Rewrite the product demo to fit a small context window: 5145 bytes down to 2982, three worked examples covering three distinct shapes rather than five with overlap, and tighter gotchas.
  • Document incomplete.failures[].fixable on a partial result, so an agent can tell its own rejected argument from a site that did not answer, and retry only what is worth retrying.

@Metroxe Metroxe changed the title update io.pilot.bowmark: declare X-Bowmark-Channel install-attribution header update io.pilot.bowmark: install-attribution header, and the fixable-failure guidance Aug 4, 2026
@Metroxe Metroxe changed the title update io.pilot.bowmark: install-attribution header, and the fixable-failure guidance update io.pilot.bowmark v1.0.1: attributable app-store traffic, and a demo that fits a small context Aug 4, 2026
@Metroxe
Metroxe force-pushed the bowmark-channel-header branch from 9651147 to 3f34af9 Compare August 4, 2026 19:21
@Alexgodoroja

Copy link
Copy Markdown
Collaborator

Verified and merged. Your three claims all check out independently.

The routes. GET /v1/pilot-app/library and POST /v1/pilot-app/run both answer 200 in production. The old /v1/library and /v1/run still answer too, and so does a made-up segment (/v1/not-a-real-channel/library), so the fall-through is real and the transition is safe in both directions — which means the broker swap and the version rollout do not have to be simultaneous. Worth saying explicitly, because it is the property that makes this change cheap.

Your read of BrokerEntry is right, and thank you for chasing it down rather than shipping the header and assuming. First non-empty header wins and breaks, and the upstream request is rebuilt with only Content-Type plus the injected key. A second header entry would have been silently dropped. Routing the attribution through the path is the correct call given that, and you are right that it needs nothing from us structurally: allow is derived from the same http.path values.

It does need one operational thing, which is on us, not you: the broker's allow-list is registered configuration rather than something derived per call, so it has to be swapped to /v1/pilot-app/* before 1.0.1 reaches the catalogue. That is in hand and is why the catalogue entry is not merging in the same breath as this PR.

The demo. demo-score reports 100.0 here, up from 90.0, with the rendered SKILL at 2982 bytes against the 3000 target. Your point about the rubric banding examples at 2–6 is correct and is the sort of thing that is invisible unless someone reads the scorer, so it is useful to have it written down on a public thread.

Gates. verify-submission builds and verifies all four platforms; verify-update passes (1.0.1 forward, owning key); TestAllSubmissionNextStepsValid — the one that caught your 242-char why — is green, along with the demo, gateway and cross-app step validators.

Production bundles for 1.0.1 are built, signed with the same publisher key, and live on the artifact registry with each public URL fetched back and sha-checked. Runtime e2e against them follows the broker swap.

One note for next time, since it cost nothing here but could: 1.0.0's catalogue entry never merged, so the live catalogue is still on 0.1.0. 1.0.1 supersedes it and goes out directly. No user ever sees a 1.0.0.

@Alexgodoroja
Alexgodoroja merged commit eaf5db4 into pilot-protocol:main Aug 5, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants