Single Source of Truth for Task Status
Last Updated: 2026-10-04
The production catalog plan is active. Its canonical owner is
agentstation/starmap, at docs/plans/starport-production-catalog-plan.html.
It owns catalog lifecycle, configuration, storage, request latency, operator UX,
documentation, the Starport README, and its demonstration.
The canonical plan holds the current task status and the only status ledger. PR #366 merged the first documentation and qualification changes. All six native archive jobs passed. The plan records their evidence and the remaining production qualification work.
The ledger contains 40 tasks, 50 primary cases, and 324 required subcases.
Eight additional local checks supplement the candidate gate without qualifying incomplete publication cases.
The activation proof is proof/starport-production-catalog/activation-2026-09-05/ beside the canonical plan.
Historical storage, latency, and audit evidence remains unchanged.
CSP6.1 now standardizes both products on Go 1.27.1. It preserves behavioral and platform checks while removing older compiler coverage. The canonical plan records current qualification and merge status.
On 2026-10-04, CSP21 found a loader regression from #384.
The environment decoder materialized an empty inference destination approval set. Every loader-built configuration then denied every inference destination.
The fix adds the noinit option on the field and two loader-composed regression tests.
CSP21 also adds STARPORT_<PROVIDER>_INFERENCE_BASE_URL. It approves one operator inference origin for environment credentials.
CSP6.2 repairs recognition billing and protocol facts across both projects. Its local implementation preserves actual units, measured usage, and charges after request failures. Paired qualification, review, module publication, and merges remain open.
CSP16 selects one deployment configuration authority.
Shared management stores catalog deployment settings as SQL revisions, with an audit record and a fleet policy fence.
CSP16.1 adds the HTTP configuration API, the local file writer, shared credential saves, and operation receipts.
CSP16.2 adds explicit fleet baseline promotion with starport catalog promote-baseline and starport catalog baseline-status.
The command records a request in shared storage and never takes the publication lease.
The lease holder executes the request and records a receipt that makes a retry with the same operation ID exact.
Rollback and a console view remain out of scope.
CSP19 adds one deployment recipe for each of the seven architecture targets. Each recipe states its durable owners, memory state, admission, latency targets, checks, and recovery. CSP22 owns the latency qualification. CSP19.1 owns the local-to-shared move.
Both Compose recipes run with a read-only root file system and tmpfs scratch. A deployment that writes outside the declared mounts stops at start. The fleet recipe test replaces both gateway containers and reads the records again.
CSP19.1 qualifies the move of a populated local deployment to the shared recipe.
Its tests capture Badger, SQLite, and file storage, then prepare, inspect, and activate into Valkey, PostgreSQL, and object storage.
They cover record parity, typed refusals, a second replica, and rollback to the local stores.
A local gateway does not refuse a start after backup close, so the external writer fence is mandatory.
Catalog and fixture tests prove that the fleet leader promotes a newer packaged baseline over the moved head. The fixture test runs the shared gateway, because only a running gateway executes a promotion request.
The move copies process-scoped keys without a filter. A local source writes none, and a moved runtime migration receipt fails closed.
CSP20 aligns the README with the first-use sequence: install, catalog inspection, temporary gateway, request, client, and persistent path. The README owns the three credential roles, the path anchors, the storage roles, and the refused development selectors. It links each fact to its site page. CSP24 owns the final recording and the released installer evidence.
The tests in cmd/starport/readme_test.go prove the README order, links, and claims against the performance profile.
The test TestDocumentedInferenceRequestStreamsThroughGateway sends the README request body through the gateway to a fake provider.
The test TestModelsSearchAndShowWithoutCredentialsOrNetwork runs the catalog commands without credentials or network.
The candidate-install CI job installs each candidate archive on its native runner.
The candidate-install job runs only on pull requests, as its parent release-snapshot does. A main push run has no install evidence.
The install evidence therefore comes from the final pull request run. Its source commit matches the squash-merged tree.
The format 4 capture records the run event and the pull request number. A format 3 capture fails an install entry.
CSP19.2 adds starport backup write-history, which writes the independent history package for a controlled stop.
The package holds only the final KV and SQL authorization rotations, bound to the backup and the closed target digest.
The command records evidence digests, requires the operator attestations, and changes no target store.
The activation, adoption, and measurement tests build their final-only packages through this writer.
The fleet recipe test writes the package and activates a restored target with the image.
No shipped command writes prefix steps for activity after the backup.
Console primitive migration. Move the remaining hand-rolled controls onto
their shadcn counterparts, one primitive per pull request, each with a variant
set tuned to DESIGN.md before any call site moves: Form buttons to
Button (radius 6, heights 32 and 36, the four DESIGN variants), Form
fields to Field, Select to NativeSelect, Pill to Badge, Card to
the shadcn Card, LoadingFailed to Empty and Alert, and the sonner
toasts to the Base UI toast. Triage the oxlint React plugin findings recorded on
2026-09-21 (nine set-state-in-effect, five purity, one refs, one
exhaustive-deps) before enabling that plugin; each one is a deliberate
pattern today (a live tokens-per-second read in render, a state reset on a
prop change) whose fix changes runtime behavior. Open when a maintainer picks
it up; no plan file exists yet.
| Task | Team | PR | Completion Date | Notes |
|---|---|---|---|---|
| Usage test fixture retention | Usage | #381 | 2026-09-21 | Repaired eight internal/usage tests that failed on every backend from 2026-09-20 with no code change, the eighth arriving with #377. An aggregate counter expires at its window end plus the retention, an absolute instant, and the fixture pinned every record to 2026-08-20, so the counters were born expired once that date was a month old. The fixture is now noon today in UTC, inside one day, week, and month window and inside retention on any date the suite runs. |
| shadcn lint and skill adoption | Console | #380 | 2026-09-21 | Made the DESIGN.md ownership rule enforceable. @shadcn/lint 0.1.5 runs under oxlint 1.85.0 as pnpm lint, the first step of pnpm check, with all six rules at error level: a component under components/ui owns its color, typography, spacing, shape, effects, and motion; a call site adds layout alone; every value is a token; a dynamic value is a CSS custom property that a static utility reads. The baseline reported 306 findings (217 restyles, 47 arbitrary values, 36 inline styles, 4 dynamic classes, 1 raw color, 1 array construction); the tree now reports none. The fixes surfaced five design drifts and closed each at the source: a 10 px step that the scale never named is now 2xs (10/14), micro-labels that borrowed the wordmark's 0.08 em now use tracking-caps (0.04 em) and the wordmark alone uses tracking-wordmark, twenty titles restated a tracking the lg, xl, and 2xl steps already carry, the model picker and the chart tooltip drew their own shadows instead of shadow-overlay, and one panel named a bg-bg-base token that never existed. IconButton and ExternalLink became variant-owned (cva) primitives so no call site paints a button or a link, TabsList gained a sm size, and every meter, virtual list, data-table row, skeleton grid, chart swatch, and entity logo moved its inline style to a custom property. cn comes from the cn package (shadcn migrate cn), every template-literal className in the tree (71 sites in 35 files) now composes through it, shadcn is at 4.21.0 on Base UI 1.8.0, lucide-react moved to 1.47.0, and .github/dependabot.yml gained an npm ecosystem for console/ so the console packages get the same weekly grouped bumps as the Go modules and the actions. The shadcn skill is installed project-local at .agents/skills/shadcn, pinned by skills-lock.json, with .claude/skills/shadcn a symlink. DESIGN.md gained an Ownership section, the 2xs step, the tracking tokens, the IconButton and ExternalLink variants, and the lint and skill mapping; console/README.md and AGENTS.md record the command and the rule. |
| Catalog distribution | CAT | #360–#362, starmap#116–#123 | 2026-09-04 | Made the published Starmap catalog the default catalog source, and made Starport a connected consumer of it. Starmap publishes an immutable catalog-<digest> release for every generation, attests each archive with Sigstore, and points a mutable channel document on the protected Git branch catalog/v1 at the current release. The connected runtime in github.com/agentstation/starmap/runtime verifies the attestation before activation, and a generation identity survives a container restart. Starport #360 replaced the local refresh loop with that runtime. It reads the channel, activates a verified generation, and shows the catalog state in the console through one shell chip and its panel. The operator guide gained the catalog configuration reference and the topology guide, and the environment example names every canonical variable. Starport #361 pinned v0.16.3, and #362 pinned v0.16.5 and reads the catalog/v1 branch. The Starmap campaign verifier scripts/verify-catalog-distribution.sh is terminal at 68 conditions (CAT-V01–CAT-V68) and runs the Starport conditions against this tree. The proof root moved out of this repository at close. |
| Console polish campaign | CPL | #332–#358 | 2026-09-02 | Leveled the console up for production use and shipped it as v1.2.0. TanStack Query gained client defaults and query factories, and the router owns loaders, preload, and pending, error, and not-found states, so a page never fetches on its own. List state lives in search params. One primitive layer on shadcn and Base UI replaced the hand-rolled controls: dialogs and sheets, toasts bound to mutations, popovers, menus, tooltips, a command palette, a combobox, skeletons, field validation, and live regions. A formatting vocabulary, a shared data table, and a chart series descriptor with an interval and a legend made the numbers honest. The enterprise surfaces became honest too: system info, a webhook summary, settings sections, budget meters, confirmations for every cascading write, an audit investigation tool, usage guardrail fields with an export, and a batches panel. A copy and states pass covered the shell, models, providers, forms, chat, and the docs page under a navigation coverage test. Below 640 px the sidebar becomes a left sheet behind a top bar, the model picker becomes a bottom sheet, touch targets reach 44 px, and no route is wider than its viewport. scripts/verify-console-polish.sh holds 48 conditions and runs in CI. DESIGN.md, CHANGELOG.md, and console/README.md record the shipped system. |
| Enterprise readiness campaign | ENR | #309–#330 | 2026-09-01 | Closed the competitive gaps against the hosted gateways. internal/telemetry opened observability export: Prometheus metrics at /metrics, OTLP traces only when configuration names an endpoint, and NDJSON usage export through the activity API. internal/audit records every admin mutation with its actor over the relational store (migration 0006_audit_log), and the console renders the log. internal/events delivers signed webhooks under X-Starport-Signature for budget, job, and provider-health transitions. Surface parity landed the three routes a 2026 OpenAI SDK expects: /v1/responses on the chat contract, /v1/moderations behind its own scope, and gateway-executed /v1/batches over internal/jobs. Routing gained an opt-in spread mode inside the ranking band, and availability state shares through the KV contract when the operator configures a distributed store — and stays local when nothing is configured. internal/guardrails owns the fail-closed check pipeline: allow, redact, or refuse verdicts, Luhn card detection, and a moderation check that rides the account's own routing. Team budgets meter every key a team reaches and refuse pre-flight. The semantic cache answers beside the exact identity, opt-in twice over, and never crosses an account boundary. Preset saves became immutable numbered revisions with @preset/name@N pinning and rollback. The agent surface replaced the planned MCP server after the Stripe agent setup exemplar review: starport models search and show answer the embedded catalog offline with --json, and starport agent setup installs the embedded skill from skills/starport; MCP stays deferred with named re-open conditions. The campaign closed IDENTITY-001: deleting an API key now repairs a corrupt hash-index record and leaves a foreign one in place. scripts/verify-enterprise-readiness.sh is terminal at 33 conditions (ENR-V01–ENR-V33), authored red at baseline f7dfb6b, fully green at close, and runs in CI. |
| In-console incident log | Providers | #306 | 2026-08-29 | Let an operator read a provider's incident history without leaving Starport, in two provenances that never blur. The provider's own published log is read on demand through the catalog-declared health API — a Statuspage incidents.json, an RSS feed, or the Google Cloud incident feed — normalized into one incident shape, bounded to 90 days and 25 entries, and cached for five minutes; a provider whose convention carries no history (Hyperping, or no declared API) answers unpublished rather than an empty list, and a declared log that does not answer says unreachable, so a clean quarter is a stated fact and never a guess. The gateway's own record is the second provenance: internal/providers/state now returns the indicator transitions each poll pass produces — with a detection memory that survives an unanswered pass, so a recovery seen after an API gap still records the close — and the app layer persists them to internal/sqlstore (migration 0005_incident_transitions in all three dialects, 90-day retention pruned on write). The live indicator stays in the in-memory store the router reads; no model request touches the relational plane. GET /api/v1/admin/providers/{provider}/incidents serves both under one response, and the provider detail page renders them as an Incidents section with severity chips, deep links, an honest sentence per availability verdict, and an "Observed by this gateway" subsection on the deployment's own clock. |
| Credential sharing and identity | CSH | #281–#299 | 2026-08-29 | Gave one deployment many credentials, many people, and the grants that join them. internal/sqlstore opened the relational plane: an embedded, cgo-free SQLite database rides the binary by default, and a configured PostgreSQL or MySQL connect scales it, the way Badger pairs with Valkey. internal/providers/keyring now holds many shared credentials per provider, each one either open to every account or granted to some, chosen per credential at creation with open as the default; the source word on the wire stays shared, because who may use a credential is policy and not a new kind of credential. internal/account gained the operator's BYOK policy and the account's provider and model access, enforced at the BYOK put, at keyring resolution, and at route planning, so a refusal happens at the earliest seam that can name it. Account templates stamp creation defaults and never rewrite an existing account. internal/identity opened the people plane: users, teams, memberships, and account grants, acquired through gothic OAuth or WorkOS enterprise SSO into one user model, filling the identity slot that internal/localauth registered inert in the CSG campaign — that grant now mints a console session from a provider-asserted identity, which is the CSG revision this row records. An account is granted to a user or a team, a session resolves its reachable accounts through those grants, and granted shared credentials resolve through the same rows. The console gained members, teams, and grant surfaces. The campaign closed with the identity handoff: every identifier on the API-key surface now says API key, and the identity words refer only to people; the storage prefix identity:v1: and the stored JSON tags stay, because durable data does not move. scripts/verify-credential-sharing.sh is terminal at 23 conditions (CSH-V01–CSH-V23) and runs in CI. |
| Reranking | RNK | #260–#270, starmap#107–#108 | 2026-08-28 | Gave Starport a rerank route on models the catalog already knew. Starmap named the rerank operation and the two billing bases the providers use, then catalogued five offerings: three Cohere generations billed by the search unit, and two Voyage ones billed by the tokens they read. Jina is deferred, because it publishes no first-party price. internal/inference owns the canonical request, the ranked result, and the search unit in Usage, and the transport descriptor and connector call carry them to a provider without either protocol's vocabulary. The two codecs own every wire name each protocol states: the OpenAI path takes return_documents and echoes the ranked text only when asked, and the OpenRouter schema requires index, relevance_score, and document on every result. Both encoders refuse a result that names a document the request never held, or a score outside the unit interval, because either one produces output that reads as correct. POST /v1/rerank and POST /api/v1/rerank sit behind rerank:write alone: a rerank reads the documents the caller sent rather than a stored one, and it generates no message, so neither chat:write nor files:read covers it. Routing became operation-aware, so a rerank request to a model that serves only chat is refused at planning rather than at the provider, and the gateway bounds a request against the offering's document limit. The meter records search units and prices them, because a Cohere rerank turn reports no tokens at all and a token-reading meter would bill every such turn as free; an offering that bills in a unit it publishes no price for records no_pricing instead of a zero cost. The spend bound refuses a turn before the provider call, priced against the generation's cheapest search unit, because the floor is known before the money is spent. The catalog projection gained the search unit price and the document limit, which a Cohere offering had rendered as four empty price columns, and the OpenRouter offering shape gained both beside it. The console gained an operations column and facet, Unit price and Max docs columns in the offering table, and rerank:write in the key form, and it omits a rerank-only model from the chat picker. docs/ARCHITECTURE.md also gained the three operations and the five video routes that earlier plans never added to it. scripts/verify-reranking.sh is terminal at 22 conditions (RNK-V01–RNK-V22) and runs in CI. The proof root stays at docs/proof/reranking/. |
| Document parser | PLG | #249–#259, starmap#106 | 2026-08-27 | Made the OpenRouter file-parser plugin do what it says. Starport used to decode plugins as raw JSON, drop it, bill the caller, and report the field in a header the caller had to know to read; an unenforced plugin identifier is now HTTP 400 at the route. The gateway serves two engines and not OpenRouter's three: native reads a text layer in process, recognition sends a scanned page to a catalog model, and the two vendor names this catalog cannot reach draw a refusal that carries the served vocabulary rather than a silent fallback to some other vendor. internal/document owns the read, reaches no network address, and bounds a document at 200 pages and 15 seconds. Starmap gained the documents-recognition operation and a page_input price, and an offering that serves recognition without publishing a page price does not project at all, so a recognized page either carries a price or says no_pricing. The spend bound refuses a document before the provider sees it, priced against the lowest page price in the generation because the planner chooses the offering afterward; the record then carries the price of the offering the planner chose. An extraction cache keyed by account, content hash, engine, and catalog generation reads one document once inside a one-hour window, and extraction_cached separates a page an earlier turn paid for from a page no provider ever charged for. Usage records the engine, the pages attached, the pages recognized, the pages read in process, the milliseconds, and the recognized share of the cost, and the console reads them at /documents beside the catalogued recognition models and their page prices. Three silent projection defects closed on the way: the OpenRouter offering carried no operations field and dropped the list on every response, offeringPricing swallowed a page-only price, and the usage record never copied the cached flag. scripts/verify-document-parser.sh is terminal at 20 conditions (PLG-V01–PLG-V20) and runs in CI. The proof root stays at docs/proof/document-parser/. |
| Async media jobs | AMJ | #238–#248 | 2026-08-27 | Gave Starport a way to serve work a provider cannot answer inside one request. internal/jobs owns the record, the five states queued, running, completed, failed, and cancelled, and the rule that a terminal job never returns to running. The provider's own job identifier never reaches a caller, so a deployment moves a model between providers without breaking a caller mid-poll. Starport polls the provider itself under a bounded policy: the wait starts at two seconds and doubles to a 30-second ceiling, and a job that has not answered in an hour fails rather than polls forever. A finished asset is fetched into internal/blob behind a stated 24-hour retention window, because both provider families publish links that expire; a caller past the window reads HTTP 410 and the window length rather than a not-found. Accounting draws exactly once at the terminal state, so polling a completed job a hundred times costs one usage record, and a failed or cancelled job draws nothing. An account holds at most outstanding_jobs jobs open, defaulting to eight, and the gateway answers a full account with HTTP 429; it is a level and not a rate, so a terminal job frees the slot. Five routes under /v1/videos and /api/v1/videos submit, list, read, fetch the bytes, and cancel, all behind the single videos:write scope, because only the submitting account can read its own job. A completed job publishes expires_at while the bytes are there and drops it once they go, which is the name the OpenAI video object already uses. The console gained a Jobs page that submits from the catalog's videos-generations offerings, names a failure reason, marks an expired asset instead of rendering a player, and stops polling once every job is terminal. docs/OPERATOR-GUIDE.md gained a ## Video Jobs section covering the routes, the states, the STARPORT_JOBS_ settings, and the bound. scripts/verify-async-media-jobs.sh is terminal at 18 conditions (AMJ-V01–AMJ-V18) and runs in CI. The proof root stays at docs/proof/async-media-jobs/. |
| Files API | FIL | #226–#237 | 2026-08-27 | Gave Starport a place to keep a document between requests. internal/blob owns the bytes behind a four-method contract over streams, with a filesystem backend by default and an S3-compatible object store by configuration; an incomplete object-store selection refuses startup rather than falling back, because a deployment that expected a shared bucket and got a local directory would lose a file the moment a second node answered. internal/files owns the record, the two purposes user_data and vision, the retention window, and the stored-byte bound. The record and the bytes live apart by size: a record is small and read by a prefix scan, while a 512 MiB value in a KVStore would appear in every scan of files:v1:account:. Five routes under /v1/files upload, list, retrieve, read, and delete, behind the two scopes files:read and files:write, and every route scopes its answer to the calling credential. A chat request names a stored file instead of inlining it. Retention has a floor of one hour and the deployment window as its ceiling, so a caller shortens it and never extends it. The stored-byte bound is a level and not a rate: an upload raises it, a delete lowers it, and no interval resets it. The console gained a files view that renders the total against the account bound, reports a capped list as a floor, and asks before a delete. GET /api/v1/admin/info reports files.backend. scripts/verify-files-api.sh is terminal at 22 conditions (FIL-V01–FIL-V22) and runs in CI. The proof root stays at docs/proof/files-api/. |
| Model modalities | MOD | #216–#225 | 2026-08-27 | Made every modality Starmap records as a model fact reachable through Starport, in three stages. Phase A widened the canonical request to five content kinds — text, image, audio, document, and a file wire word — and carried them through both codecs, the connector adapter, the cache identity, the request body limit, and the token estimator, with the audio input prices relocated in Starmap first. Phase B returned non-text output: modalities and audio on the request, generated images and streamed audio chunks on the response, and media units in Usage with a cost for each kind. Phase C added the dedicated operations — internal/routing gained one named OperationSet that replaced three hardcoded guards, internal/catalog projected the five media operations and named the residual offerings it cannot route, internal/failure normalized a media provider failure, and internal/server published eight media routes behind the new images:write and audio:write scopes. The console then gained an output-modality facet separate from the input one, catalog-driven modality badges, a served-operations capability tier, and a transcript that renders a generated picture and plays a spoken answer beside its transcript; audio chunks decode on arrival and re-encode once, because joining separately padded base64 strings yields a payload no decoder accepts. scripts/verify-model-modalities.sh is terminal at 26 conditions (MMD-V01–MMD-V26) and runs in CI. It owns the media surface alone, so scripts/verify-openrouter-parity.sh keeps its own terminal count of 16 (decision MOD-D5). docs/ARCHITECTURE.md now tables the five modalities and the seven operations, and the proof root stays at docs/proof/model-modalities/. |
| Console session grants | CSG | #211–#214 | 2026-08-26 | Made minting a console session a named, registered grant instead of one hard-coded path, and made the words match. internal/localauth now owns a grant seam with three kinds: ticket, the one-time launch link the CLI hands the browser; local-token, the local admin token a reader pastes; and identity, which is registered, ships no provider, and refuses with ErrIdentityProviderNotConfigured held by a contract test, so an enterprise deployment fills a slot rather than reopening the seam. Added POST /console/session for the paste path and gave the console one first-contact page outside the shell (console/src/components/auth/) that derives its trust readout from the address it was served on rather than asserting Local-only, never stores the token, and keeps the gateway API key behind a disclosure as the different credential it is. Deleted ConnectCard and its 18 references; that exposed a gap the route guard could not cover, since a credential that dies mid-visit still satisfies hasCredential, so RootLayout now redirects on a rejection and /auth bounces only a credential that is present and not rejected. The layering then drove the vocabulary: a ticket and a token say where you are, only an identity provider says who you are, and the sign-in words are reserved for it across CLI output, route comments, the README, and the operator guide. scripts/verify-console-session-grants.sh is terminal at 16 conditions (CSG-V01–CSG-V16) and runs in CI; CSG-V16 is a reservation across every shipping surface rather than a single-literal grep. |
| Routable-offering signal | Routing | Starmap #102; Starport #204, #207 | 2026-08-25 | Closed the gap between what the Providers screen advertised and what a request could reach. Starmap's isChatCompletionModel disqualified any model whose pricing.operations block merely existed, so 24 offerings across google-ai-studio, google-vertex, and groq published no chat-completions operation and could never be routed; the predicate now asks whether the model charges for generated media (image, audio, or video output above zero) rather than whether it prices anything at all. Correcting it exposed a mirror defect — 25 embedding models, two Whisper models, and one image model declared neither an output modality nor a disqualifying tag — so those 28 model YAMLs were corrected too, and internal/bootstrap/offering_operations_test.go now cross-checks every published chat-completions offering against its canonical definition so the class of drift cannot return. On the Starport side, internal/catalog emits a routability verdict for every offering in the same pass that builds the routes, internal/providers/state projects them as a generation-bound routing field with an explicit unknown state, and the console excludes unroutable offerings from the card's available count and names the reason in a Routing column. Running the gateway locally then showed #204 reporting every offering as adapter_not_ready: the verdicts were pushed from three sites in internal/app, and the registry installs the runtime adapter set by replacing it on the control plane itself, after the only startup push. #207 moved the refresh to App.ProviderStates(), the single read accessor, so the verdicts follow the snapshot the caller is about to read. |
| Auth and onboarding campaign | AON | #185–#202 | 2026-08-25 | Separated five ideas the product blurred into one word. A gateway API key now only authenticates a caller and owns nothing else. A provider credential comes from one of three named sources — the process environment, a gateway credential the operator applies for the whole deployment at scope *, and BYOK, which is only what an account brings for itself at scope account:<id>. Added the internal/account seam with a canonical default account that carries account-wide limits and the credential strategy an operator uses to govern spend, the shared internal/limits vocabulary, and renamed internal/providers/byok to internal/providers/keyring, which owns the four source words. Added internal/authmode: authentication is required by default and an operator turns it off by --no-auth, config field, or console switch, with a non-loopback tripwire that needs --allow-remote-no-auth. Added internal/localauth so starport dev prints a one-time launch link that opens a signed HttpOnly console session instead of putting a gateway key in a browser. Gave each credential idea its own console screen and owner, and carried the served credential source into every usage record. scripts/verify-auth-onboarding.sh is terminal at 26 conditions (AON-V01–AON-V26) and now runs in CI. Clean breaking changes throughout; nothing had shipped, so no migration path was added. |
| Catalog, performance, and brand campaign | CP | #144–#179 | 2026-08-22 | Closed the Design Review No. 2 roadmap and absorbed the last three console-modernization tasks (CM13→CP12, CM14→CP18, CM15→CP19). Made the catalog a traversable provider/model/author graph with logos, detail pages, facets, and a global command palette; retooled the composer so presets live in the model picker and + attaches images; measured and published the per-request gateway overhead through x-starport-overhead-ms, a console p50/p99 stat, and a CI benchmark; swept the brand to the STARPORT wordmark, API Keys, and TTFT; fixed the gateway defects the review found (credential resolution, streaming 429 honesty, empty-completion caching, and the development-runtime catalog refresh, whose 11 MB generation value now stores as content-addressed chunks); and cut the React SPA over as the only console. scripts/verify-catalog-performance.sh is terminal at 20/20 and scripts/verify-console-modernization.sh at 21/21, both running in CI. |
| Console chat parity and streaming usage | Console | #140–#142 via #143 | 2026-08-21 | Restored the legacy chat UX details (#140), added KaTeX math and Mermaid diagram rendering in chat (#141), and normalized streaming usage: every chat stream ends with one usage frame — provider-reported when available, otherwise estimated by a startup-initialized tiktoken estimator — with a live tok/s badge during streams (#142). The whole open train (#125, #127–#142) landed on main through merge-train PR #143 as one linear commit per pull request. |
| OpenRouter parity campaign | ORP | #126–#139 via #143 | 2026-08-20 | Closed the OpenRouter feature-parity roadmap as a stacked pull-request train on top of #125. Shipped request logs and usage accounting (internal/usage, usage:v1: namespace, /api/v1/activity, console Usage page: #127–#130), the catalog freshness surface with console-triggered refresh (#131, #132), preset CRUD with @preset/ model resolution (#133), provider.sort and max_price routing completion (#134, #135), per-key budgets and allowed-model limits with 402 responses and X-Starport-Budget-* headers (#136, #137), and side-by-side model comparison in chat (#138). scripts/verify-openrouter-parity.sh keeps conditions ORP-V01 through ORP-V16 and runs in CI (#139). |
| Starport console revamp | Console | #125 | 2026-08-20 | Replaced the chat-only UI with a six-page embedded console (Overview, Chat, Models, Providers, Keys, Settings) designed from first principles as a local OpenRouter replacement. Renamed CHATUI_* config to CONSOLE_*, added catalog-driven credential_fields to the providers API, fixed provider-key timestamps to RFC 3339 UTC, and anchored the vendor/ gitignore rule. All verification gates and the OpenRouter SDK smoke checks pass. |
| Dependency direction hardening | DDH | Starmap #94; Starport #117–#123 | 2026-08-20 | Established 14 executable dependency rules, moved provider and resource ownership into Starmap, isolated Starport proxy and catalog contracts, corrected release VCS provenance, and passed all hosted checks for both implementation pull requests. |
| Package ownership refactor | POR | Starport #105–#110 and Starmap #74–#76 | 2026-08-12 | Moved packages to concept-owned paths in both repositories. Deleted unused HTTP transport code. All nine campaign assertions pass. |
| Automatic provider runtime | APR | #96–#103 | 2026-08-11 | Published immutable v1.0.3. Starport now derives executable providers and inference authentication profiles from one Starmap generation. It supports credential refresh, safe provider state, authenticated provider operations, and provider-neutral local development. |
| Catalog-driven provider runtime | CDP | #91, #93, #94 | 2026-08-11 | Published immutable v1.0.2. Provider YAML now drives the Starport runtime. Connectors hold no credential value. scripts/verify-catalog-driven-providers.sh keeps conditions CDP-V01 through CDP-V19. The pull requests hold the CDP3.1 and CDP7.1 secret-source measurements. |
| Starport developer experience | DX | #88 | 2026-08-10 | Published immutable v1.0.1 and the Homebrew cask. Verified exact-version installation on macOS and Linux, then merged release-readback hardening after all 10 CI jobs passed. |
| SPR3 | Release | #75 | 2026-08-09 | Stored compact terminal proof and removed the completed release control plane |
| SPR2 | Release | Release workflow | 2026-08-09 | Published immutable v1.0.0 with 13 verified assets and a public, attested, two-platform GHCR image at sha256:f4230687fdf664022e4be80031c4145ff2eb795ff200489216ea76ba4b64bc24 |
| SPR1 | Release | #73 | 2026-08-09 | Merged the complete v1 release candidate after all 10 CI jobs passed, including cross-platform race tests, official OpenRouter SDK compatibility, release contracts, security, and reproducible release snapshots |
| CI-002 | DevOps | #72 | 2026-08-04 | Made Gosec SARIF artifacts available on pull-request and default-branch runs without paid Code Security, and removed unused elevated workflow permissions |
| CI-001 | DevOps | #71 | 2026-08-04 | Confirmed that default-branch CodeQL SARIF upload is unavailable because Code Security is disabled for the private repository |
| SVA16 | Architecture | #69 | 2026-08-04 | Established the Starport v1 concept seams, made Starmap v0.3.0 the provider and model fact owner, separated catalog-acquisition auth from inference auth, added OpenAI and OpenRouter protocol contracts, and passed the cross-platform CI, security, race, fuzz, and architecture gates |
| P1-S4-4.2b | Backend | #30 | 2025-01-10 | Valkey storage implementation with full KVStore interface, pub/sub support for cache invalidation, transaction support with MULTI/EXEC, atomic operations with Lua scripts, batch operations with auto-pipelining, integration tests, valkey-go client integration |
| P1-S4-4.2a | Backend | #29 | 2025-01-09 | Cache architecture refactoring with data-type-specific strategies, pub/sub invalidation for multi-node deployments, hybrid caching (local + distributed), automatic deployment mode detection, proper cache coherence for security-critical data (API keys, presets), distributed-only for rate limits, 75%+ test coverage |
| P1-S4-4.2 | Backend | #28 | 2025-01-08 | Caching system with Ristretto in-memory layer, KV store persistence, cache key generation, TTL management, cache policies, invalidation logic, cache warming, metrics tracking, proxy handler integration, 75.3% test coverage |
| P1-S4-4.1 | Security | #27 | 2025-01-08 | BYOK implementation with OpenRouter compatibility, 5% pricing model, AES-256-GCM encryption, Argon2id key derivation, fallback strategies, provider validation, BYOK manager, API endpoints, usage tracking, response headers, 75%+ test coverage |
| P1-S3-3.7 | Backend | #19 | 2025-01-08 | Dynamic model fetching for Anthropic/Gemini/Groq, split GeminiConnector into GoogleAIStudioConnector and VertexAIConnector, 1-hour cache TTL, Vertex AI models (PaLM, Codey, Claude), 85%+ test coverage |
| P1-S3-3.6 | Backend | #18 | 2025-01-08 | Provider metadata & /api/v1/providers endpoint, enhanced /api/v1/models with full metadata (pricing, context, architecture), /api/v1/models/{model}/endpoints, 85%+ test coverage |
| P1-S3-3.5 | Backend | #17 | 2025-01-08 | Provider routing with preferences (order/only/ignore), health tracking, latency-based routing, cost optimization, sticky sessions, 76.2% test coverage |
| P1-S3-3.4 | Backend | #16 | 2025-01-08 | OpenRouter-compatible model routing with fallback chains, auto model selection, provider preferences, bounded availability, model_used field in responses |
| P1-S3-3.3 | Backend | #15 | 2025-01-08 | Proxy endpoints implemented with /v1 and /api/v1 routes, streaming support, request validation, connector initialization from config, 85.4% test coverage |
| P1-S3-3.2 | Backend | #13 | 2025-01-08 | All 6 LLM provider connectors implemented with streaming, OpenRouter-compatible model IDs, 84.0% test coverage |
| P1-S3-3.1 | Backend | #12 | 2025-01-08 | Model Connector Interface with streaming support, health checks, mock implementation, 90.6% test coverage |
| P1-S2-2.3 | Storage | #10 | 2025-01-08 | Core storage models with APIKey, Preset, ProviderKey, TokenBucket, AES-256-GCM encryption, 91.9% test coverage |
| P1-S2-2.2 | Storage | #7 | 2025-01-08 | Badger DB integration with full KVStore implementation, TTL support, backup/restore, compaction, 100% test coverage |
| P1-S2-2.1 | Storage | #6 | 2025-01-08 | Storage interface with KVStore abstraction, error types, serialization, mock implementation, 82.4% test coverage |
| P1-S1-1.5 | API | #5 | 2025-01-07 | Configuration system with env vars, .env files, validation, and hot reload for rate limits |
| P1-S1-1.4 | API | #4 | 2025-01-07 | HTTP server with chi router, middleware, health checks, 93% test coverage |
| P1-S1-1.3 | DevOps | #3 | 2025-01-07 | Development environment with CI/CD, Docker, and pre-commit hooks |
| P1-S1-1.2 | Backend | #2 | 2025-01-07 | Project structure with CLI framework and clean architecture |
| P1-S1-1.1 | Foundation | #1 | 2025-01-07 | Repository initialized with go.mod, LICENSE, and badges |
None. IDENTITY-001 closed on 2026-09-01. Deleting an API key now removes a corrupt hash-index record and leaves a foreign one in place. Neither defect blocks the delete, and runtime authentication still fails closed.
- Authentication uses hash-based identity lookup and fails closed.
- Response caching uses account-safe canonical semantic keys.
- HTTP middleware enforces rate limits through the concept repository.
- Starmap v0.16.x owns provider, model, offering, endpoint, operation, and acquisition-auth facts.
- Starport owns inference credentials, request policy, route planning, execution, and protocol adaptation.
- OpenAI and OpenRouter raw protocol smoke tests pass.
- The pinned official OpenRouter Python, TypeScript, and Go SDK gates pass.
- Release archives, SBOMs, checksums, attestations, and GHCR publication are fail-closed release requirements.
- Independent checks verify public immutable release
v1.1.0and its public, attested GHCR image atsha256:0fbb56d1424d1d0ff0e8aa8ea63c6bedbad62f00e175677b64bd14fc51910f14.
This file keeps task status and the Phase 1 completion history. The canonical
v1 design is in docs/ARCHITECTURE.md.