Skip to content

[codex] add Go runtime contract foundations#55

Merged
gnanam1990 merged 5 commits into
mainfrom
feat/go-m0-runtime-contracts
Jun 4, 2026
Merged

[codex] add Go runtime contract foundations#55
gnanam1990 merged 5 commits into
mainfrom
feat/go-m0-runtime-contracts

Conversation

@gnanam1990

@gnanam1990 gnanam1990 commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add Go runtime event and usage contracts, including provider token alias normalization and reasoning-token accounting
  • add the first Go model registry contract with provider/status/capability/reasoning validation and case-insensitive alias lookup
  • add config contract gap reporting for provider startup, runtime policy, and sandbox fields

Commits

  • feat: add Go runtime usage contracts
  • feat: add Go model registry contracts
  • feat: add Go config contract gaps

Validation

  • go test ./...
  • bun run test
  • bun run typecheck
  • bun run build
  • bun run smoke:build
  • bun run build:go
  • bun run smoke:go
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added a model registry to manage models across providers with capability, status, validation, and lookup support.
    • Introduced runtime configuration contract-gap tracking for required settings by milestone.
    • Expanded agent event types and enhanced token accounting: provider-specific aliases, reasoning tokens, cached-token handling, and effective/billable input/output calculations.
  • Tests

    • Added comprehensive tests for model validation and registry behavior, usage normalization, event names, and token-aggregation logic.

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Typecheck: bun run typecheck
  • [pass] Tests: bun run test
  • [pass] Build: bun run build
  • [pass] Smoke build: bun run smoke:build

Scope

Head: ae0f282e07bc
Changed files (8): internal/config/contracts.go, internal/config/contracts_test.go, internal/modelregistry/models.go, internal/modelregistry/models_test.go, internal/zeroruntime/helpers.go, internal/zeroruntime/provider_test.go, internal/zeroruntime/types.go, internal/zeroruntime/usage.go

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cd430c98-31b1-4f83-8a26-1e93441d83e0

📥 Commits

Reviewing files that changed from the base of the PR and between 1d1485c and ae0f282.

📒 Files selected for processing (2)
  • internal/modelregistry/models.go
  • internal/modelregistry/models_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/modelregistry/models_test.go
  • internal/modelregistry/models.go

Walkthrough

Adds a runtime-owned contract-gap model, a typed model registry with validation and normalized lookup, and expanded token usage normalization (including reasoning tokens) with stream integration and tests.

Changes

Model Registry, Token Usage, and Config Contracts

Layer / File(s) Summary
Contract Gaps Configuration System
internal/config/contracts.go, internal/config/contracts_test.go
ContractGap struct with Field, Owner, Milestone, and Reason tracks runtime configuration requirements. DefaultContractGaps() returns hardcoded gaps; FindContractGapsByMilestone() filters by milestone. Tests validate presence and filtering.
Token Usage Types, Normalization, and Stream Integration
internal/zeroruntime/types.go, internal/zeroruntime/usage.go, internal/zeroruntime/helpers.go, internal/zeroruntime/provider_test.go
Adds AgentEventType constants, TokenUsage provider-alias shape, expanded Usage including ReasoningTokens, Usage helper methods, and NormalizeUsage() that validates and resolves primary/alias token fields and clamps cached input tokens. Stream accumulation now uses effective-token helpers and collects reasoning tokens; tests cover mapping, clamping, negative validation, and mixed-stream merging.
Model Registry Enums and Data Structures
internal/modelregistry/models.go, internal/modelregistry/models_test.go
Introduces ProviderKind, ReasoningEffort, ModelCapability, ModelStatus enums; ContextLimits, ModelCost, ModelEntry structs; ModelEntry.Validate() and ModelCost.Validate() enforce required fields, numeric constraints, enum membership, alias/API provider rules. Baseline validation tests included.
Model Registry Construction and Lookup
internal/modelregistry/models.go, internal/modelregistry/models_test.go
NewRegistry() builds a normalized lookup map registering entries under id/API model/aliases with duplicate-key and duplicate-model-id detection; Registry.Get() performs normalized (trim+lowercase) lookups. Tests assert case-insensitive resolution and constructor rejection on duplicates/invalid entries.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Gitlawb/zero#52: Overlaps changes to internal/zeroruntime streaming contracts used by agent loop/provider wiring.
  • Gitlawb/zero#50: Related updates to runtime provider contracts and token/accounting normalization.

Suggested reviewers

  • anandh8x
  • Vasanthdev2004
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[codex] add Go runtime contract foundations' directly describes the PR's main contribution: establishing foundational contract structures for Go runtime, including event/usage contracts, model registry contracts, and config contract gaps.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/go-m0-runtime-contracts

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
internal/modelregistry/models_test.go (1)

