Skip to content

Circadian WP1: human posture twin, Bend gate laws, circadiand - #244

Open
kvnloo wants to merge 2 commits into
masterfrom
feat/circadian-wp1
Open

kvnloo wants to merge 2 commits into
masterfrom
feat/circadian-wp1

Conversation

@kvnloo

@kvnloo kvnloo commented Oct 26, 2026

Copy link
Copy Markdown
Owner

What

CIRCADIAN-SPEC WP1 (Python twin + host service) with the Revisions applied.

  • src/z0int/human_posture.py: pure evaluate_human_state, policy, route, gate. Fallback ladder wearable (measured, only when fresh) -> activity (proxy) -> clock (default); a no-data night is never scored (R3). Real-time sleep rule and owner-day rollover after a night with no gap (R2). Phases use absolute instants, so a DST night is continuous (C17). Readiness always the normal row (R5). Canonical JSON (C4). Defaults are SYNTHETIC; real anchors live only in private host config (R4).
  • bend/circadian/: the notice gate in Bend 2 with 8 laws (C2, C3, C5 + R2 opt-in, C10, C14, day decisions). PROOF.bend is generated full case analysis; bend PROOF.bend -> ALL PROOFS CHECK. The compiled truth table equals the Python gate on all 1024 inputs.
  • src/z0int/circadian/: read-only adapters (ActivityWatch, phone dumpsys usagestats screen on/off, NOOP DB copy), circadiand tick loop + loopback GET /posture, circadian CLI (route, done, undone, release, replay, show). Only quiet-phase holding is enforced; day batching and capture are shadow (C12, R2b). Owner days in shadowDates enforce nothing.
  • deploy/circadian/: user unit (MemoryMax 128M, CPUQuota 10%), installer that keeps the previous release and writes circadian-rollback, and the fail-open guard for host notify scripts.

Tests

uv run --no-project --with pytest --with hypothesis python -m pytest -q tests/test_human_posture.py tests/test_circadian_service.py
196 passed
cd bend/circadian && bend PROOF.bend      # ALL PROOFS CHECK
python3 scripts/circadian_mutation.py      # AST mutation score (target >= 85), result posted below

The SYNTHETIC golden fixtures are shared with the dash TypeScript twin (kvnloo/dash turbo/circadian-wp1); both compare canonical JSON byte for byte. A 30-day shadow replay ran on the host before enforcement (R11); its receipt stays private.

🤖 Generated with Claude Code

CIRCADIAN-SPEC WP1 with the Revisions applied (R2, R3, R5, R7, R11):

- z0int.human_posture: pure evaluate_human_state / policy / route / gate.
  Owner-day anchors from activity (proxy), the wearable (measured, only when
  fresh) or the clock (default). Real-time sleep rule and owner-day rollover
  after a night with no gap. Phases follow absolute instants, so a DST night
  is continuous (C17). Readiness always selects the normal row (R5).
  Canonical JSON (C4). Defaults are SYNTHETIC; real anchors are private host
  config only (R4).
- bend/circadian: the notice gate in Bend 2 with 8 laws (C2, C3, C5+R2,
  C10, C14, day decisions) proven by generated case analysis; the compiled
  truth table equals the Python gate on all 1024 inputs.
- z0int.circadian: read-only adapters (ActivityWatch, phone usagestats,
  NOOP DB copy), circadiand tick loop + loopback GET /posture, the
  `circadian` CLI (route/done/undone/release/replay/show), and the R2
  release rule. Only quiet-phase holding is enforced; day batching and
  capture are shadow (C12, R2b). Owner days in shadowDates enforce nothing.
- deploy/circadian: user unit, installer with previous-release rollback and
  a fail-open guard for host notify scripts.
- SYNTHETIC golden fixtures shared with the dash TypeScript twin, red/green
  law tests, a hypothesis property test, an AST purity lint and an AST
  mutation runner (target >= 85).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the area:verify Tests, mutation, evidence label Oct 26, 2026
