Skip to content

oci-extract: resolve operations and models from the HTTP surface, not Go names - #14

Merged
sinkog merged 1 commit into
develfrom
feature/oci-extract-generalize
Aug 3, 2026
Merged

oci-extract: resolve operations and models from the HTTP surface, not Go names#14
sinkog merged 1 commit into
develfrom
feature/oci-extract-generalize

Conversation

@sinkog

@sinkog sinkog commented Aug 3, 2026

Copy link
Copy Markdown
Member

P2.2-P2.4 were proven on vcn and subnet. Both live in core/network, so they
established that the pipeline is not resource-specific; they could not establish
that it is not service-specific. Measured against all 171 services of the pinned
SDK, it was.

The four assumptions that held for core/network and not for OCI

# Assumption Measurement
1 An operation has a request object IdentityClient.ListRegions(ctx) has none and builds its wire call with common.MakeDefaultHTTPRequest. It was dropped silently: 8047 of 8048 resolved, and nothing named the missing one
2 The create verb is Create, the delete verb is Delete core.Instance uses LaunchInstance/TerminateInstance; 570 of 1217 resources have no Create<R>Details
3 A resource is addressed by one path parameter, and it is its id objectstorage.Bucket is /n/{namespaceName}/b/{bucketName} — two, neither an id. 323 of 1481 Get operations (21.8%), across 65 of 158 services
4 Models are structs OCI declares 1014 models as interfaces (470 *Details/*Base); those parsed as absent

Assumption 2 is the dangerous one. The old code exited 0 with a valid draft-07
schema that had no required list, a create surface built from Update ∩ Read,
and neither a create nor a delete operation in its map — a schema that validates
and is wrong.

What replaces them

Lifecycle is now derived structurally from the HTTP surface rather than from Go
identifiers:

read       = GET  <readPath>
collection = readPath minus its trailing /{param}
create     = POST <collection>
update     = PUT <readPath>, else POST <readPath>
delete     = DELETE <readPath>
actions    = POST under <readPath>/

Body models come from the request struct's own contributesTo:"body" tag. One
convention survives as a fallback (Get<Resource>, only when no response models
are given), and the resolution records which route it took.

Silence became signal. -audit counts candidates separately from resolved
and exits 4; -schema/-policy report unresolved surfaces and exit 5, so
oci.generate cannot commit a schema whose create surface was never derived.

Verification

  • 8048/8048 operations resolved, 0 missing method/path, across 319 client
    files of the pinned SDK v65.121.0
  • Per service: core/network 271/271, core/compute 129/129, identity 145/145,
    objectstorage 56/56, database 456/456, dns 54/54
  • vcn and subnet are unchanged — oci-extract -diff reports neither a
    breaking nor a compatible change to their config schemas, and
    regression_test.go freezes their field set, policies, state size and
    operations against a written-out expectation. The bundles differ only by the
    additive path_params
  • CI green on 5c1e035

Scope limits — deliberate, not oversights

  • No new resource types ship. module/schemas/ is still vcn + subnet.
    The full sweep is a separate job
  • Polymorphic create models are not expanded. Eight resources whose
    Create<R>Details is an interface now report and exit 5 rather than emitting
    an empty create surface. Expanding them is discriminator semantics — a
    modelling decision, not extraction
  • No cic-primitives / YANG binding. That layer carries behavior, not shape;
    laying it over an incomplete mechanical surface would make it impossible to
    separate what came from the API from what we assumed

Review

Orchestrator review with independent re-verification, and an explicit list of
what was not re-verified, is in the cic-factory repo at
jobs/oci-extract-generalize/review.md.

…e, not Go names

P2.2-P2.4 were proven on vcn and subnet. Both live in core/network, so they
established that the pipeline is not resource-specific; they could not establish
that it is not service-specific. Measured against all 171 services of the pinned
SDK, it was. Four assumptions held for core/network and not for OCI:

1. An operation has a request object. IdentityClient.ListRegions(ctx) has none,
   and therefore builds its wire call with common.MakeDefaultHTTPRequest rather
   than request.HTTPRequest. It was dropped silently — 8047 of 8048 operations
   resolved and nothing named the missing one.
2. The create verb is "Create" and the delete verb is "Delete". core.Instance
   uses LaunchInstance/TerminateInstance; 570 of 1217 resources have no
   Create<R>Details. The name lookup found nothing and emitted a config schema
   with no required list and a create surface built from Update ∩ Read — a
   schema that validates and is wrong.
3. A resource is addressed by one path parameter and it is its id.
   objectstorage.Bucket is /n/{namespaceName}/b/{bucketName}: two, neither an
   id. 323 of 1481 Get operations (21.8%), across 65 of 158 services, have a
   count other than one, and nothing recorded them.
4. Models are structs. OCI declares 1014 models as interfaces (470 *Details or
   *Base); those parsed as absent, giving the same silent empty create surface.

Resolution now derives the lifecycle structurally: read = GET readPath, create =
POST on readPath minus its trailing /{param}, update = PUT readPath else POST
readPath, delete = DELETE readPath, actions = POST under readPath/. Body models
come from the request struct's own contributesTo:"body" tag. One convention
survives as a fallback (Get<Resource>, only when no response models are given)
and the resolution records which route it took.

Silence became signal: -audit counts candidates separately from resolved and
exits 4; -schema/-policy report unresolved surfaces and exit 5, so oci.generate
cannot commit a schema whose create surface was never derived.

Verified on the real pinned SDK v65.121.0: 8048/8048 operations resolved, 0
missing method/path across 319 client files. Per service — core/network 271/271,
core/compute 129/129, identity 145/145, objectstorage 56/56, database 456/456,
dns 54/54.

vcn and subnet are unchanged: oci-extract -diff reports neither a breaking nor a
compatible change to their config schemas, and regression_test.go freezes their
field set, policies, state size and operations against a written-out expectation.
The bundles differ only by the additive path_params, hence the re-pinned
extracted_schema_hash and the rebuilt guest.

CI also now triggers on feature/** branches, which it did not before.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEQCIGLo+rBakUqxWsKcaqtYS9eeXqgewbOPnhNu4xdh91MLAiBcKkd4R8M6ixoX1WgIrcxw7CFiD6khsarF3KwmcAV83w==
hash-algorithm = sha256
digest = M2tsElmF0suuGzMLzT8tx+dVYyCN60pUEReVVqcnwpM=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
@sinkog
sinkog merged commit 0adf578 into devel Aug 3, 2026
1 check 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.

1 participant