Skip to content

Board: freeze provider-neutral observation contract - #956

Merged
jeffhuber merged 4 commits into
mainfrom
codex/946-board-observation-contract
Sep 16, 2026
Merged

jeffhuber merged 4 commits into
mainfrom
codex/946-board-observation-contract

Conversation

@jeffhuber

@jeffhuber jeffhuber commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Board needs one closed local read model for session and work activity before presentation or producer work can safely begin. This defines code_mower.boardObservation.v1, with exact session/work/run and repository/worktree binding, the existing remote-session public lifecycle projection, per-source freshness and coverage, separate requested and observed evidence, deterministic next-actor routing, and explicit unavailable measurements.

The offline fixtures cover assigned through merged work, waiting and failure paths, stale and unavailable sources, unlinked process observations, and a strictly covered no-work state. Adversarial cases fail closed on enum/field drift, cross-session or worktree joins, stale live claims, timestamp and head mismatches, unauthorized display labels, missing measurements serialized as zero, and oversized identifiers.

The branch is refreshed onto v1.4.1 main d52bc68396397edfeae782d08a768386f89a00f2. Its session identity contract now uses the same 32-character hexadecimal identity accepted by the current-session resolver from #935, including identifiers beginning with a digit. The current committed package manifest includes the new module and schema.

This PR adds no Board UI, lifecycle producer, Slack mapping, cloud event or field, network action, provider mutation, or lease mutation. The later #949 producer integration must reuse the accepted #935 resolver; this PR only freezes the provider-neutral local observation contract and offline truth fixtures.

Validation at exact head 28356d970f391c124927ff4fa64e6a3ca6ee98a2:

  • 230 focused and adjacent Board, session-current, remote-session, Slack-contract, lineage, packaging, and install-taxonomy tests passed
  • 3 targeted release privacy, committed-manifest regeneration, and release-readiness tests passed
  • repository-wide Ruff, privacy scan, Python compilation, and diff whitespace checks passed
  • wheel and sdist builds passed and include board_observation.py plus its schema

The earlier independent audit and CI evidence belong only to historical head 0feb5f98374622956bbc71158c6a1147a0df253c. This refreshed head still requires a new independent exact-head audit, normal CI, and authoritative code-mower/gate before merge.

Closes #946

@jeffhuber jeffhuber added the builder:codex Code Mower generated label label Sep 12, 2026
@jeffhuber

Copy link
Copy Markdown
Contributor Author

Claude audit (merge-authority lane)

Head SHA: 0feb5f98374622956bbc71158c6a1147a0df253c
Findings: P0=0, P1=0, P2=0, P3=0 (blocker policy: any P0/P1/P2 -> BLOCKED)

Claude Audit: PASS

Summary:

New, additive, self-contained board_observation contract module with a closed JSON-Schema, extensive validation logic, and 17 valid + 13 adversarial fixtures exercising the invariants (timestamp ordering, identity binding, freshness/staleness, primary-route determinism, measurement null-vs-zero semantics, privacy scrubbing of display labels). package_manifest.py change is purely additive. No correctness, security, or contract-violation blockers found.

Findings: none.

@jeffhuber
jeffhuber force-pushed the codex/946-board-observation-contract branch from 0feb5f9 to 28356d9 Compare September 16, 2026 11:26
@jeffhuber

Copy link
Copy Markdown
Contributor Author

Code Mower Codex writer refresh

Rebased the existing branch onto exact v1.4.1 main d52bc68396397edfeae782d08a768386f89a00f2 without textual conflicts and pushed with force-with-lease.

New exact head: 28356d970f391c124927ff4fa64e6a3ca6ee98a2

Compatibility updates after the rebase:

  • regenerated the committed package manifest so the Board observation module and schema ship in the current package inventory;
  • aligned observation session_id values with the 32-character hexadecimal identity accepted by the merged Sessions: discover the current local brief and lease from a checkout #935 current-session resolver, including digit-leading IDs;
  • replaced fixture-only session IDs and retained a valid cross-session mismatch case;
  • added a regression that checks accepted and refused identities against the current resolver.

Writer validation on this head:

  • 230 focused and adjacent tests passed;
  • 3 targeted release privacy/manifest/readiness tests passed;
  • repository Ruff, privacy scan, compilation, and diff checks passed;
  • wheel and sdist builds passed with both new contract files included.

The PR remains draft. The historical audit does not apply to this head; fresh independent exact-head review, completing CI, and an authoritative gate pass remain required.

@jeffhuber

Copy link
Copy Markdown
Contributor Author

Claude audit (merge-authority lane)

Head SHA: 28356d970f391c124927ff4fa64e6a3ca6ee98a2
Findings: P0=0, P1=0, P2=0, P3=1 (blocker policy: any P0/P1/P2 -> BLOCKED)

