Skip to content

Keep timer time monotonic and qualify immutable coverage campaigns - #10

Merged
ErzenXz merged 3 commits into
mainfrom
codex/clock-and-coverage-foundations
Oct 13, 2026
Merged

ErzenXz merged 3 commits into
mainfrom
codex/clock-and-coverage-foundations

Conversation

@ErzenXz

@ErzenXz ErzenXz commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

The logical clock could move backward when fallback polling had advanced time before the first PIT interrupt: a retained VM fixture observes 3 → 1 on prior main. One scoped clock now preserves fallback time and advances it on hardware delivery. IRQ-masked, nonwaiting access retires its borrow before scheduling and preserves caller IF. Raw interrupt counts remain separate diagnostics.

Coverage campaigns now compile only SHA-256-locked runtime sources, reject unexpected cached files, build from a retained clean source archive, isolate runtime/executable/corpus artifacts per run, and preserve partial logs and failure manifests. A new bounded handle-table target compares both owners with independent models across type/rights checks, exhaustion, revocation and clear. Fresh CI coverage runs require nonzero coverage, exact run counts and new corpus discovery.

Validation on clean 0da9e7c: five pure clock tests; retained old-main VM regression and corrected real-PIT proof (3 → 4 → 6); 10,000 handle cases with 272 new corpus entries; workspace and seven parser harness tests; 173 Python tests; strict kernel/harness lint; reviewed unsafe inventory remains 407 sites with no new unsafe construct. Pinned strict-provenance Miri passes all 136 selected tests plus native allocator stress. All 83 required remote checks pass on implementation head 0da9e7c; a live policy/success audit confirms 83 executed and zero failed. The new timer and two coverage contexts are enforced, with every unrelated protection field preserved. Publication head 8334b5f contains documentation only and requires its own checks before integration.

The PR9 merge is recorded as F0.1 completion, bringing the unchanged console checklist denominator to 52/100. F1 boot/CPU obligations, remaining F4/F5 ownership, other F6 targets and sustained qualification remain open. GenOS remains Experimental.

@sourcery-ai

sourcery-ai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

The PR makes logical timer time monotonic across fallback-to-PIT transition using a scoped, saturating clock; adds immutable, evidence-preserving coverage campaigns with a new two-owner handle-table target; and integrates the corresponding CI checks, harnesses, documentation, and roadmap qualification updates.

Sequence diagram for monotonic timer transition

sequenceDiagram
    participant Coordinator
    participant Interrupts
    participant Clock
    participant PIT
    participant Scheduler

    Coordinator->>Interrupts: poll_fallback_tick()
    Interrupts->>Clock: poll_fallback()
    Clock-->>Interrupts: logical ticks
    Interrupts-->>Coordinator: monotonic ticks
    PIT->>Interrupts: genos_irq0_rust(frame)
    Interrupts->>Interrupts: TICKS.fetch_add()
    Interrupts->>Clock: hardware_tick()
    Clock-->>Interrupts: advanced logical ticks
    Interrupts->>Scheduler: timer_preempt(frame)
    Interrupts-->>PIT: complete IRQ handling
Loading

File-Level Changes

Change Details Files
Replaced the split fallback/hardware timer counters with a single saturating monotonic logical clock guarded by a non-waiting scoped borrow.
  • Preserve accumulated fallback ticks when the first PIT interrupt arrives and stop fallback polling thereafter.
  • Keep raw hardware interrupt counts as separate diagnostics while scheduling uses logical ticks.
  • Mask IRQs around clock access, retire borrows before restoring caller IF or preempting, and halt on conflicting access.
  • Add pure clock tests and an immutable-source VM/PIT harness covering transition ordering, saturation, fallback cessation, IRQ progress, and IF preservation.
