Skip to content

docs: roadmap consolidation, staleness refresh, settled design cases - #38

Open
t41372 wants to merge 3 commits into
mainfrom
docs/drop-roadmap-md
Open

docs: roadmap consolidation, staleness refresh, settled design cases#38
t41372 wants to merge 3 commits into
mainfrom
docs/drop-roadmap-md

Conversation

@t41372

@t41372 t41372 commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Bundles the docs work from the 2026-07-05 planning session (3 commits, squash-ready).

1. Roadmap consolidation

Delete docs/roadmap.md — issue #27 declared itself the canonical roadmap and the committed page had drifted (still listed the first PyPI release as pending, counted 6 compliance dimensions). Docs nav links the issue directly, same pattern as the external Releasing entry.

2. Staleness refresh (10 files)

  • installation.md / quickstart.md: install from PyPI (live since v0.1.1) instead of "not yet published" git installs; from-source install kept as a dev section.
  • Diarization made visible to app developers: params example + result loop (discover_and_use.md), streaming event table gains the speaker column, README supports() block. All examples verified against the real API (DIARIZE, RuntimeParams.diarization, Segment.speaker).
  • CHANGELOG: [Unreleased] filled with feat: add speaker diarization to the standard #31 / refactor: group modules into subpackages; de-jargon comments #32 / the roadmap move.
  • mkdocs nav: API-reference labels updated to post-restructure module paths (the old flat names no longer import).
  • spec: all CJK+English H1s (incl. Dependencies) get stable explicit {#id} anchors (attr_list), fixing all 42 broken internal cross-references; §10's defer list now points at the settled streaming-cadence design case; stale 设计笔记和决策/ paths now point at docs/design-notes/.
  • errors.md: StructuredError field names corrected to .param/.hint/.details; UnsafeAudioUrlError added to the hierarchy tree.
  • plugin_entrypoints.md: transcript captured live against std-faster-whisper — list, show (incl. the new config-schema section), compliance entrypoints, compliance run with the two-check disclosure — abridged with ... markers and labeled as such; stale future-tense compliance claim rewritten. ⚠ Captured with the fix/toolchain-honesty CLI: merge fix: make the toolchain honor its own promises #41 before this PR.

3. Settled design cases (docs/feat_plan/)

  • release-pipeline-redesign.md — v0.1.0 burn post-mortem + decided single-dispatch pipeline (guards → inline TestPyPI rehearsal → PyPI → GitHub release last → automated dev-bump PR). Design settled 2026-07-05.
  • streaming-cadence-and-tuning.mdoutput_latency capability node, target_latency_ms param, preferred_stream_chunk_ms hint; decisions D1–D7, engine facts verified against official upstream sources (incl. a survey correction: Voxtral's delay dial is 80 ms-stepped, not continuous; the Voxtral row links its HF card + paper). Settles open question 4 of issue Runtime compliance: end-to-end inference verification & robustness probes #33 (the issue itself stays open — it tracks the runtime e2e compliance implementation); Roadmap #27's design-case links become valid on merge.

Verified: mkdocs build exit 0 with zero link/anchor messages (the 297 pre-existing griffe docstring warnings are fixed separately on fix/griffe-docstring-format).

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added opt-in speaker diarization with speaker labels in batch results and streaming transcription events (including streaming speaker fields).
  • Documentation

    • Updated installation/quickstart and developer guides to reflect PyPI-based installs, diarization usage, streaming speaker fields, structured error field changes, and clarified diarization/streaming semantics.
    • Added new design docs for streaming cadence and target-latency tuning; refreshed release-process and spec guidance, and moved the roadmap to a GitHub issue.

The canonical roadmap now lives in issue #27 (which declared itself the
replacement). The committed page had already drifted (still listed the
first PyPI release as pending) — a second source of truth we don't want
to maintain. The docs nav now links to the issue directly, same as the
existing external Releasing entry.
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR documents diarization behavior, clarifies normative specification contracts, adds release-pipeline and streaming-tuning design cases, updates documentation navigation, and changes installation guidance to published package commands.

Changes

Documentation and design updates

Layer / File(s) Summary
Specification and navigation updates
docs/spec/specification.md, mkdocs.yml
Clarifies capability, runtime, diarization, streaming, event, audio, language, and error contracts, and updates documentation navigation and heading anchors.
Diarization documentation and examples
CHANGELOG.md, README.md, docs/for_app_dev/*, docs/for_asr_dev/plugin_entrypoints.md
Documents capability-gated diarization requests, speaker labels, structured error fields, and capability metadata.
Release pipeline redesign design doc
docs/feat_plan/release-pipeline-redesign.md
Defines an ordered workflow-dispatch release pipeline with TestPyPI rehearsal, verification, rollout phases, and implementation checks.
Streaming cadence and tuning design doc
docs/feat_plan/streaming-cadence-and-tuning.md
Defines streaming latency capabilities, runtime tuning parameters, chunk hints, compliance rules, and rollout considerations.
Installation and quickstart guidance
docs/installation.md, docs/quickstart.md
Updates package installation examples to use published packages and adds source-install guidance.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description does not follow the required template and is missing the specified sections and checklist. Rewrite it with the required 'What does this PR do?', 'Related Issues', and 'Checklist' sections, including the checklist items and issue references.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title clearly summarizes the docs roadmap, refresh, and design-case updates.
✨ 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 docs/drop-roadmap-md

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.

@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@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: 5

🤖 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 `@docs/feat_plan/release-pipeline-redesign.md`:
- Around line 72-94: The fenced flow block in the release pipeline redesign doc
is missing a language tag, which triggers Markdownlint MD040. Update the opening
fence for that block to use a text language tag so the existing content remains
unchanged while satisfying the lint rule; this applies to the flow diagram
section near the version/publish steps.

In `@docs/for_app_dev/discover_and_use.md`:
- Around line 80-90: Update the diarization docs in the example around
result.segments and the surrounding prose to account for the always_on
exception: `segment.speaker` should not be described as `None` whenever
diarization was not requested, since always_on engines may still populate
speaker labels. Adjust the inline comment and the explanatory paragraph to say
speaker labels are present when supported by the engine even without an explicit
request, while `None` still means not attributed. Use the `segment.speaker` and
`word.speaker` references in that section to keep the wording aligned.

In `@docs/for_app_dev/errors.md`:
- Around line 53-55: The error example for UnsupportedFeatureError currently
suggests that .details is commonly available, which is misleading. Update the
snippet around UnsupportedFeatureError to either use an example that explicitly
populates details through the relevant constructor path, or remove the
exc.details line and keep only the fields that are actually expected such as
exc.param and exc.hint.

In `@docs/for_app_dev/streaming.md`:
- Around line 58-61: Update the streaming documentation paragraph around
RuntimeParams and event.speaker to include the always_on exception: clarify that
event.speaker stays None when diarization was not requested or is unsupported,
except for always_on engines which may emit speaker labels without an explicit
diarization request. Keep the wording aligned with the existing
streaming.diarization and DIARIZE explanation.

In `@docs/installation.md`:
- Around line 43-50: The “Install from source” section is ambiguous because the
current `pip install "standard-asr @ git+..."` example installs a remote
snapshot rather than a local editable checkout. Update the `installation.md`
guidance to either describe the contributor workflow using a local clone with an
editable install via the project’s setup instructions, or rename the section to
clearly state that it is a remote Git install. Keep the wording aligned with the
section title and the install example so readers understand whether they are
working from a local checkout or a published repository snapshot.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9cc6c743-bb30-41b0-ac94-c5765389b8b3

📥 Commits

Reviewing files that changed from the base of the PR and between 2718fb3 and c5940d2.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • README.md
  • docs/feat_plan/release-pipeline-redesign.md
  • docs/feat_plan/streaming-cadence-and-tuning.md
  • docs/for_app_dev/discover_and_use.md
  • docs/for_app_dev/errors.md
  • docs/for_app_dev/streaming.md
  • docs/for_asr_dev/plugin_entrypoints.md
  • docs/installation.md
  • docs/quickstart.md
  • docs/roadmap.md
  • docs/spec/specification.md
  • mkdocs.yml
💤 Files with no reviewable changes (1)
  • docs/roadmap.md

Comment thread docs/feat_plan/release-pipeline-redesign.md Outdated
Comment thread docs/for_app_dev/discover_and_use.md Outdated
Comment thread docs/for_app_dev/errors.md Outdated
Comment thread docs/for_app_dev/streaming.md Outdated
Comment thread docs/installation.md
@t41372
t41372 force-pushed the docs/drop-roadmap-md branch from c5940d2 to 0bdf982 Compare July 6, 2026 10:57
@t41372
t41372 force-pushed the docs/drop-roadmap-md branch from 0bdf982 to 3b4fc54 Compare July 16, 2026 02:32

@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: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/spec/specification.md (1)

1253-1262: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Separate global streaming capabilities from mode-scoped capabilities.

The introduction says all listed nodes live under capabilities.streaming.*, but streaming_input and streaming_output are defined elsewhere as top-level global capabilities. Clarify the table so consumers do not serialize or query these axes as capabilities.streaming.streaming_input and capabilities.streaming.streaming_output.

🤖 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 `@docs/spec/specification.md` around lines 1253 - 1262, 更新该 capability
表及其引导文字,明确区分顶层全局的 streaming_input 和 streaming_output 与 capabilities.streaming.*
下的模式级节点;将前两项标注为顶层路径,避免消费者将其序列化或查询为
capabilities.streaming.streaming_input/streaming_output,并保留其余 streaming.* 节点不变。
🤖 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 `@docs/feat_plan/release-pipeline-redesign.md`:
- Around line 67-75: Update the release-pipeline heading and surrounding summary
to describe a single release pipeline rather than “one human action,” while
preserving the documented merge, workflow dispatch, and dev-bump PR steps.
- Around line 90-103: Update the release-pipeline description around “create
GitHub Release” and “Why publish-PyPI-before-GitHub-Release” to avoid claiming
tag and release creation are atomic. Document that gh release create may leave a
tag when release creation fails, and add an explicit retry/reconciliation path
for the tag-created/release-failed state.

In `@docs/feat_plan/streaming-cadence-and-tuning.md`:
- Line 140: Rewrite the sentence beginning with “#33's probe set” so it refers
to “the probe set for issue `#33`” or equivalent, ensuring the line no longer
begins with a hash that Markdownlint interprets as a heading.
- Around line 96-103: Revise the StreamingCapabilities.output_latency
declaration to represent non-contiguous supported values, including 80–1200 ms
in 80 ms increments and the standalone 2400 ms value. Extend the constraint
model with an explicit discrete-values or exception mechanism, and ensure
supports(), canonical JSON, and wire serialization preserve the exact set
without advertising unsupported intermediate values; do not rely on snapping.

In `@docs/spec/specification.md`:
- Around line 950-958: The error-event contract must not permit logging raw
exception text. Update the adjacent error-logging rule to require redacted,
allowlisted structured fields only, excluding paths, URLs, credentials, and
other untrusted exception details, while preserving the client payload’s removal
of human-readable error details.
- Around line 683-691: Clarify the speaker inheritance model in the
specification so Word.speaker=None cannot simultaneously mean inheritance and
explicit unknown attribution. Define a distinct representation for an explicitly
unknown word speaker while preserving None as the inheritance marker, and update
the related None semantics and segment-speaker synthesis rules to use that
representation consistently.
- Line 135: Update Example E to align with the v1 streaming contract: describe
incompatible wire sample rates as rejected by
EngineBase.ensure_stream_format_supported when standard-layer streaming
resampling is unavailable, rather than requiring 16 kHz→24 kHz resampling.
Alternatively, explicitly label the resampling and missing-[audio] failure
behavior as future standard-layer streaming behavior, while preserving it for
the batch transcribe path.

---

Outside diff comments:
In `@docs/spec/specification.md`:
- Around line 1253-1262: 更新该 capability 表及其引导文字,明确区分顶层全局的 streaming_input 和
streaming_output 与 capabilities.streaming.* 下的模式级节点;将前两项标注为顶层路径,避免消费者将其序列化或查询为
capabilities.streaming.streaming_input/streaming_output,并保留其余 streaming.* 节点不变。
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 64de8bf0-5e40-4752-bacf-660666b3dc49

📥 Commits

Reviewing files that changed from the base of the PR and between 0bdf982 and 3b4fc54.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • README.md
  • docs/feat_plan/release-pipeline-redesign.md
  • docs/feat_plan/streaming-cadence-and-tuning.md
  • docs/for_app_dev/discover_and_use.md
  • docs/for_app_dev/errors.md
  • docs/for_app_dev/streaming.md
  • docs/for_asr_dev/plugin_entrypoints.md
  • docs/installation.md
  • docs/quickstart.md
  • docs/roadmap.md
  • docs/spec/specification.md
  • mkdocs.yml
💤 Files with no reviewable changes (1)
  • docs/roadmap.md
🚧 Files skipped from review as they are similar to previous changes (9)
  • README.md
  • CHANGELOG.md
  • docs/for_app_dev/errors.md
  • docs/quickstart.md
  • docs/for_app_dev/discover_and_use.md
  • docs/for_app_dev/streaming.md
  • mkdocs.yml
  • docs/for_asr_dev/plugin_entrypoints.md
  • docs/installation.md

Comment on lines +67 to +75
**One pipeline, one human action, fully automatic, ordered by
irreversibility.** The GitHub Release is demoted from *trigger* to *final
output*; the TestPyPI rehearsal is promoted from *separate manual dry-run* to
*inline stage of every release*.

```text
[human] merge chore(release): vX.Y.Z PR (version + CHANGELOG entry)
[human] press workflow_dispatch ← the only trigger; version read
│ from pyproject.toml on main

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Reconcile the “one human action” claim with the documented flow.

This section shows at least two human actions—merging the release PR and dispatching the workflow—and step 8 later requires merging the dev-bump PR. Replace “one human action” with a precise description such as “one release pipeline” to avoid contradicting the runbook.

🤖 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 `@docs/feat_plan/release-pipeline-redesign.md` around lines 67 - 75, Update the
release-pipeline heading and surrounding summary to describe a single release
pipeline rather than “one human action,” while preserving the documented merge,
workflow dispatch, and dev-bump PR steps.

Comment on lines +90 to +103
├─ 7. create GitHub Release: gh release create vX.Y.Z --target <sha>
│ (creates tag + release atomically; notes = the CHANGELOG section)
└─ 8. open follow-up PR: bump pyproject to X.Y.(Z+1).dev0 + `uv lock`
(maintainer merges; CI validates it like any PR)
```

### 2.1 Why publish-PyPI-before-GitHub-Release

The GitHub Release is the only step that permanently burns a tag name (once
immutable releases return). Placed last, its failure-downstream is empty:
`gh release create` failing means PyPI is live and the fix is a retry of one
idempotent-ish step — nothing is burned, nothing is inconsistent for longer
than the retry. It also makes the announcement follow the fact: no window
where GitHub says "released" but `pip install` fails.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and nearby references
git ls-files docs/feat_plan/release-pipeline-redesign.md
printf '\n--- file excerpt ---\n'
sed -n '1,220p' docs/feat_plan/release-pipeline-redesign.md

printf '\n--- search for recovery / retry / reconciliation / tag-created / release-failed ---\n'
rg -n "retry|reconcil|tag-created|release-failed|gh release create|immutable releases|burns a tag|PyPI-before-GitHub-Release|follow-up PR|release" docs/feat_plan/release-pipeline-redesign.md

Repository: standard-voice/standard_asr

Length of output: 17018


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the GitHub CLI docs wording around tag creation and release creation.
python3 - <<'PY'
import urllib.request, re
url = "https://cli.github.com/manual/gh_release_create"
html = urllib.request.urlopen(url, timeout=20).read().decode("utf-8", "replace")
for needle in [
    "automatically create",
    "create a new release",
    "create a tag",
    "If the tag does not exist",
    "the tag will be created",
]:
    idx = html.lower().find(needle.lower())
    print(f"\n=== {needle} ===")
    if idx == -1:
        print("not found")
    else:
        start = max(0, idx - 300)
        end = min(len(html), idx + 700)
        print(re.sub(r"<[^>]+>", " ", html[start:end]))
PY

Repository: standard-voice/standard_asr

Length of output: 2759


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for any mention of explicit recovery for a tag-created/release-failed state elsewhere in the repo.
rg -n "tag.*release|release.*tag|reconcile|recovery|retry|idempotent|burns a tag|atomic|GitHub Release|gh release create" .

Repository: standard-voice/standard_asr

Length of output: 7959


Do not call tag creation and release creation atomic. gh release create may leave a tag behind if release creation fails, so the zero-burn recovery story needs an explicit retry/reconciliation path for a tag-created/release-failed state.

🤖 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 `@docs/feat_plan/release-pipeline-redesign.md` around lines 90 - 103, Update
the release-pipeline description around “create GitHub Release” and “Why
publish-PyPI-before-GitHub-Release” to avoid claiming tag and release creation
are atomic. Document that gh release create may leave a tag when release
creation fails, and add an explicit retry/reconciliation path for the
tag-created/release-failed state.

Comment on lines +96 to +103
**D1 — Declaration: `StreamingCapabilities.output_latency` node.**
`mode: "fixed" | "configurable" | "tiered" | "none"` (default `none` — degrade
to unknown, never false precision), with constraint payload:
`points_ms: list[int]` (tiered — non-empty, sorted), `range_ms: {min, max,
step?}` (configurable — `step` optional, for the verified 80 ms-stepped dials),
and `typical_ms: int | None` (all modes except `none`; the default/expected
operating point). Lives in **capabilities** because it gates the tuning param
(D3) — and it flows into `supports()`, canonical JSON, and the wire for free.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Represent non-contiguous latency values explicitly.

The documented Voxtral range supports 80–1200 ms in 80 ms steps plus a standalone 2400 ms value. range_ms: {min, max, step} cannot represent that set without advertising unsupported values or omitting 2400 ms. Add an explicit discrete-values/exception mechanism, or revise the declaration model before implementation; snapping does not fix an inaccurate capability declaration.

Also applies to: 112-120

🤖 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 `@docs/feat_plan/streaming-cadence-and-tuning.md` around lines 96 - 103, Revise
the StreamingCapabilities.output_latency declaration to represent non-contiguous
supported values, including 80–1200 ms in 80 ms increments and the standalone
2400 ms value. Extend the constraint model with an explicit discrete-values or
exception mechanism, and ensure supports(), canonical JSON, and wire
serialization preserve the exact set without advertising unsupported
intermediate values; do not rely on snapping.

Comment thread docs/feat_plan/streaming-cadence-and-tuning.md
Comment thread docs/spec/specification.md
Comment on lines +683 to +691
说话人分离("谁说了什么")经 [§Runtime 参数 3.4](#runtime-parameters) 的 `diarization` marker 请求,能力声明于 `capabilities.<mode>.diarization`([§能力系统 3.2](#capabilities))。结果语义(normative):

- **`Segment.speaker`(权威)+ `Word.speaker`(可选细化)。继承规则**:`Word.speaker` 为 `None` 时继承所在段的 `Segment.speaker`;非 `None` 时在词级**覆盖**段级值(混合说话人段的词级细化)。**不**加顶层 `speakers[]` roster(YAGNI,需要时 additive)。
- **`None` 语义(TR.1 重申)**:diarization **激活**时 `speaker=None` = "引擎无法判定该段/词的说话人"(显式的「不知道」);未请求时 = 不适用。应用判「引擎是否支持/做了 diarization」MUST 看 capability,MUST NOT 看字段 null(TR.1 null 规则;always-on 豁免见下,使字段 null 判定更加不可靠)。
- **段级 speaker 合成(标准层,单一钉死规则)**:当 `Segment.speaker is None` 而其 `words` 携带非 `None` speaker 时,标准层合成段级 speaker。规则**唯一且钉死**:**按词数多数决;平手取并列 speaker 中最早出现(最低下标)的词的 speaker;`speaker=None` 的词不投票;无携带 speaker 的词则保持 `None`**。该合成以同一实现跑在两条路径上:batch 在 `EngineBase.transcribe` 的结果后处理(作用于顶层 `segments[]` **与**每个 `channels[i].segments`——TR.4 两视图必须一致),streaming 在标准归约器(`session.result()`)。适配器 MAY 自行预填 `Segment.speaker`(原生段级引擎如此);标准层仅在段级为 `None` 时合成,且不论 diarization 是否被请求(always-on 数据同样受益)。钉死单一规则的理由:同一引擎+同一音频 MUST 经任何路径/实现得到相同的 `Segment.speaker`——两条相近规则(majority vs first)会静默分叉,破坏本特性存在的可移植性。
- **标签有效性(构造期强制)**:`speaker` 标签 MUST 非空、非纯空白、且无首尾空白——`Segment` / `Word` / `TranscriptionEvent` 构造期拒绝(`""` 是既非 `None` 又非真实标签的第三种未定义状态;`"A "` 与 `"A"` 是两个不同字串 = 两个不同说话人,一个适配器 off-by-one 即静默打破一致性;**拒绝而非归一化**,与 `phrase_hints` 词条的 fail-loud 立场同款)。`None` 合法。标准**不**规定标签格式(`"speaker_0"`、`"A"`、known-speaker 场景的真实姓名皆可)。
- **result 内一致性(适配器义务)**:同一结果内同一字串 = 同一说话人、不同说话人 = 不同字串。一致性范围横跨**所有**标签载体——顶层 `segments[]`、`words[]`、以及 `channels[]` 子结果:逐通道独立 diarize 的引擎(两个通道都把各自第一个说话人标 `"0"`)MUST 由适配器在组装前重标进同一个 result 级命名空间,否则同一字串静默指代两个人。非空性之外的一致性无法构造期强制,合规套件亦**不**校验——套件只提供下方「合规范围」条的负向 presence 交叉检查(`stream_exceeds_diarization` / `result_exceeds_diarization`:只比对「是否携带 speaker」与声明能力,**绝不**比对标签字串一致性);一致性在无多说话人 fixtures 时不可验证,标准层不假装强制。与 TR.2 排序(同为引擎义务、构造期不强制、套件不校验,但渲染器在自身边界防御性重排兜底)不同,此项是**纯适配器义务**——连渲染器都不代为修复,没有任何标准层安全网。
- 标签跨会话**不**稳定、**不**关联身份、**不**跨引擎可比。
- **always-on 引擎的具名豁免(normative)**:声明 `always_on` 为 supported 的引擎 MAY 在 diarization **未被请求**时填充 `speaker`,这**不是**违规——它是对「未请求的数据 MUST NOT 回填」立场(TR.3 对 word timestamps 的禁令)的**有意、具名**豁免:架构上不可关闭的 joint 模型无法不产出 speaker,强制剥离 = 主动丢弃高价值数据 + 在静默方向(漏剥没人知道)留 bug 窗口。此类引擎 MAY 额外发一条 `info` diagnostic(`code="unrequested_speaker_labels"`)。想要无 speaker 标签的应用(隐私场景)在 always-on 引擎上无标准关闭手段,自行在客户端剥除。可关闭的引擎不享受此豁免(能关 MUST 关,[§能力系统 3.2](#能力系统-capabilities--normative))。
- **always-on 引擎的具名豁免(normative)**:声明 `always_on` 为 supported 的引擎 MAY 在 diarization **未被请求**时填充 `speaker`,这**不是**违规——它是对「未请求的数据 MUST NOT 回填」立场(TR.3 对 word timestamps 的禁令)的**有意、具名**豁免:架构上不可关闭的 joint 模型无法不产出 speaker,强制剥离 = 主动丢弃高价值数据 + 在静默方向(漏剥没人知道)留 bug 窗口。此类引擎 MAY 额外发一条 `info` diagnostic(`code="unrequested_speaker_labels"`)。想要无 speaker 标签的应用(隐私场景)在 always-on 引擎上无标准关闭手段,自行在客户端剥除。可关闭的引擎不享受此豁免(能关 MUST 关,[§能力系统 3.2](#capabilities))。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Disambiguate Word.speaker=None.

Line 685 defines None as “inherit Segment.speaker,” while Line 686 defines None as an explicit unknown speaker. A word with an unknown speaker inside a segment labeled "A" is therefore indistinguishable from a word spoken by "A". Define one unambiguous representation for inheritance versus unknown attribution.

🤖 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 `@docs/spec/specification.md` around lines 683 - 691, Clarify the speaker
inheritance model in the specification so Word.speaker=None cannot
simultaneously mean inheritance and explicit unknown attribution. Define a
distinct representation for an explicitly unknown word speaker while preserving
None as the inheritance marker, and update the related None semantics and
segment-speaker synthesis rules to use that representation consistently.

Comment on lines +950 to +958
| `words` | `list[Word] \| None` | 词级细节(可选,与 [§结果模型](#transcription-result) 共享同一 `Word` 定义) |
| `speaker` | `str \| None` | 段级说话人标签。继承规则与 `Segment.speaker` 相同(TR.5):`event.words[i].speaker` 非 `None` 时在词级覆盖;标签有效性规则同 TR.5(构造期拒绝空/纯空白/带首尾空白)。冻结区域保护见 §4.2 |
| `start` / `end` | `float \| None` | 段的起止时间(秒,原点 = 会话第一个音频采样)|
| `audio_processed_until` | `float \| None` | 引擎已处理到的音频时间点(§4.4) |
| `old_ids` / `new_ids` | `list[str]` | 仅 `supersede` 事件使用(§5) |
| `detected_language` | `str \| None` | 引擎检测到的语言(BCP-47,非 `auto`;与结果模型同规则校验)。是 §6.3 重连连续性承诺的载体——重连前后 MUST 保持一致 |
| `code` / `recoverable` / `retriable_after` | | 仅 `error` 事件使用(§7.2) |
| `reconnect` / `gap_start` / `gap_end` | | 仅 `progress` 的重连通知使用(§7.3) |
| `extra` | `dict[str, Any]` | 引擎特定/实验数据槽位(默认 `{}`)。语义与 [结果模型](#结果模型-transcription-result--normative) 的 `extra` 一致:**引擎特定、不可移植**,可移植应用代码 MUST NOT 依赖其中的键。提供给适配器透传原生协议的额外信息(如 token 级置信度、自定义元数据),而无需扩展封闭的标准字段集 |
| `extra` | `dict[str, Any]` | 引擎特定/实验数据槽位(默认 `{}`)。语义与 [结果模型](#transcription-result) 的 `extra` 一致:**引擎特定、不可移植**,可移植应用代码 MUST NOT 依赖其中的键。提供给适配器透传原生协议的额外信息(如 token 级置信度、自定义元数据),而无需扩展封闭的标准字段集 |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not prescribe logging raw exception details.

The revised error-event contract removes human-readable details from the client payload, but the adjacent rule still permits logging raw str(exc) values that may contain paths, URLs, or credential fragments. This conflicts with IC.3’s requirement that plaintext secrets never be logged. Require redacted, allowlisted structured logging instead.

🤖 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 `@docs/spec/specification.md` around lines 950 - 958, The error-event contract
must not permit logging raw exception text. Update the adjacent error-logging
rule to require redacted, allowlisted structured fields only, excluding paths,
URLs, credentials, and other untrusted exception details, while preserving the
client payload’s removal of human-readable error details.

t41372 added 2 commits July 15, 2026 23:18
- installation/quickstart: install from PyPI (live since v0.1.1), git install
  demoted to a from-source section
- surface diarization in every app-developer path (params example, result
  loop, streaming event table, README supports() block)
- CHANGELOG: fill [Unreleased] with #31/#32 and the roadmap move
- mkdocs nav: API-reference labels updated to the post-restructure module
  paths; enable attr_list
- spec: stable explicit heading ids replace 42 broken CJK-slug anchor links;
  design-note references point at the renamed docs/design-notes/
- errors.md: correct StructuredError field names (.param/.hint/.details);
  add UnsafeAudioUrlError to the hierarchy tree
- plugin_entrypoints: transcript captured live against std-faster-whisper --
  list, show (incl. the config-schema section), compliance entrypoints, and
  compliance run with the two-check disclosure -- abridged with elision
  markers and labeled as such. Captured with the fix/toolchain-honesty CLI, so
  that branch must merge first. Stale future-tense checker claim rewritten.
- errors.md: InvalidSessionUseError example corrected (end_audio is idempotent;
  double-feed is the real programming error)
- streaming.md: progress/error rows no longer claim segment_id is always None
  (spec 4.1 allows either to carry the segment id)
…reaming cadence

Both rebuild documents lost before ever being committed, then settle them:

- release-pipeline-redesign: v0.1.0 burn post-mortem, the two root causes
  (never-rehearsed release path; validation after the irreversible act), and
  the decided single-dispatch pipeline — guards -> TestPyPI (inline rehearsal)
  -> PyPI -> GitHub release last -> automated dev-bump PR.
- streaming-cadence-and-tuning: output_latency capability node,
  target_latency_ms runtime param, preferred_stream_chunk_ms hint; decisions
  D1-D7 with engine facts verified against official upstream sources.

Spec 10's defer list now points at the settled streaming-cadence case (the
spec records that a decided design exists instead of deferring silently; the
full normative text lands with the implementation). The Voxtral row links its
verified sources (HF card + paper) and 3 notes how to re-verify the rest;
the RELEASING.md no-op-gate claim is scoped to what the runbook actually says
(an optional, currently-unprotected gate); a superseded roadmap-draft
reference in D2 is labeled as such.
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