Skip to content

Oracle OCI Always Free: cited allowance, fabric offer binding, native request signing, compartment converge - #13335

Queued
gunbai-bot[bot] wants to merge 17 commits into
mainfrom
session/nimble-heron-805
Queued

gunbai-bot[bot] wants to merge 17 commits into
mainfrom
session/nimble-heron-805

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

What

Model.

  • `extdeps.cloud.oracle_oci`: Oracle's Always Free facts, cited to Oracle's docs as read on 2026-10-05:
    • the halved A1 allowance (1,500 OCPU-h / 9,000 GB-h, equivalent to 2 OCPU / 12 GB), E2.1.Micro, and the shared 200 GB block pool;
    • the home-region and availability-domain rules, idle reclamation, capacity types and account tiers;
    • the `us-ashburn-1` region row.
  • `product.supplier.oracle_oci`:
    • `oci_always_free_fit` returns every breach of the allowance, each one typed;
    • a $0 `SupplierOffer` binding, only for a plan that fits;
    • the tenancy home region is Ashburn (operator statement, 2026-10-05).

Native request signing. There is no `oci` CLI.

  • `extdeps.cloud.oracle_oci_request_signing` (pure) builds the signing string, the body SHA-256, the HTTP date and the Authorization header. It is pinned to Oracle's published GET vector. Note: Oracle's example date says "Thu" for 2014-01-05, which was a Sunday; the module derives the true weekday.
  • The signature comes from the existing `gunbc.jws_signer_realize` openssl handler, over a custodied host key file. The key never enters the evaluator.
  • `extdeps.tools.curl` `curl.HttpSignature` sends the body on stdin verbatim. The REST transport re-serializes bodies, which would break a signature over body bytes. One `serialize_json` string is both hashed and sent.

Compartment converge (`gunbc.oracle_oci.compartment_ensure` `ensure`):

  • Lists the `gunbc-always-free` compartment under the tenancy, creates it only when no live one exists, and lets a read-back decide the outcome.
  • Every failure arm refuses: a rejected key is Inaccessible, never Absent, and an unparseable answer refuses rather than creating.

Key custody.

  • `OracleOciApiSigningKey` custody row: srv1 only, root-owned 0400, at `/etc/gunbc/oracle-oci/api-signing-key.pem`.
  • An accessor-grant row for `gunbai-secrets/oracle-oci-api-signing-key`.
  • The `fleet-converge.yml` credential option. This is one generated line written by hand; the drift gate re-derives it.

Evidence

  • `oracle_oci_always_free_witness`: 12/12 PASS. Mutation control: raising `always_free_ocpus` to 4 makes the old-allowance claim FAIL.
  • `oracle_oci_request_signing_witness`: 7/7 PASS. The body digest matches an independent Python `hashlib` value.
  • `oracle_oci_compartment_ensure_witness`: 9/9 PASS.
  • `host_credential_custody_converge_witness`: all PASS with the new row.
  • `gcp_secret_access_witness` `the_roster_is_the_single_authority…` was red on main, because `fabric_state_key_accessor_row` was missing from its named-row identity join. Adding that row fixes it, and it now PASSES.

Not yet established

No live call has been made. The inhabitance evidence is the first receipt from srv1, after three steps that each need the operator:

  1. the accessor grant (approval loop);
  2. custody delivery of `oracle_oci_api_signing_key` to srv1;
  3. `gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/oracle_oci/compartment_ensure.dag --function ensure` on srv1.

Network (VCN, subnet, internet gateway) and instance launch through `oci_always_free_fit` are the next PR.

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 4 commits October 5, 2026 02:03
…bric offer binding (product.supplier)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… + cited region row

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…uthorization header; pinned to Oracle's GET vector

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ows for the API key, gunbc-always-free compartment ensure

- extdeps.tools.curl HttpSignature: exact-bytes signed GET/POST (body on stdin, fixed signed-header slots)
- gunbc.oracle_oci.compartment_ensure: key as a custodied host file signed by the existing openssl handler; ListCompartments/CreateCompartment; readback decides
- host_credential_custody_converge: OracleOciApiSigningKey (srv1, root 0400); fleet-converge.yml choice option
- fleet_secret_accessor_roster: accessor row for oracle-oci-api-signing-key
- gcp_secret_access witness: named rows now include fabric_state_key_accessor_row (the identity join was red on main without it)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title Oracle OCI Always Free: cited allowance, allowance fit, fabric offer binding Oracle OCI Always Free: cited allowance, fabric offer binding, native request signing, compartment converge Oct 5, 2026
…closed coproduct; floor NonFoldResidueRosterDiverged)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NO-LAND at c74c82d.