54-127: ⚡ Quick win

Add regression tests for provider-list consistency and duplicate lookup keys.

Current tests miss two high-risk contracts:

  1. reject entries where Provider is not included in APIProviders, and
  2. detect duplicate normalized lookup keys across entries (ID/API model/alias).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/modelregistry/models_test.go` around lines 54 - 127, Add two
regression tests: (1) TestModelEntryRejectsProviderNotInAPIProviders — create a
model from validModelEntry(), set ModelEntry.Provider to a provider value not
present in ModelEntry.APIProviders, call model.Validate() and assert it returns
an error that mentions the provider/API providers contract (reference
ModelEntry.Provider, ModelEntry.APIProviders, and ModelEntry.Validate). (2)
TestRegistryDetectsDuplicateNormalizedLookupKeys — create two ModelEntry
instances that differ by ID/API model/alias but normalize to the same lookup key
(e.g., case variants or alias vs API model), try to build the registry with
NewRegistry([]ModelEntry{...}) or insert both into Registry, and assert the
registry creation/insertion fails or reports a duplicate normalized key
(reference NewRegistry, Registry.Get and the normalized lookup behavior) so
duplicate lookup keys are detected in tests.
internal/zeroruntime/provider_test.go (1)

179-206: ⚡ Quick win

Add a mixed-shape usage aggregation test to lock in correct totals.

Current coverage validates alias-only and normalized-only paths, but not a stream that mixes both. Add one mixed case to prevent regressions in CollectStream aggregation behavior.

Suggested test case
+func TestCollectStreamAccumulatesMixedUsageShapes(t *testing.T) {
+	events := make(chan StreamEvent)
+	go func() {
+		defer close(events)
+		events <- StreamEvent{Type: StreamEventUsage, Usage: Usage{PromptTokens: 10, CompletionTokens: 4}}
+		events <- StreamEvent{Type: StreamEventUsage, Usage: Usage{InputTokens: 6, OutputTokens: 3, ReasoningTokens: 2}}
+		events <- StreamEvent{Type: StreamEventDone}
+	}()
+
+	collected := CollectStream(context.Background(), events)
+
+	if collected.Usage.EffectiveInputTokens() != 16 {
+		t.Fatalf("input tokens = %d, want 16", collected.Usage.EffectiveInputTokens())
+	}
+	if collected.Usage.EffectiveOutputTokens() != 7 {
+		t.Fatalf("output tokens = %d, want 7", collected.Usage.EffectiveOutputTokens())
+	}
+	if collected.Usage.ReasoningTokens != 2 {
+		t.Fatalf("reasoning tokens = %d, want 2", collected.Usage.ReasoningTokens)
+	}
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/zeroruntime/provider_test.go` around lines 179 - 206, Add a new unit
test that exercises CollectStream with a mixture of alias-shaped and normalized
TokenUsage events to ensure aggregation is correct; construct one StreamEvent
using a raw/alias usage shape (e.g., fields that map to EffectiveInput/Output
via aliases) and another StreamEvent using NormalizeUsage(...) output, send both
through the events channel followed by StreamEventDone, call
CollectStream(context.Background(), events) and assert EffectiveInputTokens(),
EffectiveOutputTokens(), ReasoningTokens and TotalTokens match the expected
combined totals; reference CollectStream, StreamEvent, TokenUsage and
NormalizeUsage to locate and implement the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/modelregistry/models.go`:
- Around line 131-135: When validating a Model, besides checking each entry in
model.APIProviders with ValidRuntimeProviderKind, also enforce that when
model.APIProviders is non-empty the model.Provider value is included in that
slice; update the validation code (the loop that iterates model.APIProviders and
the similar block around the 167–176 region) to return an error if
model.Provider is not present in model.APIProviders (and ensure model.Provider
itself is validated by ValidRuntimeProviderKind where appropriate), with a clear
error message like "primary provider %q not allowed by APIProviders".
- Around line 183-193: NewRegistry currently overwrites duplicate normalized
keys silently; change register and NewRegistry to detect collisions and surface
them: modify the Registry.register(key string, entry ModelEntry) to check
registry.entries for an existing entry and return an error if an existing entry
with a different ModelEntry is present (include key, existing.ID and new
entry.ID in the error), then update NewRegistry to call register and
propagate/aggregate any errors and change its signature to return (Registry,
error) so callers can handle collisions instead of silent overwrite; update any
callers of NewRegistry accordingly.
- Around line 152-154: Replace the simple non-empty check on
cost.SourceLastVerified with a strict date parse: after trimming, attempt
time.Parse using the layout "2006-01-02" and return an error if parsing fails;
specifically update the validation around cost.SourceLastVerified in models.go
(the block that currently returns fmt.Errorf("model cost source last verified
date is required")) to instead validate and reject values that do not parse as a
YYYY-MM-DD date using time.Parse("2006-01-02", cost.SourceLastVerified).

In `@internal/zeroruntime/helpers.go`:
- Around line 68-73: The aggregation currently adds both canonical fields and
alias fields directly, causing alias-only events to be lost when later canonical
totals become non-zero; fix by normalizing each event's usage into canonical
fields before accumulation: create local normalized values from event.Usage (map
alias fields like CachedInputTokens/ReasoningTokens to the canonical
InputTokens/OutputTokens/PromptTokens/CompletionTokens as appropriate or call a
new normalize function) and then add those normalized fields into
collected.Usage (references: collected.Usage, event.Usage, and the
EffectiveInputTokens()/EffectiveOutputTokens() consumers).

---

Nitpick comments:
In `@internal/modelregistry/models_test.go`:
- Around line 54-127: Add two regression tests: (1)
TestModelEntryRejectsProviderNotInAPIProviders — create a model from
validModelEntry(), set ModelEntry.Provider to a provider value not present in
ModelEntry.APIProviders, call model.Validate() and assert it returns an error
that mentions the provider/API providers contract (reference
ModelEntry.Provider, ModelEntry.APIProviders, and ModelEntry.Validate). (2)
TestRegistryDetectsDuplicateNormalizedLookupKeys — create two ModelEntry
instances that differ by ID/API model/alias but normalize to the same lookup key
(e.g., case variants or alias vs API model), try to build the registry with
NewRegistry([]ModelEntry{...}) or insert both into Registry, and assert the
registry creation/insertion fails or reports a duplicate normalized key
(reference NewRegistry, Registry.Get and the normalized lookup behavior) so
duplicate lookup keys are detected in tests.

In `@internal/zeroruntime/provider_test.go`:
- Around line 179-206: Add a new unit test that exercises CollectStream with a
mixture of alias-shaped and normalized TokenUsage events to ensure aggregation
is correct; construct one StreamEvent using a raw/alias usage shape (e.g.,
fields that map to EffectiveInput/Output via aliases) and another StreamEvent
using NormalizeUsage(...) output, send both through the events channel followed
by StreamEventDone, call CollectStream(context.Background(), events) and assert
EffectiveInputTokens(), EffectiveOutputTokens(), ReasoningTokens and TotalTokens
match the expected combined totals; reference CollectStream, StreamEvent,
TokenUsage and NormalizeUsage to locate and implement the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 13b4b4d0-1876-4998-9ba8-a007875d2bff

📥 Commits

Reviewing files that changed from the base of the PR and between e9b3d7b and 29c526a.

📒 Files selected for processing (8)
  • internal/config/contracts.go
  • internal/config/contracts_test.go
  • internal/modelregistry/models.go
  • internal/modelregistry/models_test.go
  • internal/zeroruntime/helpers.go
  • internal/zeroruntime/provider_test.go
  • internal/zeroruntime/types.go
  • internal/zeroruntime/usage.go

Comment thread internal/modelregistry/models.go
Comment thread internal/modelregistry/models.go Outdated
Comment thread internal/modelregistry/models.go Outdated
Comment thread internal/zeroruntime/helpers.go Outdated
@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

Blockers

  • internal/modelregistry/models.go: NewRegistry() never calls entry.Validate() before registering lookup keys. That means callers can build a registry containing entries that violate the contract this PR is adding: blank display names, invalid primary providers, impossible context limits, unsupported enum values, missing aliases, malformed cost metadata, etc. The per-entry validation tests pass only because they call ModelEntry.Validate() directly, but the actual registry constructor path accepts invalid models as long as the id is non-blank and lookup keys do not conflict. Since the registry is the boundary future provider resolution will rely on, it should fail closed by validating every entry inside NewRegistry() before seenModelIDs/register(), with a regression test such as an invalid context limit or unknown provider being rejected by NewRegistry().

Non-Blocking

  • The PR branch is based on current origin/main (e9b3d7b), so I did not need a separate latest-main test merge.
  • Local review host still does not have go in PATH, so bun run test:go and bun run build:go fail locally with bun: command not found: go. I verified Go validation through GitHub CI instead: Go test/build/smoke passed on ubuntu, macos, and windows at head 1d1485c.
  • After running the transitional bun run build, bun run smoke:go fails locally because the existing Bun-built zero.exe prints 0.1.0 while the Go smoke expects zero 0.1.0. That is a local artifact-order issue caused by unavailable local Go/build:go, not the PR's CI behavior; GitHub runs Go build before Go smoke and passes.

Looks Good

  • The runtime usage contract is a useful Go M0 foundation: provider aliases are normalized, cached input is clamped, negative token counts fail closed, and reasoning tokens are tracked separately while contributing to billable output.
  • CollectStreamWithOptions() now aggregates reasoning tokens and still flushes open tool calls on done/error/channel close/context cancellation.
  • The model registry enums and validation shape line up with the Go-native direction: provider kind, capabilities, status, context limits, cost source/date, aliases, and API provider allowance are explicit instead of implicit strings.
  • Duplicate normalized lookup keys across model id/API model/aliases are detected, which prevents future provider/model routing ambiguity.
  • Config contract gaps document the M0/M1 provider/runtime/permission/sandbox fields that still need concrete resolver/config wiring.
  • Local validation I ran:
    • bun install --frozen-lockfile PASS
    • bun run typecheck PASS
    • bun test ./tests --timeout 15000 PASS, 279 pass / 0 fail
    • git diff --check PASS
    • bun run build PASS, produced transitional zero.exe
  • GitHub CI for 1d1485c: Go test/build/smoke PASS on ubuntu/macos/windows, TS/Bun test/typecheck/build/smoke PASS, performance smoke PASS.

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Requesting changes because NewRegistry() currently registers model entries without calling ModelEntry.Validate(), so invalid model contracts can enter the registry path future provider resolution will depend on. Full details and validation are in my review comment.

@gnanam1990

Copy link
Copy Markdown
Collaborator Author

@Vasanthdev2004 @anandh8x pushed ae0f282 to address the requested change.

What changed:

  • NewRegistry() now calls ModelEntry.Validate() before registering model IDs, API models, or aliases, so invalid model contracts fail closed at the registry boundary.
  • Added TestRegistryRejectsInvalidModelEntries to cover an invalid context limit through the actual registry constructor path.

Validation run:

  • go test ./internal/modelregistry passed
  • go test ./... passed
  • bun install --frozen-lockfile passed
  • bun run typecheck passed
  • bun test ./tests --timeout 15000 passed, 279 pass / 0 fail
  • bun run build passed
  • bun run smoke:build passed
  • bun run build:go passed
  • bun run smoke:go passed
  • git diff --check passed

Ready for re-review.

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

Blockers
None.

Non-Blocking

  • Local review host still does not have go in PATH, so bun run test:go and bun run build:go fail locally with bun: command not found: go. I verified the Go-specific validation through GitHub CI instead: Go test/build/smoke passed on ubuntu, macos, and windows at head ae0f282.
  • bun run smoke:go still fails locally after bun run build because the transitional Bun-built zero.exe prints 0.1.0 while Go smoke expects zero 0.1.0. CI runs Go build before Go smoke and passes, so this remains a local artifact-order limitation on this review host rather than a PR blocker.

Looks Good

  • The previous blocker is fixed: NewRegistry() now calls entry.Validate() before registering model ids, API models, or aliases, so invalid model contracts fail closed at the registry constructor boundary future provider resolution will depend on.
  • The new regression test covers the actual constructor path (TestRegistryRejectsInvalidModelEntries) with an invalid max-output/context-limit model and verifies NewRegistry() rejects it.
  • Duplicate normalized model ids and lookup keys are still checked after validation, preserving the ambiguity protection for id/API-model/alias resolution.
  • The runtime usage contract remains sound: provider token aliases are normalized, cached input is clamped, negative token counts fail closed, and reasoning tokens contribute to total/billable output accounting.
  • Local validation I ran:
    • bun install --frozen-lockfile PASS
    • bun run typecheck PASS
    • bun test ./tests --timeout 15000 PASS, 279 pass / 0 fail
    • bun run build PASS, produced transitional zero.exe
    • git diff --check PASS
  • GitHub CI for ae0f282: Go test/build/smoke PASS on ubuntu/macos/windows, TS/Bun test/typecheck/build/smoke PASS, performance smoke PASS.

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved current head ae0f282 after verifying NewRegistry() now validates entries before registering lookup keys and CI/local validation passed.

@gnanam1990 gnanam1990 merged commit 62a10f5 into main Jun 4, 2026
6 checks passed
@Vasanthdev2004 Vasanthdev2004 deleted the feat/go-m0-runtime-contracts branch June 28, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants