LearnNewsExamplesServices
Frontmatter
id17115
titleDeployment templates must project every behavior-binding clock — an unprojected inner timeout shipped blind on two successive plane generations
stateClosed
labels
enhancementaiagent-os
assigneesneo-opus-grace
createdAtAug 14, 2026, 3:06 PM
updatedAtAug 14, 2026, 9:17 PM
githubUrlhttps://github.com/neomjs/neo/issues/17115
authorneo-opus-vega
commentsCount0
parentIssue17072
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 14, 2026, 5:06 PM

Deployment templates must project every behavior-binding clock — an unprojected inner timeout shipped blind on two successive plane generations

Closed Backlog/active-chunk-16 enhancementaiagent-os
neo-opus-vega
neo-opus-vega commented on Aug 14, 2026, 3:06 PM

Problem

The canonical provider-lane compose templates project some embed clocks (NEO_OPENAI_COMPATIBLE_BATCH_EMBEDDING_TIMEOUT_MS, probe timeouts) but not others — the contention ladder leaves (NEO_OPENAI_COMPATIBLE_CONTENTION_TIMEOUT_MS, NEO_OPENAI_COMPATIBLE_CONTENTION_RETRY_COUNT) bind deadline-free interactive embedText calls yet appear in no template. An operator reading the deployment file sees 300s/900s deadlines and cannot see the ~47s ladder that actually binds behavior. That invisibility shipped on two successive plane generations and was only found by live provider-activity trace.

Projection = the leaf is present in the template with its default, a plane-class guidance comment (CPU-constrained vs GPU), and parity-checked against the config source.

Scope wording corrected post-merge (see #17125 debt 1). This sentence originally read "govern every single-input embed call", then "the interactive embedText path". Both overstated it: bulk work routes through embedTexts under the batch ceiling, and deadline-bearing probe calls bypass the ladder entirely#17122 landed caller-owned probe deadlines, so a probe carries its own deadline rather than inheriting the ladder. Three successive narrowings of one sentence is itself the finding: a scope claim in operator-facing prose attracts overstatement, because the writer knows the mechanism and the reader only gets the sentence.

Acceptance Criteria

  1. Canonical templates enumerate and project every clock in the declared namespaces × clockSuffixes profile, each with a plane-class guidance comment.
  2. The config-leaf-parity gate (or a successor template lint) fails when a behavior-binding clock leaf exists in ai/configBase.mjs without template projection — mechanically, not by review discipline.
  3. Existing planes' template deltas are enumerated in the PR body (which leaves become newly visible, with their effective current values unchanged).
  4. ADR-0019 compliance throughout (no re-derivation, no hidden defaults in templates).

AC-1 wording corrected post-merge (see #17125 debt 2). It originally read "every clock named by the ordering contract (the #17114-class derivation table)". #17114 closed NOT_PLANNED on 2026-08-14 without ever producing that table, so the criterion was anchored to an artifact that will never exist. PR #17117's body was corrected to own its declared set; this ticket was not, and a closed ticket stays discoverable — so the two disagreed with the more findable one being wrong. Coverage is what the declared profile says, and widening it is a reviewable policy edit rather than an appeal to a missing derivation.

Contract Ledger

Added post-merge per #17125 debt 2. Read from the shipped artifact ($behaviorBindingProjection in ai/scripts/lint/config-leaf-parity.json at origin/dev), not from the PR narrative.

Target Surface Source of Authority Behavior Failure Posture Evidence
$behaviorBindingProjection.clockSuffixes config-leaf-parity.json, reviewed as a policy edit Selects timing/retry leaves mechanically by suffix — no semantic judgment at lint time. Shipped set: _CHUNK_SIZE, _KEEP_ALIVE, _RETRY_COUNT, _RETRY_DELAY_MS, _TIMEOUT_MS, _YIELD_MS (6). A leaf outside the suffix set is simply not in scope — silent by design, which is why widening is a deliberate edit and not a heuristic lint-config-template-ssot suffix matching
$behaviorBindingProjection.profiles[file].namespaces same Bounds which env prefixes a given template is responsible for. Shipped: NEO_OPENAI_COMPATIBLE_ (1 namespace, 1 profile). Out-of-namespace env names are not demanded of that file per-profile loop in detectUnprojectedBehaviorBindingClocksFromSources
Per-line projection shape classifyProjection A projected line must carry the canonical # ENV: "value" # guidance shape, both token boundaries, a value equal to the resolved config default, and non-empty trailing guidance. Four distinct violation codes rather than one: unprojected-behavior-binding-clock, projection-default-mismatch, projection-missing-guidance, plus the guidance-block count mutation-tested in PR #17117; a stale value, prose, or an OLD_-prefixed token each fail
Declared guidance-block count profiles[file].guidanceBlocks Prose blocks are counted, not inferred. Shipped: 3. Deleting a guidance block is a policy edit someone reviews, not a silent deletion — the per-line annotations alone once left this green the count check, added after exactly that false green
Lint scan surface SCAN_SURFACE Declares ai/deploy/** alongside the .mjs roots, so the sibling parity spec demands the CI workflow watch it. An undeclared read surface would let the spec report a satisfied invariant over an incomplete picture — the same shape as the unprojected clock these rules exist to catch, one layer up lint-guard-ci-parity

Successor note. PR #17135 (#17121) widens this policy to 8 suffixes (_PERCENT, _WINDOW_MS), 3 namespaces (NEO_MEMORY_SATURATION_, NEO_STORE_MEMORY_SATURATION_) and 4 guidance blocks. The table above is the state this ticket shipped; the widening is recorded in that PR's own ledger.

Evidence class

Template-vs-configBase diff (contention leaves absent from all templates) + the two-generation blind-ship history, 2026-08-14.

Part of epic #17072.

tobiu referenced in commit a1ccb2d - "feat(ai): project every behavior-binding clock and gate the unprojected ones (#17115) (#17117) on Aug 14, 2026, 5:06 PM
tobiu closed this issue on Aug 14, 2026, 5:06 PM