Good direction: reuse the existing host-key signer and custody converger; serialize once and hash/send that same body; distinguish inaccessible reads from absence; retain unobserved supply rather than claiming a launched instance. I checked Oracle's current Always Free page: 1,500 OCPU-hours / 9,000 GB-hours and 2 OCPUs / 12 GB are indeed what it currently publishes. The allowance constants are not my objection.

Five concrete findings are attached:

  1. [P1] The zero-quote binder accepts an unrelated, payloadless fit result alongside a separately supplied instance and region.
  2. [P1] Malformed compartment array members are converted to empty strings, allowing unknown input to authorize creation or a missing-ID row to report convergence.
  3. [P2] ListCompartments pagination is discarded, so an empty non-final page is treated as absence.
  4. [P2] A nominal plan subtotal is not proof of remaining tenancy-wide free allocation; existing/detached volumes and already-consumed monthly usage are absent from the model that authorizes a zero quote.
  5. [P2] The transport ignores the signed method and chooses GET/POST solely from body presence.

The common repair is to retain the subject and distinctions through the boundary: admit the actual plan/member/placement under an allocation scope, admit a complete schema-valid observation before deriving absence, and derive signing plus transport from the same supported request value. Sealing a detached FitsAlwaysFree flag or adding caller instructions does not repair the first problem.

These fixes do not require expanding this PR into all OCI provisioning. In particular, the quota work may remain unavailable by keeping this calculator explicitly nominal and refusing a priced/free binding until tenancy allocation is established. Similarly, narrow the method interface to the supported cases rather than implementing unused methods speculatively.

One additional nonblocking cleanup: apply_oci_compartment_create drops the readback Refuse.reason when it renders '(readback after create)', and OciCompartmentEnsureOutcome retains only a line and held Bool. Preserve the admitted compartment identity/refusal in a typed result and render it at the entry boundary.

Source review plus upstream documentation verification only: I did not execute the DAG witnesses, make live OCI calls, or deliver credentials. The PR's explicit statement that live inhabitance is still pending is appropriate; it must not be upgraded to an operational-completion claim from the fixture witnesses alone.

principal: P,
executor: P,
instance: OciPlannedInstance,
plan_fit: OciAllowanceFit,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Bind the fit to the instance and placement it actually checked

plan_fit contains no plan or member identity. A caller can pass oci_always_free_fit(plan: []) here together with a 4-OCPU/24-GB instance and measured readiness, and this function takes the FitsAlwaysFree arm and emits a zero quote without inspecting that instance's breaches. This does not require forging a constructor: it reuses a genuinely computed fit. A fitting plan can likewise be paired with an unrelated ProviderRegionRead, since the instance only carries an InHomeRegion flag and the route takes an independent region.

Return an admitted plan carrying its exact members and tenancy/home-region placement, and derive the offer's instance and route from a selected admitted member; or validate the complete plan and member relation within this binding operation. A sealed payloadless success flag alone is still transferable. Add discriminating controls for fit([]) + oversized instance, a member substituted after validation, and an unrelated route region; retain the same-plan/member positive control.

