Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions DOCS/RuntimeBoundary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Runtime Resolver Boundary (HC-114)

**Status:** Decided · **Date:** 2026-06-12 · Decision record for workplan HC-114
(closes RFC §10 "Performance" / the JIT-vs-AOT question).

## The question

Where does context binding happen?

1. **Build/generation time** (the current mode): `--ctx` is supplied when
resolving; the output is a static resolved graph per context, consumed by
generators, validators and `diff`.
2. **Embedded runtime resolver**: an application links the resolver and
supplies per-request context (tenant, user, cohort), getting resolved
values live from a single deployment.

RFC §9.8 had noted mode 2 as "optional, currently out of scope". This record
makes the boundary a decision, not a deferral.

## Decision

**Build/generation-time resolution is the only supported mode of the
reference implementation.** The embedded runtime resolver is **out of
scope** — excluded from the core's contract, with explicit revisit conditions
below. Consequently **HC-115** (an OpenFeature bridge for the runtime mode)
is parked.

## Rationale

1. **The product is the artifact, not the answer.** Everything that makes
Hypercode worth using — review compression, per-node SHA-256 hashes,
`hypercode diff` as an invalidation feed, HC2104 gating, generated-artifact
conformance — assumes a *finished, reviewable* resolved graph. A
per-request resolution has no stable artifact: nothing to hash, nothing to
diff, nothing to review or attest.
2. **Provenance semantics.** At build time, provenance points at a line a
human can review *before* anything ships. At runtime, "which rule won"
becomes telemetry — an observability problem with its own capture,
sampling and retention questions, foreign to the core.
3. **The validation story depends on enumerable contexts.**
`validate --ctx …` runs once per context in CI, which works because
build-time contexts are finitely enumerable. Per-request context spaces
(user IDs, cohorts) are unbounded; admitting them would silently void the
"every shipped context was checked" guarantee the contract layer provides.
4. **The runtime niche is occupied — deliberately.** OpenFeature and
LaunchDarkly decide dynamic values per request well. Hypercode's role
([Positioning](Positioning.md)) is to provide the stable anchors
(`type`/`.class`/`#id`) such systems target. A bridge would blur exactly
the layer boundary the positioning depends on.
5. **The library stays embeddable as a fact, not as a contract.** `Resolver`
is a pure function of `(sheet, context)`; a consumer *can* call it
in-process today. The decision is that core makes **no runtime API
commitments**: no caching, no sheet hot-reload, no per-request provenance
sink, no latency guarantees. Embedding it means accepting build-time
semantics evaluated late, with none of the runtime conveniences.

## Binding consequences for design

- Resolution remains a **pure function**. No public API may require an
execution environment (clock, network, environment variables) at resolve
time.
- Diagnostics, IR, hashes and `diff` stay defined over the resolved artifact.
- Interpolation placeholders that appear in sheets (e.g. the `"${DB_HOST}"`
in RFC §4.2.2) pass through resolution as opaque strings; binding them is
the **consumer's** generation/deploy concern, not resolver semantics.
- HC-115 (OpenFeature bridge) is parked: it only makes sense in the runtime
mode. Runtime flags compose with Hypercode by targeting resolved anchors,
not by flowing through the resolver.

## Revisit when

All three together, not any one alone:

1. A consumer demonstrates a deployment whose context space genuinely cannot
be pre-resolved (true per-request combinatorics, not "many tenants" —
N tenants × M environments enumerate fine);
2. a provenance/attestation design exists for runtime answers (what replaces
the reviewable artifact);
3. the runtime API is drafted as a **separate package** so the core's purity
and guarantees are untouched.

## Pointers

[RFC §9.3, §9.8](../RFC/Hypercode.md) · [Positioning — layer answers](Positioning.md)
· [OVERVIEW §6](../OVERVIEW.md)
5 changes: 3 additions & 2 deletions OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,9 @@ runnable today: [`Examples/codegen-demo/`](Examples/codegen-demo/).

Binding time is explicit: context resolves at build/generation time. Runtime
feature flags (OpenFeature, LaunchDarkly) are a different, composable layer;
an embedded runtime resolver is an optional mode, currently out of scope
([RFC §9.8](RFC/Hypercode.md)).
an embedded runtime resolver is decided out of scope — the resolver stays an
embeddable pure function, but core makes no runtime API commitments
([decision record](DOCS/RuntimeBoundary.md), [RFC §9.8](RFC/Hypercode.md)).