kernel/src/tick_clock.rs
kernel/src/interrupts.rs
kernel/src/lib.rs
tools/test_tick_clock.py
tools/test_tick_clock_harness.py
tools/test_pure_rust.py
docs/TICK_CLOCK.md
docs/adr/0015-monotonic-logical-clock.md
docs/adr/README.md
docs/PURE_RUST_VERIFICATION.md
.github/workflows/foundation-hardening.yml
Hardened coverage-fuzz campaigns around immutable, reproducible source and per-run evidence.
  • Require clean committed source, build from a retained Git archive, and bind source/runtime/compiler/executable/input identities in manifests.
  • Reject unexpected or symlinked cached runtime files and compile only SHA-256-locked C++ sources.
  • Isolate source, runtime, executable, corpus, logs, artifacts, and manifests per run; serialize cache updates and retain partial failures.
  • Require nonzero coverage and exact run statistics, with CI additionally requiring corpus growth.
tools/test_coverage_fuzz.py
tools/test_coverage_fuzz_harness.py
tools/coverage-fuzz/README.md
.github/workflows/ci.yml
tools/coverage-fuzz/runtime-lock.json
Added a bounded coverage target for process-local handle-table authority and expanded its verification surface.
  • Drive two independent HandleTable owners through registration, rights/type checks, duplicate and zero-handle refusal, exhaustion, revocation, clear, and owner-isolation cases.
  • Compare production tables against independent models after every command, including all handle kinds and authority bits.
  • Add deterministic harness tests and expose the target to parser-stress and coverage-fuzz campaigns.
tools/parser-stress/src/handles.rs
tools/parser-stress/src/lib.rs
tools/parser-stress/src/main.rs
tools/parser-stress/tests/handles.rs
tools/parser-stress/README.md
tools/coverage-fuzz/README.md
Updated CI and project qualification records for the new timer and coverage contracts and recorded F0.1 integration.
  • Add timer-transition and dual coverage CI jobs with retained evidence artifacts.
  • Update required-check metadata, pure-test totals, roadmap status, and console-progress test behavior.
  • Refresh the unsafe inventory and document that independent reproduction and broader roadmap qualification remain open.
.github/workflows/ci.yml
.github/workflows/foundation-hardening.yml
ROADMAP.md
tools/required-ci-checks.json
docs/unsafe-inventory.json
tools/test_console_progress.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T10:39:48.333773Z 0da9e7c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: aa58e205-7d76-47d1-b2cb-0c4da69cb2f1
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@sourcery-ai sourcery-ai 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.

Hey - I've found 4 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tools/test_coverage_fuzz.py" line_range="120-121" />
<code_context>
     compiler = run(["clang++", "--version"]).splitlines()[0]
-    fingerprint = hashlib.sha256((json.dumps(lock, sort_keys=True) + compiler).encode()).hexdigest()
+    recipe = ["clang++", "-std=c++17", "-O2", "-g", "-fno-omit-frame-pointer"]
+    fingerprint = hashlib.sha256(json.dumps({"lock": lock, "compiler": compiler,
+                                            "recipe": recipe, "archiver": ["ar", "rcs"]}, sort_keys=True).encode()).hexdigest()
     marker = runtime / "archive.json"
     if archive.is_file() and marker.is_file():
</code_context>
<issue_to_address>
**Runtime archive reused across architectures**

When a coverage cache is reused on a different host architecture whose Clang reports the same first version line, `build_runtime` can accept an archive compiled for a different host because its cache fingerprint omits the compiler target, while the C++ objects are compiled for Clang’s default target. The later fuzz executable then links against the wrong-architecture archive and the campaign fails.

Include the actual Clang target triple and Rust host target in the archive fingerprint so a host change forces a rebuild.
</issue_to_address>

### Comment 2
<location path="tools/test_coverage_fuzz.py" line_range="68-71" />
<code_context>
-def verified_source(*, offline: bool) -> tuple[Path, dict]:
-    lock = json.loads(LOCK.read_text())
+def check_source_files(source: Path, lock: dict) -> None:
+    expected = {entry["name"] for entry in lock["files"]}
+    if any(path.name not in expected or not path.is_file() or path.is_symlink()
+           for path in source.iterdir()):
+        raise ValueError("unexpected or symlinked file in pinned runtime source cache")
+
+
</code_context>
<issue_to_address>
**Updated locks strand campaigns**