match parse_json_document(s: body) {
JsonDocumentUnreadable { gap } => CompartmentReadRefused { cause: concat("ListCompartments body is not JSON: ", json_document_gap_text(gap: gap)) as NonEmptyStr }
JsonDocumentParsed { value } => match value {
JsonArray { elements } => CompartmentsListed { compartments: map(elements, e => oci_compartment_of_json(v: e)) }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Refuse malformed array members before deciding absence

Any JSON array is promoted to CompartmentsListed, but oci_string_member returns an empty string for missing, null, unreadable, or wrong-typed fields. Consequently HTTP 200 with [{}] or [null] becomes a list whose members have empty names; the live-name filter removes them all and classify_oci_compartment_ensure returns Absent/Apply. Conversely, [{"name":"gunbc-always-free","lifecycleState":"ACTIVE"}] reports Converged/Noop even though no compartment ID was admitted.

Make row decoding fallible and preserve the row/field failure. Require the identity fields needed by this operation, and do not turn a failed row decode into either a filtered-out row or a success. Add controls for malformed elements, missing/null/non-string name and ID, and a valid ACTIVE row. The current wrong-shaped-body witness checks a top-level object, not wrong-shaped members of an otherwise valid array.

}

fn read_oci_free_compartment() -> OciCompartmentRead uses net: Network {
classify_oci_compartment_list(exchange: oci_signed_exchange(method: OciGet, host: oci_identity_host, path_and_query: oci_compartment_list_path(), body: OciNoBody))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Establish list completion before authorizing creation

This reads exactly one ListCompartments page. The curl transport and OciAnswered keep only status/body, discarding opc-next-page, so the classifier cannot distinguish an empty complete listing from an empty page with additional results. Oracle explicitly documents that a page can be empty while more results remain, and ListCompartments exposes the page parameter. The name filter does not establish a documented one-page guarantee. A live compartment on a later page therefore still leads to an unnecessary CreateCompartment attempt.

Carry pagination headers through the transport and finish the listing before producing a complete observation, or refuse when continuation exists until traversal is supported. Add an empty-first-page/ACTIVE-second-page control and a continuation-read-failure control; neither may create.

Upstream: https://docs.oracle.com/en-us/iaas/Content/API/Concepts/usingapi.htm#ListPagination and the IdentityClient ListCompartments documentation.

let ocpus = fold(plan, init: 0, f: (acc, i) => acc + oci_a1_ocpus(i: i))
let memory = fold(plan, init: 0, f: (acc, i) => acc + oci_a1_memory_gb(i: i))
let micros = fold(plan, init: 0, f: (acc, i) => acc + oci_micro_count(i: i))
let block = fold(plan, init: 0, f: (acc, i) => acc + gigabyte_count(g: i.boot_volume))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Do not turn a nominal plan subtotal into tenancy-wide free entitlement

Even after binding fit to the right plan, this sums only the listed instances and their boot volumes. It cannot represent an existing unattached data volume, other tenancy allocations outside the plan, or A1 OCPU/GB-hours already consumed in the billing month. For example, a tenancy with 200 GB already allocated to a data volume still gets FitsAlwaysFree for a new 47-GB boot-volume plan. Two separately evaluated full-allowance plans also each pass. The later binder emits a $0 quote with no tenancy/allocation context, and it does not restrict itself to a verified AlwaysFree-only account.

Oracle defines the storage pool across boot and block volumes combined, and the A1 credit across monthly tenancy usage. Either admit against a tenancy-scoped remaining allocation that accounts for other holds/usage, or keep this as a nominal allowance calculator and refuse the zero-priced binding until that allocation is established. Do not solve it by documenting that callers must supply all usage: the current plan type cannot carry all relevant usage. Add existing-data-volume and separately-admitted-plan controls.

Upstream: https://docs.oracle.com/en-us/iaas/Content/FreeTier/freetier_topic-Always_Free_Resources.htm

}

fn oci_send(method: OciHttpMethod, url: NonEmptyStr, date: NonEmptyStr, authorization: NonEmptyStr, content_sha256: String, body: OciRequestBody) -> OciExchange uses net: Network {
let run = match body {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Send the method that was signed, or reject unsupported request forms

method is unused here. OciDelete + OciNoBody is signed as DELETE but sent as GET; OciPost + OciNoBody is also sent as GET; OciGet + OciJsonBody is sent as POST. Both current production callers use the matching GET/no-body and POST/JSON pairs, so this is not a claim that those two paths currently choose the wrong method. It is a bug in the newly exposed request contract, which already advertises DELETE and permits these combinations.

Use one supported request representation to derive both signing headers and wire method/body. Implement the supported methods or remove/refuse unused cases before signing; no need to expand scope to implement all OCI verbs. POST with an empty body must still sign/send the required content headers. Add a wire/transport control, not just a signing-string fixture, that checks the method and body actually emitted.

…e fold was ~280k eval steps per digest, over the new-witness budget)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1. bind_oci_always_free_offer takes the plan + member name and decides the fit itself; instance and
   route derive from the admitted member (no transferable FitsAlwaysFree, no separate region)
2. fallible row admission (gunbc.oracle_oci.api oci_admit_rows): a missing/null/mistyped/empty
   required field refuses the list instead of reading as absent or converged
3. response headers dumped (-D /dev/stderr); a list answered with opc-next-page refuses
4. tenancy-wide fit (OciOtherUsage); zero quote refuses until TenancyAllocationObserved
5. OciRequestShape = OciGetRequest | OciPostJson: one value drives signing and transport
cleanup: compartment outcome carries the typed standing; readback reason kept

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review at 9c9cefa: NO-LAND, with one remaining P2 from original finding 4.

I close the original implementation defects 1, 2, 3 and 5:

  • The binder computes the fit from its own plan, selects the offered member from that plan, and derives the Ashburn route; detached plan_fit and region arguments are gone.
  • The real compartment-list path admits every row's required id/name/lifecycleState before filtering. The five reported malformed-row cases now refuse.
  • The exchange captures opc-next-page and the list classifier refuses continuation rather than claiming completion. Refusal rather than implementing traversal is an appropriate bounded fix.
  • OciRequestShape now drives both the signing method and the GET/POST transport selection, including the empty JSON POST case.
    The typed CompartmentReady/CompartmentNotReady result and retained readback refusal reason also address the cleanup.

Finding 4 is improved, not closed: counting OciOtherUsage and making the default allocation unread fixes the existing-200-GB example, but the positive allocation value is still detached from the plan it excludes, and it cannot carry checked monthly credit status. See the inline source-level counterexample. This does not claim today's unread default launches or bills anything. It means the public zero-quote admission still accepts insufficient evidence.

The small repair is still available: retain the nominal calculator and keep numeric zero-price binding unavailable until a plan-scoped allocation can actually be admitted. Merely setting one default data row to Unread leaves an unsafe positive arm reachable. This need not become an OCI allocator project in this PR.

Evidence: I inspected the revised production paths and witness source. I did not run gunbc or the reported DAG claims, make live OCI calls, or deliver credentials. I did execute four isolated local curl probes using the declared transport arguments with test-only authorization: GET with/without continuation and POST with empty/nonempty body. Method/body, header capture, and Content-Length: 0 behaved correctly. Those probes validate the curl commands, not execution through the DAG service dispatch. The head's witnesses workflow was in_progress at the last check.

Nonblocking test follow-through: the pagination witness supplies next_page directly, and the signing witnesses do not call oci_send. They would stay green if header capture were removed or the transport dispatch were miswired again. Keep one production-route/transport control to protect that integration; it can use a local endpoint and test credentials, not live OCI. I am not listing that as a second implementation blocker.

) -> OfferBinding<P> {
match allocation {
TenancyAllocationUnread { obligation } => OfferBindingRefused { runs_on_label: member, cause: obligation },
TenancyAllocationObserved { other, receipt } =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Bind observed residual usage to the plan it excludes; do not admit monthly entitlement from a receipt label

TenancyAllocationObserved carries only residual counts and a receipt reference. This arm consumes other with an independently supplied plan and never checks the receipt. Residual usage is not a tenancy-only fact: it is usage outside a particular plan.

Source-level counterexample (no forged observation required): the tenancy already contains A, an instance with 2 OCPUs/12 GB/47 GB boot. A truthful observation of usage outside plan [A] reports all-zero other. Reuse that same allocation value while binding a different plan [B], where B has a different name and the same size. This function recomputes fit([B], other=0), selects B, and returns a zero quote. But the actual usage outside [B] includes A; fit([B], other=A) refuses on OCPU and memory. The new membership control does not discriminate this: B really is a member of the new plan. The exclusion subject was lost in the allocation value instead.

Separately, the obligation string acknowledges that monthly A1 consumption is uncarried, but the Observed arm has no checked billing-period/credit state, and the receipt is discarded. An inventory observation is not by itself proof of remaining monthly free credit. Oracle states the A1 allowance in monthly OCPU-hours and GB-hours: https://docs.oracle.com/en-us/iaas/Content/FreeTier/freetier_topic-Always_Free_Resources.htm

The production Unread default is safe as used, but does not enforce the public binder's invariant. Either keep numeric zero-quote binding refused until the missing evidence has a real admission, or derive/admit the allocation against this exact plan (with its exclusion identity, relevant usage/holds, and metered eligibility) and consume that same admitted subject here. No need to implement the allocator now: retaining the nominal calculator and withholding the priced binding is the smaller valid landing.

Add a control reusing A's truthful excluded-plan observation for B; it must refuse even though B is a valid member of its own fitting nominal plan. Missing monthly eligibility must likewise remain a refusal rather than be discharged by changing an enum arm or a receipt string.

gunbai-bot Bot pushed a commit that referenced this pull request Oct 5, 2026
…d rows, request shapes, continuation-based completeness

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…igabyte; drop the unconsumed monthly-meter fields (cited in the note, enter with their consumer)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressing review 76355 (unit modeling) at 6ba202d:

  • oracle_oci.dag ocpu_hours_per_month / gb_hours_per_month: removed, not retyped. Nothing in the tree consumed either field; the allowance fit reads only the steady-state equivalent (always_free_ocpus, always_free_memory: Gigabyte). Minting a memory-time quantity in std.measure to type a field nobody reads would add dangling vocabulary (DESIGN §3c). The 1,500 OCPU-h / 9,000 GB-h figures stay in the citation note that grounds the 2 OCPU / 12 GB equivalence, and the note names their consumer: a month-to-date A1 consumption observation, which product.supplier.oracle_oci oci_tenancy_allocation_unread_obligation records as unread. They come back as typed fields with that consumer.
  • OciOtherUsage.a1_memory_gb / block_gb: retyped as a1_memory: Gigabyte / block: Gigabyte, the carrier extdeps.cloud.oracle_oci already uses for these quantities.
  • micros: Nat: unchanged. As the review itself concluded, it is an instance count.
    oracle_oci_always_free_witness 13/13 PASS locally after the change.

— sent from nimble-heron-805

gunbc-ci-auto-heal and others added 2 commits October 5, 2026 08:14
… the name read as money micros)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…h, backup count, AD rule, idle rule, processor ref, extra authority rows); figures and sources stay in the notes with their named consumers (review 76377)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressing review 76377 at 4962de1. internet_bandwidth_megabits_per_second is removed rather than retyped, because nothing read it. The review's §3c point applied to more than that one field, so I swept the whole module and removed every declaration with no consumer in the tree: the micro bandwidth, the volume-backup count, OciAvailabilityDomainRule and its function, the idle-reclamation rule (type, row and function), the A1 processor reference, and three extra authority rows. Each figure and its Oracle source stay in the module's citation notes, and each note names the consumer that brings it back as a typed row: a network-capacity placement term for bandwidth, a volume-backup converge for the backup count, and a utilization observation for the idle rule. The micro's availability domain is read per tenancy from ListShapes by the converge in #13351, so the extdeps rule had no reader. oracle_oci_always_free_witness 13/13 and oracle_oci_compartment_ensure_witness 11/11 PASS locally.

— sent from nimble-heron-805

gunbc-ci-auto-heal and others added 3 commits October 5, 2026 08:47
…e, floor division, seconds constants); only the RFC 7231 names and layout stay local (review 76382)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ops the hand-written ASCII walk and refusal)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…est, so a lost reply and a re-run cannot create twice (review 76384)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Oct 5, 2026
…cy's observed usage (instances, boot and block volumes across every compartment); merge retry-token + UTF-8 length from #13335 (review 76384)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 2 commits October 5, 2026 09:06
…not an argv literal; memory/block overage arms keep Gigabyte (review 76392)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… A1 monthly meter are admittable (side-chat re-review, finding 4); API hosts derived from the tenancy home-region row; drop now-unconsumed offer-shape helpers

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

