openai-admin release#1
Merged
Merged
Conversation
Directory skeleton, npm scripts through node wrappers, latest @stackql/provider-utils (0.7.6), fetch/clean scripts adapted from the sibling openai build with the inverse (keep-admin-surface) filter, README with the applicability note up front. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pins openai/openai-openapi at a3276900 (2026-07-14), the same ref and
sha256 the sibling openai build pins, recorded independently in
spec_pin.json. clean_specs.mjs keeps the /organization subtree (46
paths / 71 ops) plus the six /projects/{project_id} role/group paths
the sibling's filter dispatches here (10 ops); 162 paths / 242 ops ->
52 paths / 81 ops, every disposition reason-coded in filter_report.csv
and the partition reconciling exactly against the sibling's report.
swagger-parser validates the filtered artifact clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Blocked on OPENAI_ADMIN_KEY (not present on this machine - the nvidia/vsphere blocked-on-key pattern): executes unchanged once keys land. Probes: admin-key accept + standard-key reject on list-projects, the bucketed idiom with group_by form-explode encoding and next_page traversal, the derived-cursor directory traversal, audit-log bracketed filter pass-through, and the opt-in --lifecycle governance run (stackql-smoke-<stamp> project -> service account -> archive). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
81 operations, all mapped, none skipped: 37 select, 15 insert, 8 update, 16 delete, 5 exec across 29 resources / 10 services. Idiom classified per resource: 9 bucketed lists (8 usage capabilities + costs, page/next_page, group_by on all 9), 20 directory lists (list envelope, derived cursor). Update-POST bodies flagged; two rename-only exceptions (groups, certificates) annotated. clean_specs re-tags /organization/costs 'Usage' -> 'Costs' for the split. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CLAUDE.md candidates adjusted on subtree evidence: groups and roles added (the RBAC surface exists in the pin); certificates confirmed exposed (org and project scopes); usage capabilities enumerated as 8 (audio splits into speeches and transcriptions). The 15 fine-grained spec tags consolidate through service_names.json; split emits 10 service specs carrying all 81 operations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
all_services.csv populated from the endpoint inventory (joined by operationId - one source of truth). All validations pass: coverage both directions, unique method keys, unique path-param signatures per SQL verb, object keys on every list. Pilots green: usage+costs (bucketed, $.data, group_by), projects (governance lifecycle mapped; live run owed on key), audit_logs (derived cursor, filter pass-through). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… draft Evidence-backed answers to the phase 1 open questions: 8 usage capabilities enumerated from the pin; group_by wire name is plain 'group_by' (no bracket suffix - OpenAI delta vs anthropic); bucket projection decided as row-per-bucket with results as JSON (result items carry no time fields; objectKey cannot flatten parent fields - anthropic_admin evidence transferred); update-POSTs partial by construction with two rename-only exceptions; zero-activity and skip-with-notice postures recorded; the four-way token-spend union drafted against actual resource names as the docs acceptance artifact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…onfig
Reframes the build on the sibling openai repo as the archetype (k8s
references removed throughout).
Pagination corrected on generate-stage evidence: the surface carries
THREE idioms, not two. The RBAC family (groups, roles, role
assignments - 9 lists) returns {object, data, has_more, next} with an
explicit next cursor that nulls out on the last page - no first_id/
last_id, and no overshoot request. build_inventory now derives the
idiom structurally from the response envelope (next_page -> bucketed,
last_id -> cursor-derived, next -> cursor-next) and fails on a list
with no cursor field.
projects and users mix idioms, so a single --service-config cannot
cover them: post_process.mjs stamps the dominant idiom per service and
overrides the 4 deviating list methods at method level, per any-sdk's
operation -> resource -> service resolution chain, then validates all
29 lists resolve to their inventory idiom.
pre_normalize expands the object-typed effective_at query param into
its bracketed wire params (effective_at[gt] etc); org/project headers
are deliberately not injected (the admin key IS the org scope).
normalize: 175 allOf flattened, 172 anyOf nullable resolved, 4 opaque
objects lowered, zero residual variants.
Provider resolves: 10 services, 29 resources, 81 methods; meta-routes
suite passes with 0 non-selectable resources.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Docgen over the generated provider: 10 service pages, 29 resource pages, landing page. Site scaffold follows the sibling openai build (shared docusaurus-config vendored at build time, thin wrappers, provider identity in website/provider.js); CNAME and the slug-derived url agree on openai-admin-provider.stackql.io. yarn build passes. The landing content leads with the applicability note (organizations, admin key class, disjoint from standard keys, sibling openai pointer), then token spend and cost as rows (bucket + json_each idiom), the single-dimension group_by posture, governance and admin-key hygiene, and the audit log with double-quoted bracketed params. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tests/smoke_test.py (pystackql): resolution, key-class evidence (the standard key rejected through the provider via custom_auth - the disjointness proven provider-routed, not by a side-channel call), directory and project-child reads, the flagship (usage buckets, group_by, USD costs, all 8 capabilities), and cursor traversal assertions (limit=1 must return the unbounded row count - proves the cursor configs walk, for both entity idioms). Skip-with-notice on 401/403/404; zero-activity orgs pass with 0 buckets. The governance lifecycle is opt-in (--with-lifecycle): the API has no project delete, so archive is terminal and every run would leave a permanently archived project. group_by encoding settled on the wire rather than inferred, captured with --http.log.enabled and a dummy key: a scalar emits group_by=project_id; JSON-array and comma-joined values arrive as single literal strings (no fan-out), so one dimension per query is the honest posture. The pre_normalize effective_at expansion is confirmed the same way (effective_at%5Bgt%5D=...). Pipeline verified reproducible from clean: same counts throughout and a byte-identical generated tree. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three defects, all from examples written but never run - the mistake the dummy-key routing checks existed to prevent. 1. strftime()/date() in WHERE does not bind. StackQL evaluates no SQL functions when binding request params: start_time was silently dropped, emitting 'GET /organization/costs?' and a rejection. Only literals bind; examples now use literal epochs and say so. 2. date()/datetime() do not evaluate over a COLUMN - they fold constant args only, so date(1781481600,'unixepoch') works (per the maintainer's google example) but date(c.start_time,'unixepoch') returns 0, and can null out neighbouring columns in the same SELECT. strftime() handles columns correctly. All examples use strftime now. 3. limit defaults to 7 buckets, so any window over a week paginates - and bucketed auto-pagination is broken upstream (NOTES 12b): any-sdk re-escapes the base64 page token's '=' padding to %3D via Go's url.Values.Encode(); httpx (OpenAI's own client) sends '=' raw, and their cursor parser rejects the escaped form -> 400 'The page token is invalid'. Both encodings are legal per RFC 3986. Ruled out config, param drift and token corruption first, against a new mock. Workaround everywhere: set limit to cover the window. Adds tests/integration/mock_admin_server.mjs (all three idioms, request recording, page-token contract, bearer enforcement) - built to diagnose this. The smoke suite now sets limit on every bucketed query (it would have hit the same 400) and asserts the defect explicitly, flipping to PASS if it is ever fixed upstream. Both flagship examples now verified end to end: extracted verbatim from the generated docs page and run, returning real dates, project ids and amounts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ects Adds work-orders/ with two fileable specs (no gh CLI on this machine): WO-001 any-sdk - pagination config switch to send the request token unencoded. SetNextPage re-renders the query with Go's url.Values.Encode(), escaping a token's reserved characters; servers whose cursor parser does not percent-decode reject the result. Proposes requestToken.encoding: none|url (default url, backwards compatible) with an implementation sketch against standardTokenSemantic and the QueryParam branch. Carries the live evidence, the cross-client comparison, and what was ruled out first. WO-002 stackql - date()/datetime()/typeof() return 0 for a bare column argument. Narrowed with isolated probes: literal args work, an expression-wrapped column works (datetime(start_time + 0, ...)), a column in arg 2 works (strftime), and abs/upper/length/max/coalesce/ json_extract all handle a bare column in arg 1 - so it is neither the modifier nor argument position in general. Records the contagion (one bad call nulls neighbouring computed columns) and notes the functions are stock SQLite builtins via the vendored driver, so what reaches SQLite is the suspect rather than the implementation. Docs now read as capability statements: the usage/cost preamble states the four conventions (literal start_time, size limit to the window, one group_by dimension, strftime for epochs) with no commentary on engine gaps. Removes the pagination warning admonition; the only admonition left is the applicability note. Engine detail stays in NOTES.md and the work orders, where it belongs. All three published examples re-extracted from the generated page and run: real dates, project ids and amounts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e suite
The live --with-lifecycle run exposed two real problems behind the
reported failure.
1. projects.archive never dispatched. stackql v0.10.542 SIGSEGVs while
preparing an EXEC whose resolved response schema carries no
array-typed property (drm.GenerateSelectDML -> wrappedSchema.GetType
on a nil inner schema); archive-project returns a bare Project
object. The SQL layer reported no error, so the smoke test recorded
'archive project - PASS' while nothing was sent - three smoke
projects had been 'archived' across runs and were all still active.
This is the anthropic repo's documented v0.10.542 finding, reused
not re-derived: post_process.mjs now stamps response.schema_override
to a synthetic envelope carrying an array property, on exec-only
methods whose response lacks one. Exactly 1 method qualifies
(projects.archive); the 4 certificate execs return list envelopes
and are untouched. Verified live: POST .../archive -> 200
{status:archived}, and the project reads back archived.
2. Writes are not read-after-write consistent. A created project took
19s to become listable, which is what the original FAIL was. Every
read-back now polls with a bound (poll_until, --timeout 60s,
--poll-interval 3s): finding the created project, listing the new
service account, confirming the archived status. Timeouts report
diagnostics rather than a bare 'not found'.
Also drops the work-order references from smoke output (internal
business, independent of the tests) and the dangling work-orders/ paths
from README/NOTES.
Live run now green: 31 PASS, 1 SKIP (standard-key rejection, needs
OPENAI_API_KEY), 0 FAIL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copied verbatim from the sibling openai build (the archetype): they are provider-agnostic, keying off website/** only. - prod-web-deploy.yml: push to main touching website/** -> yarn build -> upload-pages-artifact -> deploy-pages, with the pages/id-token permissions and the github-pages environment. - test-web-deploy.yml: PR to main touching website/** -> build only, no deploy. Verified against this repo: website/yarn.lock is tracked (both the yarn cache key and --frozen-lockfile depend on it, and a frozen install passes with the lockfile unchanged); website/build is gitignored so CI builds fresh; static/CNAME (openai-admin-provider.stackql.io) and static/.nojekyll both land in the build output. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.