When a later campaign changes the locked runtime file set after an earlier campaign populated `build/coverage-fuzz/source`, `verified_source` calls `check_source_files` before reconciling the shared cache, so a leftover file causes every campaign using the updated lock to raise `ValueError`, including online campaigns. The cache must be manually cleaned.

Reconcile or refresh the cache against the new lock before checking its files.
</issue_to_address>

### Comment 3
<location path="tools/test_coverage_fuzz.py" line_range="138" />
<code_context>
     archive.unlink(missing_ok=True)
-    run(["ar", "rcs", str(archive), *objects], log=runtime / "archive.log")
+    run(["ar", "rcs", str(archive), *objects], log=evidence / "runtime/archive.log")
     marker.write_text(json.dumps({"lock": fingerprint,
                                   "archive_sha256": hashlib.sha256(archive.read_bytes()).hexdigest()},
                                  indent=2) + "\n")
</code_context>
<issue_to_address>
**Interrupted marker write blocks campaigns**

When a campaign is stopped while writing `build/coverage-fuzz/runtime/archive.json`, `build_runtime` loads the cache marker with `json.loads` and propagates a decoding error instead of treating the cache as invalid, so a process interruption during `marker.write_text` leaves subsequent campaigns unable to rebuild the runtime until the marker is removed.

Write the marker to a temporary file and atomically replace it, and treat an invalid marker as a cache miss.
</issue_to_address>

### Comment 4
<location path="tools/test_coverage_fuzz.py" line_range="119-122" />
<code_context>
     archive = runtime / "libFuzzer.a"
     compiler = run(["clang++", "--version"]).splitlines()[0]
-    fingerprint = hashlib.sha256((json.dumps(lock, sort_keys=True) + compiler).encode()).hexdigest()
+    recipe = ["clang++", "-std=c++17", "-O2", "-g", "-fno-omit-frame-pointer"]
+    fingerprint = hashlib.sha256(json.dumps({"lock": lock, "compiler": compiler,
+                                            "recipe": recipe, "archiver": ["ar", "rcs"]}, sort_keys=True).encode()).hexdigest()
     marker = runtime / "archive.json"
     if archive.is_file() and marker.is_file():
         record = json.loads(marker.read_text())
</code_context>
<issue_to_address>
**Runtime cache misstates compiler provenance**

When a cached runtime was built by a different clang or archiver whose identity is not distinguished by the fingerprint, `build_runtime` fingerprints only the first line of `clang++ --version` and the literal `ar` command, so toolchains with the same displayed version but different builds can reuse an archive produced by another toolchain while the manifest records the current toolchain as its provenance.

Bind the cache key to complete compiler and archiver identities (or executable hashes) and record those identities with the cached archive.
</issue_to_address>

Sourcery assessment

Approval pending. 4 findings to address first.

Blocking findings: tools/test_coverage_fuzz.py:121, tools/test_coverage_fuzz.py:71, tools/test_coverage_fuzz.py:138, tools/test_coverage_fuzz.py:122


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment on lines +120 to +121
fingerprint = hashlib.sha256(json.dumps({"lock": lock, "compiler": compiler,
"recipe": recipe, "archiver": ["ar", "rcs"]}, sort_keys=True).encode()).hexdigest()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Runtime archive reused across architectures

When a coverage cache is reused on a different host architecture whose Clang reports the same first version line, build_runtime can accept an archive compiled for a different host because its cache fingerprint omits the compiler target, while the C++ objects are compiled for Clang’s default target. The later fuzz executable then links against the wrong-architecture archive and the campaign fails.

Include the actual Clang target triple and Rust host target in the archive fingerprint so a host change forces a rebuild.

Prompt for AI agents
In `tools/test_coverage_fuzz.py` at lines 120-121:

**Runtime archive reused across architectures**

When a coverage cache is reused on a different host architecture whose Clang reports the same first version line, `build_runtime` can accept an archive compiled for a different host because its cache fingerprint omits the compiler target, while the C++ objects are compiled for Clang’s default target. The later fuzz executable then links against the wrong-architecture archive and the campaign fails.

Include the actual Clang target triple and Rust host target in the archive fingerprint so a host change forces a rebuild.

Comment on lines +68 to +71
expected = {entry["name"] for entry in lock["files"]}
if any(path.name not in expected or not path.is_file() or path.is_symlink()
for path in source.iterdir()):
raise ValueError("unexpected or symlinked file in pinned runtime source cache")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Updated locks strand campaigns

When a later campaign changes the locked runtime file set after an earlier campaign populated build/coverage-fuzz/source, verified_source calls check_source_files before reconciling the shared cache, so a leftover file causes every campaign using the updated lock to raise ValueError, including online campaigns. The cache must be manually cleaned.

Reconcile or refresh the cache against the new lock before checking its files.

Prompt for AI agents
In `tools/test_coverage_fuzz.py` at lines 68-71:

**Updated locks strand campaigns**

When a later campaign changes the locked runtime file set after an earlier campaign populated `build/coverage-fuzz/source`, `verified_source` calls `check_source_files` before reconciling the shared cache, so a leftover file causes every campaign using the updated lock to raise `ValueError`, including online campaigns. The cache must be manually cleaned.

Reconcile or refresh the cache against the new lock before checking its files.

archive.unlink(missing_ok=True)
run(["ar", "rcs", str(archive), *objects], log=runtime / "archive.log")
run(["ar", "rcs", str(archive), *objects], log=evidence / "runtime/archive.log")
marker.write_text(json.dumps({"lock": fingerprint,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Interrupted marker write blocks campaigns

When a campaign is stopped while writing build/coverage-fuzz/runtime/archive.json, build_runtime loads the cache marker with json.loads and propagates a decoding error instead of treating the cache as invalid, so a process interruption during marker.write_text leaves subsequent campaigns unable to rebuild the runtime until the marker is removed.

Write the marker to a temporary file and atomically replace it, and treat an invalid marker as a cache miss.

Prompt for AI agents
In `tools/test_coverage_fuzz.py` at line 138:

**Interrupted marker write blocks campaigns**

When a campaign is stopped while writing `build/coverage-fuzz/runtime/archive.json`, `build_runtime` loads the cache marker with `json.loads` and propagates a decoding error instead of treating the cache as invalid, so a process interruption during `marker.write_text` leaves subsequent campaigns unable to rebuild the runtime until the marker is removed.

Write the marker to a temporary file and atomically replace it, and treat an invalid marker as a cache miss.

Comment on lines +119 to 122
recipe = ["clang++", "-std=c++17", "-O2", "-g", "-fno-omit-frame-pointer"]
fingerprint = hashlib.sha256(json.dumps({"lock": lock, "compiler": compiler,
"recipe": recipe, "archiver": ["ar", "rcs"]}, sort_keys=True).encode()).hexdigest()
marker = runtime / "archive.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Runtime cache misstates compiler provenance

When a cached runtime was built by a different clang or archiver whose identity is not distinguished by the fingerprint, build_runtime fingerprints only the first line of clang++ --version and the literal ar command, so toolchains with the same displayed version but different builds can reuse an archive produced by another toolchain while the manifest records the current toolchain as its provenance.

Bind the cache key to complete compiler and archiver identities (or executable hashes) and record those identities with the cached archive.

Prompt for AI agents
In `tools/test_coverage_fuzz.py` at lines 119-122:

**Runtime cache misstates compiler provenance**

When a cached runtime was built by a different clang or archiver whose identity is not distinguished by the fingerprint, `build_runtime` fingerprints only the first line of `clang++ --version` and the literal `ar` command, so toolchains with the same displayed version but different builds can reuse an archive produced by another toolchain while the manifest records the current toolchain as its provenance.

Bind the cache key to complete compiler and archiver identities (or executable hashes) and record those identities with the cached archive.

@ErzenXz
ErzenXz enabled auto-merge (rebase) October 13, 2026 10:45
@ErzenXz
ErzenXz merged commit 20f53f1 into main Oct 13, 2026
85 checks passed
@ErzenXz
ErzenXz deleted the codex/clock-and-coverage-foundations branch October 13, 2026 10:52
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