Claude Audit: PASS

Summary:

New provider-neutral Board observation contract (board_observation.py + schema + fixtures + tests) is well-scoped, fails closed on malformed/adversarial input, and is backed by an extensive fixture-driven test suite that exercises the validation branches (identity binding, timestamp ordering, stale-live claims, measurement coverage, display-label privacy checks). No P0/P1/P2 correctness, security, or data-loss issues found.

Findings:

  • [P3] decode() collapses specific validate() diagnostics to generic invalid_contract -- src/code_mower/board_observation.py:436
    Finding ID: claude:bc1a8fef17c9e277c7f5
    BoardObservationError subclasses ValueError, and decode()'s except (ValueError, TypeError, RecursionError, UnicodeError) clause re-raises any validate()-raised error (e.g. identity_mismatch, stale_live_claim, privacy_violation) as a generic invalid_contract. This never lets bad data through, but callers going through the bytes-decode entry point lose the specific rejection reason that validate() computed, which may hinder triage/operability. If intentional (e.g. to avoid leaking validation internals to untrusted byte producers), consider a short comment noting that; otherwise narrow the except clause or re-raise BoardObservationError as-is.

@github-actions

Copy link
Copy Markdown

Code Mower notice: previously audited head 0feb5f983746 is no longer an ancestor of current head 28356d970f39; commits may have been dropped. Only current-head audit verdicts count.

@jeffhuber
jeffhuber marked this pull request as ready for review September 16, 2026 11:33
@jeffhuber
jeffhuber merged commit bafbac4 into main Sep 16, 2026
16 checks passed
@jeffhuber
jeffhuber deleted the codex/946-board-observation-contract branch September 16, 2026 11:33
jeffhuber added a commit that referenced this pull request Sep 17, 2026
…de artifacts; refresh roadmap facts

- board_service_mode.py (docs/pypi-release.md section 15) now requires
  payload["schema"] == "code_mower.boardServiceStatus.v1" and requires the
  sole services row to be a dict before calling .get on it. Unrelated or
  changed JSON, a wrong/missing schema, or a non-dict row now fails closed
  instead of being silently accepted or raising AttributeError.
  tests/test_release_hygiene.py's
  test_runbook_board_service_mode_fails_closed_on_unclassifiable_status
  gained wrong_schema, missing_schema, non_dict_row, and non_dict_payload
  regression cases (and the passing cases now carry the schema field the
  real CLI always emits).
- Step 17's upgrade rehearsal (docs/pypi-release.md) now targets headless
  Linux: file hashing uses a small `$RELEASE_PYTHON`/hashlib script instead
  of the macOS-only `shasum -a 256`. The v1.4.2 upgrade installs the exact
  wheel step 9 already downloaded and digest-verified
  (`$PYPI_DOWNLOAD_DIR/code_mower-1.4.2-py3-none-any.whl`), never a fresh
  `code-mower==1.4.2` index re-resolution that could silently install a
  different build than the one this runbook verified. The v1.4.1 side is
  now explicitly downloaded and digest-bound the same way before install,
  instead of installing whatever the index resolves at rehearsal time.
  tests/test_release_v142.py's UpgradeRehearsalTests updated to match.
- Fixed the awkward inline-code line break in docs/v142-qualification.md
  ("serving == installed ==" split across a line from "1.4.2").
- Refreshed docs/current-state-and-roadmap.md's Board section: #956/#957
  are merged, not drafts behind main; #961, #999, #1000, #1002, and #951's
  #1003 are accepted on `main`; #951 itself stays open only for its bounded
  hosted Devin canary, tracked separately from its merged code evidence.
  The near-term roadmap list's Board bullet was updated the same way.

Verification (fresh venv, unittest's own exit code, no pipeline masking):
- `python -m unittest tests.test_release_v142` -> 16/16 passed, exit 0.
- `python -m unittest discover -s tests -p "test_release_v14*.py"` -> exit 1
  overall, exactly one failure:
  `test_release_v141.InstalledPromptPackTests.test_literal_starter_and_explicit_config_walkthrough`
  (the byte-identical, untouched historical file's own copy of the sandbox
  `/tmp` symlink issue, confirmed via `git diff HEAD:<path> <path>` -> no
  output for that file, docs/v141-release-notes.md,
  docs/v141-qualification.md, and docs/v140-release-runbook.md).
- `python -m unittest discover -s tests -p "test_release_hygiene.py"` ->
  361/361 passed, exit 0.
- `ruff check .`, `scripts/privacy_scan.py`, `scripts/guard_package_workflows.py`,
  and `python -m code_mower.migration release-readiness --json`
  (status: pass) all clean on this commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

builder:codex Code Mower generated label claude-audit-done

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Board: freeze the provider-neutral observation contract and truth fixtures

1 participant