…313/313 killed

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

kvnloo commented Oct 26, 2026

Copy link
Copy Markdown
Owner Author

Mutation receipt (scripts/circadian_mutation.py --jobs 4, Bend parity included): 313 mutants of src/z0int/human_posture.py, 313 killed, score 100.0 (threshold 85). The baseline passes in the scratch copy (the runner now refuses to score if it does not). Receipt: results/circadian_mutation_receipt.json.

🤖 Generated with Claude Code

kvnloo commented Oct 27, 2026

Copy link
Copy Markdown
Owner Author

N27-REV-Z0I-244

Review scope: kvnloo/z0intelligence PR #244, head 8128917e596ae090c75c366849abbc6e7595da3f, base 52aed5bb9a41b4986fb77c3017c03d3b2a4573e0. Read root AGENTS.md, README.md, docs/ONBOARDING.md, all 24 added files (including generated proof/fixtures), the complete PR diff, the base comparison (all 24 files are additions), PR discussion and exact-head workflow results. CONTRIBUTING.md is absent on this base. Acceptance-source limit: PR body/timeline do not identify a linked GitHub work-item issue; the cited .design/circadian/CIRCADIAN-SPEC.md is explicitly private and unavailable in this repo. Statuses below evaluate the PR's stated WP1/C/R requirements, not undisclosed acceptance clauses. MET means implemented in source, not independently executed.

Acceptance map (source:line)

  • MET — C2/C10 quiet phase and owner disengagement: src/z0int/human_posture.py:314-333,415-439; src/z0int/circadian/service.py:218-243,355-367. Quiet reports/decisions route to digest; done/undo entry points exist; targeted tests/test_human_posture.py:68-80,117-123, tests/test_circadian_service.py:116-122.
  • MET — C3 finite gate capacity / day shadow: src/z0int/human_posture.py:359-379,415-439 with tests/test_human_posture.py:83-95. src/z0int/circadian/service.py:223-240 deliberately enforces only quiet-phase holds; day budgets remain shadow, as declared.
  • MET — C5/R2 critical downgrade and opt-in: src/z0int/human_posture.py:47,415-423,449-460; tests/test_human_posture.py:98-108. An unapproved critical becomes a report; nighttime approved/irreversible delivery requires opt-in.
  • MET — C4 deterministic/canonical Python surface: src/z0int/human_posture.py:98-145,202-301,359-410,446-486; tests/test_human_posture.py:38-63,179-223; 163 synthetic golden cases at tests/fixtures/human_posture/cases.json. UNTESTED: independent byte-for-byte comparison with Dash at its current head (the checked-in fixture generator consumes this implementation).
  • MET — C9/R3/R5 fallback, stale wearable, unknown readiness: src/z0int/human_posture.py:202-296; tests/test_human_posture.py:111-114,132-134,157-169. Clock fallback is default, not scored as measured sleep; normal readiness row is selected.
  • MET — R2 activity-relative sleep, rollover and conservative release rule: src/z0int/human_posture.py:209-262,306-333, src/z0int/circadian/service.py:246-258; tests/test_human_posture.py:150-155, tests/test_circadian_service.py:87-113. UNTESTED: actual multi-day source coverage, wake detection and release on the deployed system.
  • MET — C14/C17 gate/channel and absolute-time DST design: src/z0int/human_posture.py:92-93,120-128,314-352,477-486; tests/test_human_posture.py:126-147. UNTESTED: real repeated-hour phone events: src/z0int/circadian/adapters.py:70-85 always resolves ambiguous wall times with the initial fold.
  • MET — Bend source laws/finite twin present: bend/circadian/gate.bend:34-216, LAWS.bend:18-97, scripts/gen_circadian_proof.py:30-77; tests/test_human_posture.py:225-257 requests proof and 1,024-row parity. Generated PROOF.bend has eight case-expanded proofs. UNTESTED: executing Bend/parity here; those tests skip if Bend is absent (tests/test_human_posture.py:227-248).
  • MET — WP1 read-only adapters/CLI/daemon and phase-limited enforcement code: src/z0int/circadian/adapters.py:37-143, service.py:120-202,218-243,298-382, __main__.py:31-100, deploy/circadian/circadiand.service:5-16. Adapter error handling, exposure and install gates below still need fixes.
  • NOT MET — R11 shadow-first deployment gate: deploy/circadian/config.example.json:6, install.sh:19-22,59-61 install/enable quiet_only immediately; src/z0int/circadian/replay.py:20-65 writes a replay but no code checks for a complete, accepted 30-day receipt or explicit owner activation. UNTESTED: the PR's claim of a separate private 30-day shadow run (receipt cannot be reviewed).
  • NOT MET — fail-open and delivery safety: deploy/circadian/notify-guard.sh:6-10, src/z0int/circadian/service.py:274-293 (details below).
  • NOT MET — previous-release rollback behavior as claimed: deploy/circadian/install.sh:17-18,48-56 saves previous but circadian-rollback only restores notification scripts and disables the service; it never restores the previous release pointer.
  • UNTESTED / contract discrepancy — R4 outbound privacy: src/z0int/human_posture.py:26-28,489-491 describes a public projection including phase but returns only allowDecisions and nextPeakAt; the optional loopback server at service.py:329-352 serves raw state/local times rather than just the public projection. The intended trusted-host boundary needs explicit definition.