## 7. What Hypercode Is Not

Expand Down
37 changes: 31 additions & 6 deletions RFC/Hypercode.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ The strongest objection to Hypercode's design comes from the configuration-langu

For example, given a base contract `Database: pool_size: int >= 1`, a more specific `Database#main: pool_size: int >= 10` is valid (narrowing), while `Database#main: pool_size: int >= 0` is rejected (weakening). Behavior cascades; safety does not. This asymmetry is the design's direct answer to the GCL lesson.

Two refinements make the rule precise (normative semantics in the [resolution specification](../EBNF/Hypercode_Resolution.md)). First, contracts **accumulate by intersection**: every contract matching a node governs it simultaneously, and an omitted bound is not a statement — it inherits through the intersection. Second, as in the CSS cascade, specificity relates two contracts only when at least one node in the document is matched by both selectors; contracts on disjoint parts of the tree are independent. Monotonicity violations are resolution errors (HC2101 type change, HC2102 interval widening, HC2103 required→optional); validating resolved *values* against the effective contract is the next layer (HC2104, in progress).
Two refinements make the rule precise (normative semantics in the [resolution specification](../EBNF/Hypercode_Resolution.md)). First, contracts **accumulate by intersection**: every contract matching a node governs it simultaneously, and an omitted bound is not a statement — it inherits through the intersection. Second, as in the CSS cascade, specificity relates two contracts only when at least one node in the document is matched by both selectors; contracts on disjoint parts of the tree are independent. Monotonicity violations are resolution errors (HC2101 type change, HC2102 interval widening, HC2103 required→optional); validating resolved *values* against the effective contract is the value layer (HC2104, `validate --ctx`, shipped in 0.5.0).
4. **Known failure modes are acknowledged.** Specificity wars and selector escalation are real CSS pathologies at scale. Countermeasures — origin/layer control analogous to CSS `@layer`, dangling-selector validation (already in `hypercode validate`), and explain tooling — are sequenced in the [work plan](../workplan.md) ahead of language surface that would amplify them.

### 9.5. Why a Stable Topology
Expand All @@ -319,15 +319,31 @@ Spec-driven development is converging on the view that the specification is the

### 9.8. Acknowledged Limits

* **Context binds at resolve time.** `--ctx` is supplied when resolving: Hypercode's default mode decides context at build/generation time. Runtime feature-flag systems (OpenFeature, LaunchDarkly) decide flag values per request at runtime — a different layer that composes with Hypercode rather than competing with it. Serving dynamic context from a single deployment (e.g., many tenants per process) would require embedding the resolver as a runtime library; that optional mode raises its own caching, latency, and provenance questions and is currently out of scope.
* **Context binds at resolve time.** `--ctx` is supplied when resolving: Hypercode's default mode decides context at build/generation time. Runtime feature-flag systems (OpenFeature, LaunchDarkly) decide flag values per request at runtime — a different layer that composes with Hypercode rather than competing with it. Serving dynamic context from a single deployment (e.g., many tenants per process) would require embedding the resolver as a runtime library; that mode raises its own caching, latency, and provenance questions and is **decided out of scope** for the reference implementation (HC-114, decision record with revisit conditions: [`DOCS/RuntimeBoundary.md`](../DOCS/RuntimeBoundary.md)). The resolver remains an embeddable pure function of `(sheet, context)`, but core makes no runtime API commitments — no caching, no sheet hot-reload, no per-request provenance sink.
* **No integrity chain yet.** As noted in §8, nothing verifies the chain end-to-end: signed `.hc`/`.hcs` → resolved-IR hash → generator identity and version → generated-artifact hashes → validator report. SLSA provides the reference vocabulary for such attestations. For the review-compression story to carry governance weight they are eventually required; they are deliberately deferred as future work.
* **Type-system maturity.** IR v2 carries typed values (string/int/double/bool, inferred at parse time with the source lexeme preserved), and the contract layer (§9.4) ships declarations and monotonicity validation. Enforcement of resolved values against the effective contract (HC2104) is in progress; until it lands, Hypercode still does not compete with typed configuration languages on safety. IR v1 remains strings-only and is kept for backward compatibility.
* **Type-system maturity.** IR v2 carries typed values (string/int/double/bool, inferred at parse time with the source lexeme preserved), and the contract layer (§9.4) ships declarations and monotonicity validation. Resolved values are enforced against the effective contract per context (HC2104, `validate --ctx`). What is still missing versus typed configuration languages: richer value types (lists, maps, durations), cross-property constraints, and user-defined predicates. IR v1 remains strings-only and is kept for backward compatibility.
Comment thread
SoundBlaster marked this conversation as resolved.

## 10. Open Questions

* **Debugging and Tooling:** How can developers effectively trace why a specific configuration was applied? This would require specialized debugging tools that can visualize the cascade and resolution of HCS rules.
* **Performance:** The overhead of parsing and resolving the HCS at startup needs to be analyzed. A JIT (Just-In-Time) resolution or an AOT (Ahead-Of-Time) compilation step might be necessary for performance-critical applications.
* **Complexity Management:** While HCS simplifies the core logic, very large and complex HCS files could become difficult to manage themselves. Best practices and modularization strategies would be required. This could include extending the at-rule system with directives like `@import`, allowing for better organization of large configurations.
The original open questions of draft 0.1 have since been answered:

* **Debugging and Tooling** — answered by `hypercode explain` (HC-110): the
full cascade trace, winner and losing rules with file, line, specificity
and source order (§9.4).
* **Performance / binding time** — closed by decision HC-114: resolution is
ahead-of-time (build/generation time) by design; an embedded runtime
resolver is out of scope
([`DOCS/RuntimeBoundary.md`](../DOCS/RuntimeBoundary.md), §9.8).
* **Complexity Management** — answered by `@import` (HC-116, §4.2.4): sheets
compose with deterministic order, import-once semantics and cross-file
provenance.

Genuinely open:

* **Integrity chain** (§8, §9.8): signed sources → resolved-IR hash →
generator identity → artifact hashes → validator report (SLSA vocabulary).
* **Type-system depth** (§9.8): richer value types, cross-property
constraints, user-defined predicates.

## 11. References

Expand Down Expand Up @@ -358,6 +374,15 @@ Prior art surveyed in §9:
the directive position, importer wins specificity ties, import-once,
cycle detection, cross-file provenance. Normative semantics in
`EBNF/Hypercode_Resolution.md` §5.1.
* Runtime resolver boundary decided (HC-114, §9.8): build/generation-time
resolution is the only supported mode; the embedded runtime resolver is out
of scope with explicit revisit conditions (`DOCS/RuntimeBoundary.md`);
HC-115 (OpenFeature bridge) parked accordingly.
* §10 Open Questions brought up to date: debugging (HC-110), binding time
(HC-114) and complexity management (HC-116) recorded as answered; the
integrity chain and type-system depth remain open.
* §9.4 and §9.8 no longer claim HC2104 is in progress — value-level
enforcement shipped in 0.5.0.

**Version 0.2** (2026-06-11):

Expand Down
4 changes: 2 additions & 2 deletions workplan.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ P0 — what makes the novelty claim defensible:

P1 — built on v2:
- [x] HC-113 `hypercode diff <old.ir> <new.ir>` — affected nodes/properties with reasons (old/new winner rule), node-hash short-circuit (unchanged subtrees skipped), selector-identity node matching, added/removed/reordered detection, `--format json` = `hypercode.diff/v1` feed, exit 1 on change — `Sources/Hypercode/Diff/` (Foundation-free JSON parser with exact number lexemes)
- HC-114 Runtime resolver boundary — document default build/generation-time mode vs. optional embedded runtime resolver (per-request context: caching, latency, provenance); decide library API or explicit out-of-scope — RFC §9.8
- 🅿️ HC-115 OpenFeature bridge for the runtime mode *(only if HC-114 decides "in scope")*
- [x] HC-114 Runtime resolver boundary — **decided: build/generation-time only**, embedded runtime resolver out of scope with revisit conditions; resolver stays an embeddable pure function with no runtime API commitments — `DOCS/RuntimeBoundary.md`, RFC §9.8/§10
- 🅿️ HC-115 OpenFeature bridge for the runtime mode — parked by the HC-114 decision (runtime mode out of scope); runtime flags compose by targeting resolved anchors instead
- [x] HC-116 `@import` for `.hcs` — sheet modularity: depth-first expansion at the directive position (importer wins ties), import-once for diamonds, cycle detection, cross-file provenance; contracts compose across imports — normative semantics `EBNF/Hypercode_Resolution.md` §5.1

## M9 — Validation & adoption (DOCS/Positioning.md)
Expand Down
Loading