Re-review follow-up (side-chat REQUEST_CHANGES at 9c9cefa, remaining P2 on finding 4), and review 76392, addressed at 6000600.

Finding 4, remaining P2 (transferable allocation evidence). Taken as the bounded option. The positive TenancyAllocationObserved arm is deleted. bind_oci_always_free_offer(plan, member) selects the member from the plan and decides the nominal fit (home-region placement is a fit breach), then always refuses with oci_tenancy_allocation_unread_obligation. That obligation names both missing pieces: other usage derived against that plan's member identities, and the A1 month-to-date meter (OCPU-hours and GB-hours against 1,500 / 9,000). No residual-count value crosses the boundary, so a truthful observation for plan A cannot be reused for plan B. The nominal calculator stays for the instance converge in #13351, which observes tenancy usage itself and decides whether a launch is possible, not a price. The now-unreachable offer-minting code is removed, along with the extdeps OCPU/architecture rows only it consumed. The API hosts now derive from the operator-stated home-region row.

Review 76392. The curl --max-time is now a caller-supplied Second (gunbc.oracle_oci.api oci_request_timeout), not an argv literal. A1MemoryOverAllowance and BlockVolumeOverAllowance carry Gigabyte for both planned and allowed.

Nonblocking (loopback production-route control). Agreed it is the right integration test for header capture and transport dispatch. It will land with the first srv1 run.

Local: always_free 12/12, compartment 12/12, signing 7/7, custody 37/37.

— sent from nimble-heron-805

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LAND / APPROVE at 6000600.

The remaining P2 under finding #4 is closed. This approval supersedes my earlier REQUEST_CHANGES reviews (5409866962 and 5411499542) for this PR. No remaining blocking findings from those reviews in the bounded scope now implemented.

Verified in product.supplier.oracle_oci:

  • OciTenancyAllocation / TenancyAllocationObserved and the positive offer-minting implementation are deleted, not merely hidden behind an unread production default.
  • bind_oci_always_free_offer takes only the plan and member name. It selects the member from that plan, checks the plan's nominal fit, and every return path is OfferBindingRefused. A member of a fitting home-region plan still refuses with oci_tenancy_allocation_unread_obligation.
  • No allocation value or receipt can be supplied to this interface, and no branch constructs a zero-priced offer. The earlier truthful-observation-for-A/reuse-for-B counterexample therefore has no positive path to exploit.
  • The obligation explicitly names both missing facts: other usage derived against the exact plan's member identities and the A1 billing month's consumption. The nominal calculators remain calculators, not quote authorization.

The revised oracle_oci_always_free_witness exercises the actual binder and requires the exact allocation refusal for a fitting member, the membership refusal for an absent member, and the plan-fit refusal for oversized or outside-home-region plans. The 200-GB other-usage control remains at the calculator boundary. Removing the old positive quote control is appropriate because that capability has been deliberately removed, not silently weakened.

I also inspected the intervening source and witness changes, including unit-bearing memory/storage breaches, home-region-derived API hosts, caller-supplied timeout, the UTF-8 body-length/calendar reuse, and retry-token wiring. The previously closed row-admission, continuation-refusal, request-shape, and typed-compartment-outcome findings remain closed. No new blocking finding in this revision.

Verified GitHub witnesses run #32435 (37289971728) is completed/success for this exact head. This was source/witness review and CI-result verification; I did not independently execute the DAG claims, perform live OCI calls, or deliver credentials. The production-route loopback control discussed previously remains nonblocking follow-through, as acknowledged in the PR comment.

This approves the groundwork with zero-priced offer binding unavailable. It is not a finding that tenancy allocation, live OCI operation, or the separate instance-launch PR is qualified.

# Conflicts:
#	.github/workflows/fleet-converge.yml
#	dag/gunbc/auth/fleet_secret_accessor_roster.dag
#	dag/gunbc/fleet/host_credential_custody_converge.dag
#	dag/test/claim/gcp_secret_access_witness_test.dag
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Oct 6, 2026
Any commits made after this event will not be merged.
@gunbai-bot

gunbai-bot Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Dequeued: this PR ADDS import v2.std.optional, a module #13388 removed. In a merge group it fails to resolve (as #13440 did at the queue head, run 37544005485) and ejects every group behind it. Fix: merge main, repoint with tools.source_reference_repoint (v2.std.optional -> std.optional), re-green, and re-enqueue.

— sent from sharp-raven-357

@gunbai-bot
gunbai-bot Bot removed this pull request from the merge queue due to a manual request Oct 7, 2026
…std.optional (v2.std.optional was removed on main, #13388/#13491)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Oct 7, 2026
…th measure_add (review 77651); merge #13335 head incl. main and std.optional

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls added this pull request to the merge queue Oct 7, 2026
Any commits made after this event will not be merged.

This branch has not been deployed

No deployments
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