Correctness findings / minimal fixes

  1. P1, fail-open guard can instead abort the notifier. deploy/circadian/notify-guard.sh:6-10: bare timeout ... route is followed by $? inspection; when sourced into a notifier using set -e, exit 10 (held) or 124 (timeout) terminates before the check, defeating both held acknowledgment and fail-open. Put command in an if ...; then ... else status=$?; fi conditional exempt from errexit; treat only 10 as held and all other errors as original delivery. Test both notifier modes.
  2. P1, duplicate release after an uncertain delivery. src/z0int/circadian/service.py:274-293: deliver command runs before durable released status and queue rename. If delivery succeeds but history append/rename fails or process dies, the next tick re-sends the same digest. Introduce stable queue/delivery IDs, durable attempt/receipt state and downstream deduplication or reconcile uncertain attempts before retry; exercise failed history/rename/restart paths. A successful subprocess exit alone is not exactly-once evidence.
  3. P1, no enforced replay prerequisite. deploy/circadian/config.example.json:6, install.sh:21,59-61, replay.py:20-65: the installed example enables quiet holding without a verifiable R11 shadow approval. Default to enforce=none and require validated coverage + explicit owner opt-in before enabling quiet_only.
  4. P1, replay silently undercounts long histories. src/z0int/circadian/replay.py:20-35,55-65 requests up to 32 days, but src/z0int/circadian/adapters.py:52-54 caps a single bucket query at 5,000 events with no pagination/completeness proof; replay still emits ok: true. Page or chunk the timeline, check actual coverage/continuity, and fail closed on incomplete source windows.
  5. P2, loopback endpoints lack access control and reveal private state. src/z0int/circadian/service.py:329-352: optional GET /posture exposes state/local containing health-derived times, and POST /done, /undone, /route mutate state without caller verification. Bind the read/write API to a permissioned local transport or authenticate callers; expose only an explicitly approved projection to the bridge. Loopback alone is not caller authorization.
  6. P2, malformed upstream data can stop all ticks, contrary to adapter contract. src/z0int/circadian/adapters.py:55-67,126-143: timestamp/duration conversions and DB epoch conversions occur outside their exception guards. A malformed event/row raises, so the entire tick fails. Validate individual entries and return unavailable/skipped provenance without inventing measurements.
  7. P2, cached posture accepts future snapshots and returns conflicting metadata. src/z0int/circadian/service.py:205-213: now - generatedAt <= STALE_AFTER accepts arbitrarily future dates; it recomputes decision but returns stale local and enforcement from the old tick. Require 0 <= age <= STALE_AFTER and recompute every dependent projection/flag together.
  8. P2, one corrupt queue line can prevent any release. src/z0int/circadian/service.py:100-105,274-282: _read_jsonl handles OSError but not invalid JSON; the daemon catches the exception and retries indefinitely. Record/quarantine invalid rows, preserve valid items and make corruption visible without silently discarding notices.
  9. P2, install can partially rewrite notifier scripts. deploy/circadian/install.sh:24-45: wiring depends on hard-coded, untested insertion anchors; a missing second anchor aborts after a first script was already changed. Preflight both anchor signatures and stage replacements before any mutation; add idempotent install and rollback integration tests.

