Skip to content

feat(hermes): admit ATOF/ATIF real-bytes gaps, state.db v19 drift, verification ledger#3092

Merged
Sinity merged 4 commits into
masterfrom
feature/feat/hermes-atof-fidelity
Jul 18, 2026
Merged

feat(hermes): admit ATOF/ATIF real-bytes gaps, state.db v19 drift, verification ledger#3092
Sinity merged 4 commits into
masterfrom
feature/feat/hermes-atof-fidelity

Conversation

@Sinity

@Sinity Sinity commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

Continuation of PR #3087 (merged as fee0799 with only its first commit — this branch grew four more commits afterward that never made it into that squash-merge, since #3087 was merged mid-session while this work was still landing). Admits real ATOF lifecycle events, proves ATIF tool_calls fidelity against real bytes, closes a real state.db v16→v19 schema-drift gap, and imports Hermes's own verification_evidence.db claim-vs-evidence ledger as structured outcomes (Ref polylogue-fs1.2.1, polylogue-wj25).

Problem

  • Two real, well-defined ATOF lifecycle event shapes (the outer session-scope boundary kind=scope,category=agent, and hermes.session.end marks) fell into the generic unrecognized-event bucket despite being present, unused, in the already-committed real ATOF fixture.
  • The real ATIF fixture used to originally admit fs1.2.1 was a minimal message-only session, so tool_execution_spans fidelity stayed "inferred" despite real trajectories with the tool_calls/observation shape sitting on disk.
  • The live ~/.hermes/state.db schema is at SCHEMA_VERSION=19, nine versions past the v16 baseline previously verified — nine real columns (gateway-routing identity from Hermes's #9006 chat-platform bridging, compression-retry state) were silently dropped by every import.
  • verification_evidence.db — Hermes's own command/exit-code/status verification ledger — was retained as a watched artifact (feat(daemon): watch Hermes runtime evidence #3084) but never parsed, so Hermes sessions carried none of the structured verification evidence the archive's claim-vs-evidence lanes are built around.

Solution

Four commits (b96cc97d1, c8db6706e, 1d716e985, 18f326632):

  1. ATOF lifecycle events (hermes_spans.py): kind=scope,category=agent and hermes.session.* marks now normalize to typed hermes_context_span evidence. context_events fidelity moves to exact; unrecognized_atof_events drops to zero on the real fixture.
  2. ATIF tool_calls proof: appended one real, privacy-redacted step (4 parallel tool_calls + correlated observation.results, drawn from a separate live trajectory) to the checked-in ATIF fixture. tool_execution_spans now reports exact fidelity like llm_request_spans. Added tests/fixtures/hermes/atif/README.md documenting provenance (the ATOF fixture already had one).
  3. state.db v19 drift (hermes_state.py): added gateway_identity and compression_recovery capability groups, extended lifecycle with expiry_finalized, wired all fields into the existing hermes_session_metadata event. Added a schema-drift canary test pinning the live-verified v19 column set against the parser's capability maps, and fixed a pre-existing stale contract file (state_db_v16.contract.json) that testmon hadn't caught.
  4. Verification-ledger import (new hermes_verification.py): parses verification_events/verification_state into a verification:<hermes_session_id> observer session — same deferred-physical-merge pattern as ATOF/ATIF. command/canonical_command/output_summary round-trip verbatim (this is Hermes's own recorded evidence, not conversational content, so ATOF/ATIF's payload-hygiene bound doesn't apply — documented in the module docstring). Wired through every route state.db already uses (dispatch, source_walk/source_parsing live ingest, live/batch full-batch ingest, import-explain CLI). session_id="default" (the producer's own unknown-identity fallback) is marked ambiguous_correlation, never trusted. Artifact-taxonomy split follows state.db's own precedent exactly: raw-path classification stays non-session (protects schema sampling from raw SQLite bytes), marker-payload classification is session-eligible.

Verification

  • devtools test tests/unit/sources/parsers/test_hermes_spans.py — 17/17.
  • devtools test tests/unit/sources/parsers/test_hermes_verification.py — 9/9.
  • devtools test tests/unit/sources/parsers/test_hermes_state_schema_canary.py — 2/2.
  • Full hermes-touching regression sweep (dispatch/sampling/watcher/artifact-inspection/import/lineage/import-explain, 236 tests) — all green.
  • devtools verify --quick green after every commit.

Known honest gaps, not silently assumed: ATIF subagent_delegation stays "inferred" (no real export sampled has a non-empty subagent_trajectories); the verification-ledger session id has no profile-qualification (same accepted gap ATOF/ATIF's observer: id already has); ATOF partial-final-line/rotation-truncation cursor behavior and unpaired-event debt remain deferred (fs1.2.1's remaining AC).

Ref polylogue-fs1.2.1
Ref polylogue-wj25

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Sinity, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 47c0ac44-4e9e-47f3-8646-d613ee09c9dc

📥 Commits

Reviewing files that changed from the base of the PR and between 20c07a0 and 2d17a8d.

📒 Files selected for processing (20)
  • docs/plans/topology-target.yaml
  • docs/topology-status.md
  • polylogue/archive/artifact_taxonomy/runtime.py
  • polylogue/schemas/providers/hermes/state_db_v16.contract.json
  • polylogue/sources/dispatch.py
  • polylogue/sources/import_explain.py
  • polylogue/sources/live/batch.py
  • polylogue/sources/live/batch_support.py
  • polylogue/sources/origin_specs.py
  • polylogue/sources/parsers/hermes_spans.py
  • polylogue/sources/parsers/hermes_state.py
  • polylogue/sources/parsers/hermes_verification.py
  • polylogue/sources/source_parsing.py
  • polylogue/sources/source_walk.py
  • tests/fixtures/hermes/atif/README.md
  • tests/fixtures/hermes/atif/nemo_relay_atif_v1.7_real_redacted.json
  • tests/unit/sources/parsers/test_hermes_spans.py
  • tests/unit/sources/parsers/test_hermes_state_schema_canary.py
  • tests/unit/sources/parsers/test_hermes_verification.py
  • tests/unit/sources/test_hermes_import_explain.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/feat/hermes-atof-fidelity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Sinity and others added 4 commits July 18, 2026 15:09
…events

Problem: real events.jsonl evidence (~/.hermes/observability/nemo-relay/atof/)
shows the outer session-wrapping scope (kind=scope,category=agent) and
hermes.session.end marks are well-defined lifecycle events, but the ATOF
parser classified both as generic unrecognized hermes_observer_span,
degrading fidelity for evidence the producer already emits structurally.

What changed: kind=scope/category=agent scope pairs and hermes.session.*
marks now normalize to typed hermes_context_span events (same treatment as
hermes.turn.*), synthesizing a stable context_event key from scope_category
since the scope's own name field carries the session identifier, not an
event key. context_events fidelity moves from absent/degraded to exact on
the real redacted ATOF fixture; unrecognized_atof_events drops to zero.

Ref polylogue-fs1.2.1

Co-Authored-By: Claude <noreply@anthropic.com>
…bytes

Problem: the real ATIF fixture used to admit fs1.2.1 came from a minimal
message-only session, so tool_execution_spans fidelity stayed "inferred"
even though the parser's tool_calls/observation mapping was never verified
against real evidence -- despite real trajectories with that exact shape
already sitting on disk (~/.hermes/observability/nemo-relay/atif/).

What changed: appended a real, privacy-redacted step (4 parallel tool_calls
with correlated observation.results, drawn from a separate live trajectory)
to the checked-in ATIF fixture. tool_execution_spans now reports "exact"
fidelity like llm_request_spans, since the field mapping is proven, not
just this session's bytes. subagent_delegation stays "inferred" honestly --
no real ATIF export sampled so far has a non-empty subagent_trajectories.
Added tests/fixtures/hermes/atif/README.md documenting fixture provenance
(the ATOF fixture already had one; ATIF didn't).

Ref polylogue-fs1.2.1

Co-Authored-By: Claude <noreply@anthropic.com>
Problem: live ~/.hermes/state.db is at SCHEMA_VERSION=19 (checked read-only
against a snapshot), nine versions past the v16 baseline fs1.1 verified.
Nine real columns -- session_key/chat_id/chat_type/thread_id/display_name/
origin_json (v18 gateway metadata consolidation, #9006) and
expiry_finalized/compression_failure_cooldown_until/compression_failure_error
-- were structurally present but mapped to no capability group, so every
Hermes session import silently dropped them regardless of schema, violating
the "every unsupported column lands in the fidelity declaration" AC.

What changed: added gateway_identity and compression_recovery capability
groups, extended lifecycle with expiry_finalized, and wired all nine fields
into the existing hermes_session_metadata event (same treatment as
source/user_id/handoff_state). Added a schema-drift canary
(test_hermes_state_schema_canary.py) pinning the live-verified v19 column
set against the parser's capability maps so a future schema bump that adds
an unmapped column fails loudly instead of silently vanishing.

This repo's live install is CLI-only (no gateway data), so a fixture proves
the mapping the same way the existing v16-vs-v17 fixture pair already does.

Ref polylogue-fs1.1

Co-Authored-By: Claude <noreply@anthropic.com>
Problem: Hermes writes verification_events (command/canonical_command/
kind/scope/status/exit_code/output_summary) and verification_state
(changed_paths per session/root) to verification_evidence.db -- its own
claim-vs-evidence ledger, live-verified against ~/.hermes/. Polylogue only
retained this SQLite artifact as a watched METADATA_DOCUMENT sidecar
(parse_as_session=False); it was never normalized, so Hermes sessions
carried none of the structured verification evidence the archive's
claim-vs-evidence lanes are built around.

What changed: new polylogue/sources/parsers/hermes_verification.py parses
the real producer schema (schema v1, exit_code always known, kind in
lint/typecheck/build/format/check/test/ad_hoc, scope targeted/full, status
passed/failed) into a verification:<hermes_session_id> observer-evidence
session -- same deferred-physical-merge pattern hermes_spans.py already
established for ATOF/ATIF, not a new mechanism. command/canonical_command/
output_summary round-trip verbatim (this is Hermes's own recorded evidence,
not conversational content, so ATOF/ATIF's payload-hygiene bound doesn't
apply). A session_id of "default" (the producer's own fallback for unknown
session identity) is marked ambiguous_correlation rather than trusted.

Wired through every route state.db already uses: dispatch.py (marker
detection/parsing), source_walk.py + source_parsing.py (live streaming
ingest), live/batch.py + live/batch_support.py (full-batch ingest),
import_explain.py (CLI dry-run). The artifact-taxonomy raw-path
classification stays METADATA_DOCUMENT/parse_as_session=False (protects
pre-JSON-decode consumers like schema sampling from raw SQLite bytes,
matching state.db's split); the marker-payload classification is now
SESSION_DOCUMENT/parse_as_session=True, matching state.db's own precedent
exactly. import_explain.py's SQLite structural checks now run before the
raw-path taxonomy skip-check, since that skip-check exists for a different
consumer than the SQLite-specific parse routes.

Fixed a pre-existing gap surfaced along the way: the state.db capability-map
contract test (test_hermes_state_db_contract_matches_parser_capability_map)
was silently stale after the prior v19 schema-drift commit added
gateway_identity/compression_recovery capabilities -- testmon hadn't
selected it. Updated state_db_v16.contract.json to match.

Ref polylogue-wj25

Co-Authored-By: Claude <noreply@anthropic.com>
@Sinity
Sinity force-pushed the feature/feat/hermes-atof-fidelity branch from 18f3266 to 2d17a8d Compare July 18, 2026 13:13
@Sinity
Sinity merged commit d527123 into master Jul 18, 2026
3 checks passed
@Sinity
Sinity deleted the feature/feat/hermes-atof-fidelity branch July 18, 2026 13:38
Sinity added a commit that referenced this pull request Jul 18, 2026
)

## Summary
Continuation of the maximalist Hermes fidelity program (Ref
polylogue-fs1.2.1, polylogue-wj25, polylogue-fs1.15) after PR #3092
merged. Closes out the remaining ATOF fs1.2.1 AC items that were
tractable in-scope, and empirically investigates two `fs1.2.1`/`fs1.15`
open questions that turned up two previously-unknown, confirmed
live-ingestion bugs — both pinned as `xfail(strict=True)` regression
witnesses with dedicated beads, not silently left undiscovered.

## Problem
fs1.2.1's remaining AC explicitly flagged "append resume" and "unpaired
events" as open concerns, and fs1.15 asked whether Hermes
coverage/freshness already flows through the existing named-source
freshness surface. Investigating these empirically (driving the real
`LiveBatchProcessor`, not just re-reading code) surfaced:

1. **Unpaired ATOF scope debt was invisible.** A `kind=scope` UUID that
never sees both its `start` and `end` phase (a crashed request, or a
truncated/rotated file cutting a pending scope in half) was
indistinguishable from a normal completed span.
2. **Confirmed data loss (polylogue-flxh):** real
`~/.hermes/observability/nemo-relay/atof/events.jsonl` is ONE file
shared across every Hermes session on an install. The live-ingest
raw-revision-authority replay chain requires exactly one logical session
per raw revision — correct for Claude Code/Codex/Beads (always one file,
one session), but genuinely violated by ATOF's shared-file shape. A
growth batch spanning a session boundary silently and permanently loses
the pre-existing session's new event.
3. **Confirmed crash (polylogue-1zex):** a Hermes `state.db` or
`verification_evidence.db` with exactly ONE session at ingest time
crashes the live watcher's full-ingest path with `UnicodeDecodeError` —
`revision_backfill.py`'s `_parse_one` (shared with historical repair)
has zero SQLite awareness, unlike the two other Hermes call sites that
correctly special-case it. Real installs almost always have 2+ sessions,
which is presumably why this escaped the earlier Phase 0 review (PR
#3084, merged).

## Solution
Three commits:
1. `feat(hermes): surface ATOF unpaired scope UUIDs as explicit debt` —
`parse_atof_stream` now tracks scope-phase pairing per UUID and emits a
typed `hermes_atof_unpaired_scope` event for any UUID missing either
phase, plus a new `unpaired_scope_debt` fidelity capability. Verified
against the real fixture (`llm-error-1`, a genuine unpaired scope
already present in the committed fixture) and two new synthetic tests
(start-only, end-only, and a paired-is-not-flagged sanity check).
2. `fix(hermes): document and pin confirmed ATOF shared-file data-loss
bug` — empirical regression test driving the real watcher through a
session-boundary-spanning growth batch; direct sqlite inspection proves
the loss. Filed polylogue-flxh with three candidate fix directions (none
chosen — this is core shared ingest plumbing used by every live
provider, deserves its own reviewed pass). Added a loud fidelity caveat
to `hermes_spans.py`'s module docstring.
3. `test(hermes): prove named-source freshness coverage, pin
single-session crash` — proves `project_named_source_freshness`
(origin-agnostic, no new code needed) correctly covers Hermes
state.db/ATOF once ingestion succeeds; separately confirms and pins the
single-session SQLite crash. Filed polylogue-1zex.

## Verification
- `devtools test tests/unit/sources/parsers/test_hermes_spans.py` —
19/19.
- `devtools test tests/unit/sources/test_live_watcher.py` — 85 passed, 1
xfailed (expected).
- `devtools test
tests/unit/sources/test_hermes_source_freshness_integration.py` — 2
passed, 1 xfailed (expected).
- `devtools verify --quick` green after every commit.

Known residual gaps, tracked not silently dropped: polylogue-flxh and
polylogue-1zex (both filed, neither fixed — both require careful design
review of shared core ingest plumbing rather than a rushed patch in this
pass). ATIF subagent topology materialization and verification-ledger
session-id profile-qualification remain explicitly deferred design
decisions (documented in prior session's bead notes), not attempted here
since they'd change shipped public identity contracts without operator
sign-off.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sinity added a commit that referenced this pull request Jul 19, 2026
…cannot claim (#3173)

## Summary

Adds `docs/hermes-operators.md`, a source-grounded operator guide
answering
the question a Hermes operator asks before pointing Polylogue at their
local
runtime: what does it watch, what fidelity does each artifact class get,
and
what does it explicitly not support yet. Written for the Nous Discord
`#plugins-skills-and-skins` audience.

## Problem

polylogue-lrou's stated prerequisite -- source fidelity +
verification-ledger
paths -- has shipped (PR #3084 Hermes runtime watcher coverage, #3092
verification_evidence.db structured import, #3120 verification-coverage
correlation primitive), but no consolidated operator-facing document
existed.
Fidelity-visibility and privacy boundaries are the trust-building
content this
audience needs; scattered module docstrings are not discoverable by an
external reader deciding whether to trust the bridge.

## Solution

- `docs/hermes-operators.md` (guide tier), registered in
  `devtools/docs_surface.py`; `docs/README.md` regenerated via
  `devtools render docs-surface`.
- Every claim cites current source: five-layer `sources.hermes.root` /
`POLYLOGUE_HERMES_ROOT` config resolution (`polylogue/config.py`);
watched
source classes and acquisition methods
(`polylogue/sources/live/watcher.py`,
  `polylogue/sources/dispatch.py`); the closed
  exact/degraded/absent/inferred/redacted fidelity vocabulary with a
  per-artifact capability table for `state.db`, ATIF, ATOF, and
  `verification_evidence.db` (`hermes_state.py`, `hermes_spans.py`,
`hermes_verification.py`); the `observer:`/`verification:`
session-identity
  scheme and its deliberately-deferred physical merge; verified query/
forensics entry points (`import --explain`, `find --origin
hermes-session`,
`read --view raw|transcript`, the MCP `query` tool's `origin` field,
citing
`docs/agent-manual.md`'s live 10-tool contract over the stale ~100-tool
  count in `docs/mcp-reference.md`); and local-only/no-network/per-class
  payload-hygiene privacy boundaries.
- A dedicated "What Polylogue cannot claim" section lists nine real,
current
limitations -- the credibility core the bead asked for -- including one
empirically verified while writing this doc: importing both the
checked-in
  ATIF and ATOF fixtures (same underlying Hermes `session_id`) into a
throwaway archive collapses to **one** archive session, carrying only
the
  most-recently-materialized artifact's evidence (content-hash revision
  replace, not a union); the other artifact's raw bytes remain durably
  retained but are not part of the queryable session. No existing test
  asserts either behavior for this combination.
- Also notes `hermes_verification_coverage` (fs1.4) has no CLI/MCP
surface
yet -- Python-only today, per that bead's own scoping note -- and that
no
  named Hermes forensics report command exists.

A `KeyError('rank')` crash in `read --view transcript` after a keyword
`find` (origin-agnostic, first hit via a Hermes query) was discovered
while
gathering verification evidence; filed as `polylogue-ajmu` rather than
fixed
here -- out of this bead's scope.

## Verification

- `devtools render docs-surface` then `devtools render all --check` --
every
  generated surface reports sync OK, exit 0.
- `devtools verify --quick` -- format/lint/mypy/render-all-check green,
including `verify doc-commands`, which validates every CLI example in
the
  new doc against the live command/flag surface.
- Every quoted command output (`import --explain` fidelity blocks for
both
  ATIF and ATOF fixtures; `find --origin hermes-session ... read --all
  --format json`; `read --view transcript` / `--view raw --format json`
  against an exact ref) was run live against a throwaway
`POLYLOGUE_ARCHIVE_ROOT` seeded only from `tests/fixtures/hermes/`,
never a
  live archive.

Ref polylogue-lrou

Co-Authored-By: Claude <noreply@anthropic.com>

Co-authored-by: Claude <noreply@anthropic.com>
Sinity added a commit that referenced this pull request Jul 21, 2026
## Summary

Closes the remaining conformance-law gaps in the OriginSpec admission
kernel
(`polylogue/sources/origin_specs.py`) against every clause of
`polylogue-2qx.1.1`'s acceptance criteria: a
public-origin/Provider-token leak
guard, a stream/parser binding parity check against dispatch, and a live
proof of the `lifecycle="reserved"` admission path.

## Problem

`polylogue-2qx.1.1` asked for the OriginSpec admission kernel (built on
the
`polylogue/declarations` DeclarationSpec kernel from `polylogue-o21.1`)
plus a
conformance law where missing parser, stream/parser conflict, ambiguous
detector order, absent fixture, undeclared coverage, leaked Provider
token,
and non-injective Provider-to-Origin collision each yield a
source-locatable
diagnostic.

Auditing the live repo found the kernel **already exists on master** —
`polylogue/sources/origin_specs.py` landed incrementally via unrelated
feature PRs (#3051, #3087, #3088, #3092, #3201, #3228: Claude Workflow
admission, Hermes ATOF/ATIF, the Grok parser, provider_completeness
migration) without ever citing this bead, so `bd`'s tracking never
reflected
it — the 2026-07-18 warroom sweep found no bead-tagged commits and reset
the
bead to open even though the code was there. It already covers all 11
`Origin` tokens, consumes the declarations kernel correctly, and is
wired
into `provider_completeness.py`, the artifact taxonomy, the live
watcher, and
Claude Code orchestration.

Auditing it clause-by-clause against the AC found three real gaps:

1. No diagnostic caught a public origin `public_name` colliding with a
raw
   `Provider`-wire token — the doctrine in
`docs/provider-origin-identity.md` ("no provider wording on public
origin
   surfaces") was enforced only indirectly (public_name must equal
   `origin.value`, and no current `Origin`/`Provider` pair happens to
collide), with no explicit guard or diagnostic for a future collision.
2. No check parity-verified declared `stream_parser_path` presence
against
`sources/dispatch.py:STREAM_RECORD_PROVIDERS` — a stream/parser binding
could silently drift from dispatch's actual streaming behavior with no
   diagnostic.
3. The module docstring still claimed a live "reserved origin" pilot,
but
Grok shipped a real parser (`polylogue-611`, #3201) after this bead was
written, so no `OriginSpec` is currently `lifecycle="reserved"` and that
   admission path had no live proof.

## Solution

- Added `_PROVIDER_TOKEN_VALUES` and a guard in
`OriginSpecRegistry.register()`
that rejects a declaration whose `public_name` collides with any
`Provider`
enum value, ordered before the existing public-name/origin equality
check
  so it is independently testable (a synthetic declaration can trip it
  without also tripping the equality check).
- Added `validate_stream_parser_parity()`, parity-checked against
  `sources/dispatch.py:STREAM_RECORD_PROVIDERS` the same way
`validate_dispatch_precedence()` already parity-checks detector
tightness
order. **Zero edits to `dispatch.py`** — only a new read-only import of
its
  existing `STREAM_RECORD_PROVIDERS` constant, respecting this slice's
ownership boundary with the concurrent `ingest_worker.py`/`decoders.py`
  lane.
- Updated the module docstring to honestly state Grok's promotion from
reserved to executable, and point at the new synthetic
reserved-lifecycle
test as the live proof of that admission path (since no real production
  `Origin` is currently reserved).
- Added five tests to `tests/unit/sources/test_origin_specs.py`:
undeclared-
  coverage rejection, provider-token-leak rejection, a synthetic
`lifecycle="reserved"` registration (built via `replace()` of the real
Grok
spec) proving the reserved admission contract requires no
parser/detector
tightness while still requiring coverage/fixture evidence, and positive
  plus negative stream/parser parity checks.

## Verification

- `devtools test tests/unit/sources/test_origin_specs.py` → 8 passed
- `devtools test tests/unit/sources/test_dispatch_ordering.py
tests/unit/sources/test_dispatch_payloads.py` → 21 passed
- `devtools test -k "provider_completeness or origin_specs or
dispatch_ordering"` → 26 passed
- `mypy --strict polylogue/sources/origin_specs.py
tests/unit/sources/test_origin_specs.py` → Success, no issues found
- `devtools verify --quick` → exit 0 (all 16 steps ok: format, lint,
mypy, render all, topology, layering, closure-matrix, schema roundtrip,
manifests, ci-workflows, doc-commands, docs-coverage,
test-infra-currency, test-clock-hygiene, pytest-timeout-overrides,
degrade-loudly)
- No new module/file added, so no topology projection regen was
required.

## AC matrix

| # | AC | Status |
| --- | --- | --- |
| 1 | `origin_specs.py` defines complete typed fields/lifecycle states,
consumes `polylogue/declarations` without adding source semantics to
that kernel | Satisfied (pre-existing on master; verified by reading
`polylogue/declarations/*` and confirming `origin_specs.py` only wraps
`DeclarationSpec`/`DeclarationRegistry`, adding no kernel-layer
semantics) |
| 2 | Claude Code / ChatGPT / reserved Grok pilots derive/validate
deterministic tightness, parser/assembly registration, public origin
values, coverage/completeness rows, fixtures, docs, reparse consequences
from one declaration each | Satisfied for Claude Code (executable,
tightness 60, stream+artifact-rule bindings) and ChatGPT (executable,
tightness 70). Grok itself is now executable (real parser shipped after
this bead was written, #3201) rather than reserved; the
reserved-lifecycle admission contract is proven live by this PR's new
synthetic test rather than by a real reserved origin, since every
current public `Origin` token is admitted as executable or
compatibility-only |
| 3 | `dispatch.py` uses derived registration/order or is parity-checked
by it; adding a synthetic executable origin requires one OriginSpec +
adapter + fixtures | Satisfied — `validate_dispatch_precedence()`
(pre-existing) plus this PR's new `validate_stream_parser_parity()`
parity-check `dispatch.py`'s
`RECORD_DETECTOR_PROVIDER_ORDER`/`STREAM_RECORD_PROVIDERS` without
restructuring dispatch.py |
| 4 | Missing parser / stream-parser conflict / ambiguous or cyclic
detector order / absent fixture / undeclared coverage / leaked Provider
token / non-injective collision each yield a source-locatable diagnostic
+ repair | Satisfied — missing parser, absent fixture, and non-injective
collision without policy were pre-existing `ValueError` raises (now also
covered by a dedicated undeclared-coverage test in this PR); ambiguous
detector order was pre-existing (`ambiguous_detector_tightness`); this
PR adds the previously-missing stream/parser-conflict diagnostic
(`stream_parser_parity_mismatch`) and leaked-Provider-token guard.
"Cyclic" detector order has no distinct failure mode beyond ambiguous
tightness, since tightness is a total order, not a graph |
| 5 | Provider stays in adapters, Origin is the public vocabulary,
Gemini/Drive-style collisions require an explicit collision policy |
Satisfied (pre-existing `collision_policy` field + registration guard,
exercised by `aistudio-drive`'s `Provider.GEMINI`/`Provider.DRIVE`
fiber) |
| 6 | Focused
declaration/dispatch/public-schema/completeness/fixture/mutation/render/quick
verification passes | Satisfied — see Verification section above |

`polylogue-2qx.1.2` (migrate every current origin onto OriginSpec,
delete
parallel inventories) is explicitly out of this slice's scope per the
bead's
own design text — it is largely already superseded in practice too (all
11
origins are already declared here and `provider_completeness.py` already
projects from `ORIGIN_SPECS`), but a formal audit of that bead's own AC
(exact-eleven-token enumeration, parallel-inventory deletion, dispatch
golden fixture) is left to whoever picks it up.

Ref polylogue-2qx.1.1

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Prevented origin names from exposing internal provider terminology.
* Added validation to ensure origin evidence is complete before
registration.
  * Improved consistency checks for origins that support streaming data.
* **New Features**
* Added support for reserved-lifecycle origins used in fixtures,
including required supporting evidence without requiring parser
configuration.
* Added diagnostics for mismatches between streaming capabilities and
origin configuration.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude <noreply@anthropic.com>
Sinity added a commit that referenced this pull request Jul 21, 2026
…gue-2qx.1.2) (#3250)

## Summary

Audits and closes the remaining gap in polylogue-2qx.1.2 ("migrate every
current origin onto OriginSpec"). Most of this bead's scope was already
shipped to `master` untagged across
#3051/#3087/#3088/#3092/#3201/#3228/#3246
(closing `polylogue-2qx.1.1`'s notes confirm this). This PR verifies
that
prior work end-to-end, proves the parity checks actually catch
regressions
(not just pass today), and closes one concrete residual gap: a second,
un-declared provider-to-assembly-hook dispatch that Claude Code, Codex,
and
AI Studio/Drive depend on.

## Problem

`polylogue/sources/origin_specs.py` already declares all eleven `Origin`
tokens with lifecycle/detector-tightness/parser/fixture/coverage
bindings,
and `polylogue/sources/provider_completeness.py` already derives its
rows
from `ORIGIN_SPECS` (`PACKAGE_MODE_SPECS` is a tuple comprehension over
it,
parity-proven by
`test_provider_completeness_is_a_projection_of_every_origin_spec`).
Dispatch-order and stream-parser-binding parity are also already
mechanically checked (`validate_dispatch_precedence`,
`validate_stream_parser_parity`) against the real production values in
`sources/dispatch.py` (`RECORD_DETECTOR_PROVIDER_ORDER`,
`STREAM_RECORD_PROVIDERS`).

What was genuinely missing: the bead's design explicitly calls for
"Claude
Code and Codex specs [to] expose typed
assembly/orchestration/title/action
extension hooks (consumed later by 2qx.2, j2zz, ih67) — a typed field on
the spec, not another registry."
`polylogue.sources.assembly.get_assembly_spec()`
is exactly that second, un-declared provider dispatch
(`ProviderAssemblySpec` factory for
`Provider.CLAUDE_CODE`/`Provider.CODEX`/
`Provider.GEMINI`) — it existed in production but had no OriginSpec
declaration or parity check, so a caller had no way to discover the hook
from `origin_specs.py` and no test would catch it drifting from the real
registry.

Also: `docs/provider-origin-identity.md` documented
Provider/Origin/Source
doctrine but never pointed at `origin_specs.py` as the per-origin
admission
authority a reader should trust over any hand-maintained list.

## Solution

- `polylogue/sources/origin_specs.py`: added
`OriginSpec.assembly_spec_path`
  (`"module/path.py:ClassName"` or `None`) declaring which
`ProviderAssemblySpec` a given origin's provider wire binds. Populated
for
  the three origins with a real live hook: `claude-code-session` →
  `assembly_claude_code.py:ClaudeCodeAssemblySpec`, `codex-session` →
  `assembly_codex.py:CodexAssemblySpec`, `aistudio-drive` →
`assembly_gemini.py:GeminiAssemblySpec` (its `Provider.GEMINI` wire is
the
one `get_assembly_spec` keys on). Added
`validate_assembly_spec_parity()`,
  following the exact idiom of `validate_dispatch_precedence`/
`validate_stream_parser_parity`: it checks the declared field against
the
live `get_assembly_spec(provider)` return value rather than replacing
that
  registry with a second one in `origin_specs.py`.
- `tests/unit/sources/test_origin_specs.py`: two new tests — one
asserting
the three declared hook paths (and `None` for two origins without a live
hook), one asserting `validate_assembly_spec_parity(get_assembly_spec)
== ()`
plus the mutation shape (a resolver that always returns `None` makes
every
origin that declares a hook path report
`assembly_spec_parity_mismatch`).
- `docs/provider-origin-identity.md`: added an "Origin admission"
section
  naming `origin_specs.py` as the per-origin declaration authority and
  pointing at both live-production parity checks.
- No parallel hand-maintained inventory was deleted, because the audit
found
none left inside my ownership (`polylogue/sources/**`) — see the
residual
  below for the one still outstanding elsewhere.

### Residual found outside owned scope

`polylogue/cli/shell_completion_values.py:_ORIGIN_DESCRIPTIONS` is a
hand-maintained `dict[str, str]` of 8 of the 11 origin tokens (missing
`beads-issue`, `grok-export`, `unknown-export`) used for
shell-completion
help text, and it is **not** parity-checked against
`Origin`/`ORIGIN_SPECS`
the way `polylogue/agent_integration/spec.py:ORIGIN_MEANINGS` already is
(that one has a `RuntimeError` guard requiring exact `Origin`-enum order
match — already satisfies AC4, no action needed there). `cli/**` is out
of
this lane's ownership (per dispatch instructions, another lane owns it
concurrently); flagging as a follow-up rather than touching it here.

## Verification

- `devtools test tests/unit/sources/test_origin_specs.py
tests/unit/sources/test_provider_completeness.py` → **15 passed**
- `devtools test tests/unit/sources/ -k "origin_specs or
provider_completeness or dispatch or assembly"` → **144 passed**
- `devtools test tests/unit/sources/test_parsers_props.py` (protected
file) → **43 passed**
- `devtools verify --quick` → all 16 steps `ok`, `"exit_code": 0` (ruff
format/check, mypy --strict, render all,
topology/layering/closure-matrix, manifests, ci-workflows, doc-commands,
docs-coverage, test-infra-currency, test-clock-hygiene,
pytest-timeout-overrides, degrade-loudly)
- Anti-vacuity mutations, run manually then reverted (`git checkout
--`), each confirmed the *existing* production dependency actually fails
on the mutation before I added anything:
- Removing `_grok_spec()` from the registration loop →
`ORIGIN_SPEC_REGISTRY.diagnostics()` reports `missing_origin_spec` for
`grok-export`.
- Dropping Claude Code's `detector_tightness` below
`gemini_cli_session`'s (contradicting its real last-in-branch-order
position) →
`validate_dispatch_precedence(RECORD_DETECTOR_PROVIDER_ORDER)` reports
`dispatch_tightness_mismatch`.
- Deleting Codex's new `assembly_spec_path` declaration →
`validate_assembly_spec_parity(get_assembly_spec)` reports
`assembly_spec_parity_mismatch` for `codex-session` (this is the
mutation the new code in this PR is proven against).

## AC matrix (polylogue-2qx.1.2)

1. **Satisfied (pre-existing).** All eleven `Origin` tokens are declared
exactly once in `ORIGIN_SPECS`; `set(by_origin) == set(Origin)` is
asserted in
`test_origin_specs_cover_the_public_enum_and_admission_lifecycles`, and
`OriginSpecRegistry.diagnostics()` emits `missing_origin_spec` for any
omission (proven above).
2. **Satisfied (pre-existing + this PR).** Every executable origin
declares acquisition modes,
detector/parser/stream-parser/fixture/coverage/fidelity/reparse fields;
`claude-code-session` additionally declares 6 typed
`OriginArtifactRule`s for its
workflow/journal/transcript/sidecar/adopt-manifest/coordinator-stream
family. `grok-export` is `lifecycle="executable"` today (it shipped a
real parser via #3201/polylogue-611 after 2qx.1.1's pilot design assumed
it would stay reserved — documented at the top of `origin_specs.py`);
the `reserved` lifecycle contract itself is proven against a synthetic
variant since no current `Origin` is genuinely reserved.
`unknown-export` is `lifecycle="compatibility-only"` with explicit
fallback semantics; `beads-issue` is executable with `issue-jsonl`
acquisition and its own non-`accepted` completeness maturity caveat (no
harvested schema sample yet). This PR adds the Claude/Codex/AI-Studio
assembly hook declaration.
3. **Satisfied (pre-existing).**
`validate_dispatch_precedence`/`validate_stream_parser_parity`
parity-check tightness and stream-binding against
`sources/dispatch.py`'s real
`RECORD_DETECTOR_PROVIDER_ORDER`/`STREAM_RECORD_PROVIDERS`;
mutation-proven above (deleting/reordering a declaration fails).
4. **Satisfied (pre-existing) for `provider_completeness.py`; this PR
extends it to the assembly-hook axis.** `PACKAGE_MODE_SPECS` is a direct
tuple comprehension over `ORIGIN_SPECS`, parity-proven by
`test_provider_completeness_is_a_projection_of_every_origin_spec`.
`agent_integration/spec.py:ORIGIN_MEANINGS` is separately parity-guarded
against `Origin` at import time. **Deferred**:
`cli/shell_completion_values.py:_ORIGIN_DESCRIPTIONS` remains a stale,
un-parity-checked hand-maintained inventory — out of this lane's
ownership (`cli/**`), flagged as a residual above rather than a named
follow-up bead (small, mechanical, single-file fix for whichever lane
next touches CLI completions).
5. **Satisfied (pre-existing).** `aistudio-drive`'s
`provider_wires=(Provider.GEMINI, Provider.DRIVE)` with
`collision_policy` is registration-enforced
(`OriginSpecRegistry.register` raises `ValueError` if
`len(provider_wires) > 1` without a `collision_policy`, tested in
`test_origin_spec_rejects_missing_fixture_and_noninjective_collision_without_policy`);
`docs/provider-origin-identity.md` already documented the non-reversal
doctrine, and this PR adds the pointer from that doc to the enforcing
code.
6. **Misframed — recorded honestly rather than claimed satisfied.**
`polylogue-2qx.2` (Claude Code orchestration artifact admission) already
closed via PR #3088, and its own close reason states it shipped as a
`claude_workflow_materializer` convergence stage *without* the
OriginSpec migration this bead was meant to gate — the blocking edge was
explicitly force-closed as "over-blocking" because the merged
implementation disproves that ordering. So AC6 as written ("Claude/Codex
extension hooks are the only admission path used by 2qx.2...") cannot be
retroactively true for `2qx.2`. `j2zz` (Codex child-action lowering) and
`ih67` (Codex title enrichment) are still open; this PR's new
`assembly_spec_path`/`validate_assembly_spec_parity` gives them a real
typed admission point to consume going forward, but I did not modify
`assembly_codex.py`/`ih67`/`j2zz` scope — those remain their own beads'
work, not migrated by me here.

## Files touched

- `polylogue/sources/origin_specs.py`
- `tests/unit/sources/test_origin_specs.py`
- `docs/provider-origin-identity.md`

Ref polylogue-2qx.1.2

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Documentation**
- Added guidance on how origin metadata is declared, validated, and kept
aligned with runtime behavior.
- Documented checks for provider completeness and assembly-related
configuration.

- **Improvements**
- Added validation to detect mismatches between declared origin
capabilities and available assembly behavior.
- Added assembly configuration metadata for Claude Code, Codex, and AI
Studio origins.

- **Tests**
- Added coverage confirming assembly declarations and runtime parity
checks behave as expected.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
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