You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: INVARIANTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,7 +26,7 @@ materialization, messaging, DING, or presence must preserve them.
26
26
| **Harness context discipline** | The numeric `harness-context` record is a sibling of `harness-state` and shares none of its ownership machinery: `incarnation` is provenance and never a fence, and a straggler's write lands rather than being refused. A reading is written only when it enters a different bucket of `usedPercent`, when a compaction edge arrives, or when the record is older than the heartbeat, so a chatty producer cannot inflate the write rate; every landed write is byte-distinct, and freshness comes from the record's own `observedAtMs`, never file mtime. A withheld value is carried as `null` and never fabricated from zero, the previous reading, or a division st2 could have done itself, and a reading above the window is carried unclamped. There is no `unknown` on this axis: past the horizon the reading is returned marked `stale` with its age, surviving every derivation the categorical record makes, while an unparseable record, a foreign schema, an uninterpretable harness, and an untrustworthy clock each read as absent. The relaunch claim removes the record, and Doctor's high-reading and stale-record lines are advisory in both directions and never change its exit status. Where a producer ships, its numerator is the harness's own and is pinned to the build it was measured on: pi's `tokens` is the last assistant message's `totalTokens` and omp's is its prompt figure, so neither harness's arithmetic can be published under the other's tag, and a harness bump that changes a number's meaning without changing its shape fails a fixture rather than shipping. A harness that positively reports it does not know its own occupancy is forwarded as withheld in the same write as the compaction edge that emptied it, a compaction edge whose harness names no reason yields `unknown` rather than an invented word, and a durable count the producer cannot read narrows to st2 counting edges rather than losing them. | `src/harness_context.rs::a_reading_inside_the_written_bucket_does_not_write_and_a_crossing_does`; `src/harness_context.rs::a_withheld_percent_has_no_bucket_and_only_a_compaction_or_heartbeat_writes`; `src/harness_context.rs::a_record_older_than_the_heartbeat_is_rewritten_and_every_landed_write_is_byte_distinct`; `src/harness_context.rs::a_compaction_always_lands_with_its_trigger_and_may_carry_a_durable_count`; `src/harness_context.rs::withheld_values_are_null_and_are_never_fabricated`; `src/harness_context.rs::a_reading_above_the_window_is_carried_unclamped`; `src/harness_context.rs::a_stale_reading_is_returned_with_its_age_rather_than_derived_away`; `src/harness_context.rs::freshness_comes_from_the_record_bytes_and_never_from_file_mtime`; `src/harness_context.rs::additive_fields_decode_but_foreign_schema_and_harness_read_as_nothing`; `src/harness_context.rs::a_record_beyond_the_future_skew_bound_reads_as_nothing`; `src/harness_context.rs::a_straggler_lands_and_is_visible_as_provenance_rather_than_being_refused`; `src/harness_state.rs::the_relaunch_claim_removes_the_harness_context_record`; `src/agents.rs::context_is_a_fourth_axis_that_survives_an_indeterminate_observed_state`; `tests/doctor.rs::harness_context_doctor_lines_are_advisory_and_never_change_the_exit_status`; `src/pi_channel.rs::the_pi_0_84_2_fixture_pins_total_tokens_as_the_numerator`; `src/pi_channel.rs::the_omp_18_0_9_fixture_pins_prompt_input_as_the_numerator`; `src/pi_channel.rs::a_pi_compaction_withholds_the_reading_it_emptied_in_the_same_write`; `src/pi_channel.rs::an_omp_compaction_yields_unknown_because_the_event_names_no_reason`; `src/pi_channel.rs::an_unreadable_durable_count_degrades_to_counting_edges_not_to_losing_them`; `src/pi_channel.rs::context_frames_decode_conservatively_or_not_at_all`; `src/pi_channel.rs::the_measured_pi_release_is_the_one_the_extension_gate_pins`; `src/omp_session.rs::the_measured_context_builds_are_admitted_by_this_gate` |
27
27
|**Replicated-path discipline**| st2 pins the exact driver-record names it expects the replication transport's include list to carry — `harness-state` and `harness-context` — and both readers derive their paths from that list, so a rename cannot silently stop replication in a repository that does not own the list. A harness-context write never creates a staging file inside the agent directory: it stages outside the agent subtree, on the same filesystem, and leaves the record plus its own permanent lock and nothing else behind. `harness-state` still stages beside itself, pending its own change; the shared write helper takes the staging directory as an argument precisely because the two answer this differently. |`src/harness_context.rs::the_replicated_driver_record_names_are_pinned`; `src/harness_context.rs::writes_stage_outside_the_agent_subtree_and_leave_nothing_behind`|
28
28
| **Status-line slot chaining** | Claude's `statusLine` is a single slot whose winning declaration replaces the others outright, and `.claude/settings.local.json` — the file st2 materializes — wins over every other settings file. So st2's entry there is a tee: it records the reading and then invokes the operator's own renderer, resolved from `$ST_CLAUDE_STATUSLINE_RENDERER` and then `~/.claude/statusline-renderer.json`, first hit wins and never both. Where no renderer resolves, and wherever a resolved renderer fails, the tee writes NOTHING to stdout and puts its diagnostic on stderr: the payload is machine JSON, so echoing it into the slot is strictly worse for the operator than a blank row. Recording is unaffected by which arm runs. | `tests/claude_statusline.rs::the_tee_records_the_reading_and_hands_the_same_payload_to_the_env_renderer`; `tests/claude_statusline.rs::the_operator_file_supplies_the_renderer_when_no_variable_does`; `tests/claude_statusline.rs::the_variable_wins_over_the_file_and_the_file_is_never_also_run`; `tests/claude_statusline.rs::with_no_renderer_the_tee_renders_nothing_rather_than_the_raw_payload`; `tests/claude_statusline.rs::a_recording_failure_still_renders_the_status_line`; `tests/claude_statusline.rs::a_renderer_that_exits_non_zero_leaves_stdout_empty`; `tests/claude_statusline.rs::a_renderer_file_that_is_not_executable_leaves_stdout_empty`; `tests/claude_statusline.rs::without_st2_on_path_the_script_drains_stdin_and_renders_nothing`; `tests/claude_statusline.rs::the_rendered_registration_names_the_chaining_tee_and_carries_the_whole_slot` |
29
-
| **Version-pinned producer arithmetic** | Every harness-context producer publishes the number its own harness means by that number, and each one is pinned to the exact build the meaning was measured on: Claude's integer percent over `total_input_tokens` and `context_window_size` (2.1.250), Codex's window with the 12,000 baseline subtracted from both sides (codex-cli 0.150.1), pi's last assistant `totalTokens` and omp's prompt-only `input` (0.84.2 and 18.0.9), and OpenCode's last non-summary assistant total over the providers window (1.18.25). The failure this bounds is a harness bump that changes what a key means without changing its shape, which no type gate and no round-trip assertion can see, so each fixture decodes a verbatim capture, asserts the version literally, and asserts the wrong numerator the same capture would yield. | `src/claude_session.rs::a_mid_session_statusline_payload_yields_claudes_own_triple`; `src/claude_session.rs::a_pre_turn_statusline_payload_withholds_rather_than_reporting_zero`; `src/codex_app_server.rs::codex_context_recomputes_the_captured_reading_and_pins_its_verified_version`; `src/pi_channel.rs::the_pi_0_84_2_fixture_pins_total_tokens_as_the_numerator`; `src/pi_channel.rs::the_omp_18_0_9_fixture_pins_prompt_input_as_the_numerator`; `src/opencode_session.rs::captured_opencode_turns_publish_the_assistant_total_over_the_providers_window` |
29
+
| **Version-pinned producer arithmetic** | Every harness-context producer publishes the number its own harness means by that number, and each one is pinned to the exact build the meaning was measured on: Claude's integer percent over `total_input_tokens` and `context_window_size` (2.1.250), Codex's window with the 12,000 baseline subtracted from both sides (codex-cli 0.151.0), pi's last assistant `totalTokens` and omp's prompt-only `input` (0.84.2 and 18.0.9), and OpenCode's last non-summary assistant total over the providers window (1.18.25). The failure this bounds is a harness bump that changes what a key means without changing its shape, which no type gate and no round-trip assertion can see, so each fixture decodes a verbatim capture, asserts the version literally, and asserts the wrong numerator the same capture would yield. | `src/claude_session.rs::a_mid_session_statusline_payload_yields_claudes_own_triple`; `src/claude_session.rs::a_pre_turn_statusline_payload_withholds_rather_than_reporting_zero`; `src/codex_app_server.rs::codex_context_recomputes_the_captured_reading_and_pins_its_verified_version`; `src/pi_channel.rs::the_pi_0_84_2_fixture_pins_total_tokens_as_the_numerator`; `src/pi_channel.rs::the_omp_18_0_9_fixture_pins_prompt_input_as_the_numerator`; `src/opencode_session.rs::captured_opencode_turns_publish_the_assistant_total_over_the_providers_window` |
30
30
| **Native-driver diagnostics are bounded and recoverable** | One additive-tolerant `st2.driver-diagnostic.v1` snapshot exposes the earliest failing native-driver boundary through closed stage/reason/source/support vocabulary and origin-timed evidence age. Absent, malformed, foreign, unknown, and wrongly paired records never read healthy. Stage recovery clears only its own failure and removes the record after final recovery without changing prompt submission, retry, read-back, or archive semantics. Roster and Doctor share the typed reader/repair policy; telemetry labels contain only bounded stage/reason/source/support/outcome values, never versions, identities, prompts, messages, or paths. | `src/driver_diagnostic.rs::every_stage_reason_and_source_has_bounded_wire_vocabulary`; `src/driver_diagnostic.rs::additive_fields_decode_but_malformed_foreign_and_unknown_records_are_indeterminate`; `src/driver_diagnostic.rs::recovery_clears_only_its_stage_and_reveals_the_next_failure`; `src/opencode_session.rs::delivery_and_read_back_boundaries_publish_and_clear_diagnostics_without_changing_retry`; `src/metrics.rs::driver_diagnostic_metric_attributes_are_exactly_the_bounded_axes`; `tests/doctor.rs::native_driver_diagnostic_roster_and_doctor_agree_and_recovery_clears` |
31
31
|**Retirement health**| A retired declaration is healthy only after every declared task ID is absent. Any live or dead declared task record reports incomplete retirement; retired declarations do not require presence. Live declarations retain their existing task and presence checks. |`tests/doctor.rs::retired_declaration_is_healthy_when_tasks_and_presence_are_absent`; `tests/doctor.rs::retired_declaration_is_unhealthy_while_a_declared_task_is_alive`; `tests/doctor.rs::retired_declaration_is_unhealthy_while_a_dead_task_record_remains`|
32
32
|**Suspension health**| A suspended declaration is healthy when no declared task is live and every retained dead record is explicitly keep-pinned. It requires no presence, but this weaker result never proves retirement. Resume preserves ordinary keep and adopt-only policy. |`tests/doctor.rs::suspended_declaration_is_healthy_when_tasks_are_absent_without_presence`; `tests/doctor.rs::suspended_declaration_distinguishes_live_dead_keep_and_dead_nonkeep`; `tests/reconcile.rs::resuming_uses_ordinary_reconcile_and_does_not_override_keep`|
| omp | 18.0.9 (and 18.0.3) | injected extension `ctx.getContextUsage()`|`.tokens` = last assistant **`input`** only |`.contextWindow`|`.percent` (float) |
402
403
| opencode | 1.18.25 | SSE `message.updated` joined with `GET /config/providers`| last **non-summary** assistant `tokens.total`|`providers[].models[<modelID>].limit.context`| st2 computes `usedTokens / windowTokens`; the server displays none |
@@ -596,7 +597,7 @@ A compaction carrying an `agent_id` is a subagent's and never touches the record
596
597
matching the categorical producer's guard for the same reason: this record
597
598
describes the top-level window (`DQ-C9`).
598
599
599
-
### codex (codex-cli 0.150.1)
600
+
### codex (codex-cli 0.151.0)
600
601
601
602
st2 does not re-derive the percentage; it **mirrors** Codex's own
602
603
`TokenUsage::percent_of_context_window_remaining` and subtracts the result from
@@ -701,14 +702,13 @@ Three limits of the shipped producer, all deliberate:
701
702
before the binding candidate names one, and a thread starting now has no
702
703
history to replay.
703
704
704
-
Finally, a version note. The arithmetic above was settled by reading codex-cli
705
-
0.150.1's Rust source, and `CODEX_CONTEXT_VERIFIED_VERSION` pins that literal in
706
-
the fixture (HC-R13). It is **ahead of `SUPPORTED_CODEX_CLI_VERSIONS`**, the
707
-
delivery-path launch gate, which admits 0.145.0–0.147.0 — so in the shipped tree
708
-
this arithmetic runs against versions whose source was not read for it. The
709
-
baseline is a long-lived Codex constant, but that is an expectation rather than a
710
-
measurement, and closing the gap means repeating the delivery gate's own
711
-
admission checks for 0.150.1, which is a separate act from this producer.
705
+
Finally, a version note. The arithmetic and notification shape above were
706
+
reverified against codex-cli 0.151.0's Rust source, and
707
+
`CODEX_CONTEXT_VERIFIED_VERSION` pins that literal in the fixture (HC-R13). That
708
+
matches the newest build admitted by `SUPPORTED_CODEX_CLI_VERSIONS`; it does not
709
+
turn the measurement into a semantic-version promise. Every later Codex release
710
+
still requires its own source comparison and live delivery proof before the exact
0 commit comments