Missing targeted regression tests (exact proposed names)

test_notify_guard_errexit_held_exit10_and_timeout_fail_open; test_release_success_then_archive_failure_no_duplicate_after_restart; test_release_history_failure_with_new_ingress_is_idempotent; test_install_requires_shadow_receipt_and_owner_opt_in; test_replay_refuses_truncated_activitywatch_history; test_posture_api_rejects_unauthorized_mutations; test_posture_api_exposes_only_approved_projection; test_activitywatch_malformed_event_is_unavailable_not_exception; test_noop_invalid_session_timestamp_is_unavailable; test_current_posture_future_timestamp_falls_back; test_current_posture_recomputes_enforcement_and_local_fields; test_release_corrupt_jsonl_line_preserves_good_items; test_install_missing_second_anchor_changes_nothing; test_rollback_restores_previous_release; test_phone_repeated_dst_hour_preserves_event_order. Add replay/guard/install tests to the repository test suite; do not treat fixture self-generation as an independent cross-language oracle.

Cross-PR / exact-head evidence

  • Cross-repo coordination: kvnloo/dash #354 implements the TS twin and posture bridge; #355 independently implements a durable deferred-notice queue, release receipts and OS notification gate. Establish one release/deferral owner and prove no double hold/double digest before either deployment. Their tests and authors' pass claims do not substitute for verifying this head against the Dash head.
  • Same-repo #246 changes onboarding/CI surfaces, but none of PR Circadian WP1: human posture twin, Bend gate laws, circadiand #244's 24 paths overlap its listed changed files; no direct textual merge conflict observed. Its PR description reports the offline-suite failure also on Circadian WP1: human posture twin, Bend gate laws, circadiand #244, so causality remains unproven.
  • Exact-head GitHub Actions: Core unit failure overall (core-unit and OMP-extension jobs succeed; offline-suite 3.11 fails and 3.13 is cancelled after failing step). Evidence receipt failure at 'Check evidence receipt and exact head'. Auto-label and AgentWeb Integration Lab succeeded. The PR author's 196 tests and 313/313 killed mutation receipt (results/circadian_mutation_receipt.json:1-8) are reported, not independently rerun here. Neither mutation score nor the expanded Bend gate proof covers daemon delivery, adapter completeness or installer safety.

Reproduce (NOT RUN — ChatGPT cannot execute code here):

uv run --no-project --with pytest --with hypothesis python -m pytest -q tests/test_human_posture.py tests/test_circadian_service.py
(cd bend/circadian && bend PROOF.bend)
pytest -q tests/test_human_posture.py -k bend
python3 scripts/circadian_mutation.py --jobs 4
python3 scripts/gen_circadian_proof.py
python3 scripts/gen_human_posture_fixtures.py
pytest -q tests/test_circadian_service.py tests/test_human_posture.py

The proposed new test names must be implemented before running them; installer/guard integration checks require isolated synthetic scripts, not live notification services.

Verdict: NEEDS-FIX — fail-open notification and duplicate-release risks plus missing shadow-before-enforcement gate are blocking, independent of the current failing exact-head CI. No approval, merge, new branch or code change performed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:verify Tests, mutation, evidence

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant