Skip to content

feat(lab): CL-07 task effectiveness evidence - #1438

Merged
Wibias merged 25 commits into
devfrom
feat/cl-07-task-effectiveness-producer
Aug 11, 2026
Merged

feat(lab): CL-07 task effectiveness evidence#1438
Wibias merged 25 commits into
devfrom
feat/cl-07-task-effectiveness-producer

Conversation

@Wibias

@Wibias Wibias commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add a bounded Lab-owned task-effectiveness producer for frozen fabric-core@1.0.0 / fabric-core.task.synthetic-patch@1.0.0 under src/lab/fabric/.
  • Exact starting SHA: b66e33ce7207d91014644d99317e456c992a3418 (CL-06 merge feat(lab): CL-06 routing compatibility policy #1394).
  • No general Agent Fabric product API. CL-08 automation/background execution is not started.

Task producer contract

Closed FabricTaskOutcomeV1 (schemaVersion 1) with task class, exact nested RouteSubjectV1, TaskSubjectV1 / subjectId, fixture/verifier/fabric/sandbox digests, timing, limits, usage, normalized outcome, verifier result, typed failure, sanitized artifact digests, optional safe sourceRefs.

Forbidden in outcomes/artifacts: user repos, prompts, credentials, host paths, unrestricted logs, raw model transcripts.

TaskSubjectV1 identity

Uses existing Lab TaskSubjectV1. Material changes to route, fixture, verifier, fabric compatibility version, or sandbox profile produce a distinct subject id.

Synthetic-patch V1 scenario

Lab-owned scratch tree with src/value.txt = before\n; requested final after\n. Limits: one file, 64 KiB aggregate I/O, one patch op, 30s total, 5s inactivity, 1 MiB artifacts. No network / user MCP / shell / user repository inside scratch.

Deterministic verifier

exact-tree-diff-v1: no-follow walk, UTF-8 path sort, reject traversal/symlinks/special/unexpected files; pass only for sole change before\n → after\n.

Sandbox design

Ephemeral scratch under Lab paths; direct file write patch apply (no shell); deny-by-default capability probe; cleanup on all exits; frozen sandboxProfileDigest.

Lab ingestion

observationFromFabricOutcome / idempotent persistFabricOutcome → existing JSONL + artifact store + rebuildable SQLite. evidenceLayer: task_effectiveness, executionMode: fabric. Catalog discovers fabric-core via CL-04 queryLabCatalog.

CL-06 boundary

Routing requiredSuites remains protocol/live only. TaskSubjectV1 cannot be resolved pre-dispatch; CL-06 semantics unchanged.

Validation

  • bun x tsc --noEmit
  • bun test tests/lab-fabric-task.test.ts (20)
  • bun test tests/lab-read-surfaces.test.ts tests/routing-compatibility.test.ts
  • bun test tests/repo-hygiene.test.ts
  • bun run privacy:scan

Explicit non-goals

CL-08 (automation / background execution) is not started.

Test plan

  • Cross-platform CI green
  • Fabric subject / sandbox / verifier / observe regressions green
  • CL-06 routing unchanged
  • Privacy scan green
  • No user repo/prompt/secret in task evidence

Summary by CodeRabbit

  • New Features

    • Added bounded task-effectiveness evaluation for synthetic patch scenarios.
    • Added deterministic verification, resource limits, sandbox restrictions, isolated workspaces, and structured results.
    • Added persistent observations and artifacts with duplicate-event protection.
    • Added task-effectiveness scenarios to catalogs and verification views, with applicability checks.
  • Bug Fixes

    • Improved failure classification, timeout reporting, ledger locking, and secret redaction.
  • Tests

    • Added comprehensive coverage for execution, security, persistence, catalog visibility, routing, and recovery.

Add a bounded Lab-owned fabric-core synthetic-patch producer with exact-tree-diff verification, scratch sandbox, TaskSubjectV1 identity, and observation ingestion without a general Agent Fabric platform.
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

CL-07 adds a bounded Fabric task-effectiveness producer for one synthetic patch scenario. It defines task outcomes and manifests, enforces scratch and execution limits, verifies exact tree changes, persists idempotent observations, exposes catalog metadata, and projects verification verdicts.

Changes

Fabric task-effectiveness evidence

Layer / File(s) Summary
Fabric contracts and authoritative manifests
devlog/_plan/260807_compatibility_lab/..., src/lab/fabric/..., src/lab/conformance/types.ts, src/lab/events/..., src/lab/index.ts
Defines Fabric identifiers, outcome schemas, task subjects, manifests, execution policies, failure classifications, and public exports.
Bounded synthetic-patch execution
src/lab/fabric/scratch.ts, src/lab/fabric/patch.ts, src/lab/fabric/verifier.ts, src/lab/fabric/executor.ts, src/lab/fabric/producer-*.ts, src/lab/paths.ts, src/lib/fabric-task-*.ts
Creates restricted scratch trees, isolates producers, applies one replacement patch, enforces limits, verifies the exact file transition, and seals typed outcomes.
Evidence ingestion and verdict projection
src/lab/fabric/observe.ts, src/lab/ledger/store.ts, src/lab/projection/..., src/lab/query/catalog.ts, src/lab/observe/..., src/lab/live/transport.ts, src/lab/artifacts/sanitize.ts
Validates and persists observations, suppresses duplicate events, exposes catalog entries, maps failures, classifies inactivity timeouts, and produces task-effectiveness verdicts.
Fabric behavior validation
tests/lab-fabric-task.test.ts, tests/lab-live-probe.test.ts, tests/lab-evidence-ledger.test.ts, tests/helpers/fabric-task-test.ts, tests/fixtures/fabric-executors/*
Tests identity, execution, filesystem safety, limits, persistence, projection, catalog exposure, routing, timeout classification, lock handling, and redaction.

Estimated code review effort: 5 (Critical) | ~90 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SyntheticPatchProducer
  participant FabricExecutor
  participant ScratchWorkspace
  participant TreeVerifier
  participant ObservationStore
  participant VerdictProjection
  SyntheticPatchProducer->>FabricExecutor: Produce bounded synthetic patch
  FabricExecutor->>ScratchWorkspace: Create fixture and apply patch
  FabricExecutor->>TreeVerifier: Verify exact tree diff
  TreeVerifier-->>FabricExecutor: Return structured result
  FabricExecutor->>ObservationStore: Persist outcome and artifacts
  ObservationStore->>VerdictProjection: Provide task-effectiveness observation
  VerdictProjection-->>ObservationStore: Project verification verdict
Loading

Possibly related PRs

Suggested reviewers: ingwannu, lidge-jun

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.98% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the CL-07 task-effectiveness evidence feature, which matches the primary changes in the pull request.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cl-07-task-effectiveness-producer

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.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

Record the implementation head and draft PR on the programme status documents.
@github-actions github-actions Bot added the enhancement New feature or request label Aug 10, 2026
Wire task_effectiveness + fabric through all-applicable-required-pass-v1 so successful synthetic-patch observations can leave PROBED.
coderabbitai[bot]

This comment was marked as resolved.

Wibias added 2 commits August 10, 2026 23:31
Harden scratch IO, timeouts, outcome validation, ledger idempotency, and
projection/catalog paths so the review findings stay closed on this branch.
Keep the CL-06 accepted head from dev and preserve the in-progress CL-07 row.
@Wibias
Wibias marked this pull request as ready for review August 10, 2026 21:41

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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)
src/lab/fabric/observe.ts (1)

189-198: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not persist raw producer verifier data.

Line 194 stores outcome.verifier without an allowlist or diagnostic sanitization. A producer can place a token in verifier.reason or an extra nested property. The assertion at Line 236 sanitizes the diagnostic, but the verifier_summary artifact keeps the raw value. Artifact and read surfaces can then expose credentials.

Build this artifact from validated, allowlisted fields. Sanitize and truncate every diagnostic field before persistence. Reject unknown nested verifier fields. Add a regression test that persists a credential-like verifier diagnostic and confirms that neither the ledger nor artifact payload contains it.

🤖 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 `@src/lab/fabric/observe.ts` around lines 189 - 198, The verifier_summary
artifact construction in observe should not persist raw outcome.verifier data.
Build verifier from an explicit allowlist of validated fields, reject unknown
nested properties, and sanitize and truncate every diagnostic field before
passing the payload to store.put. Add a regression test covering a
credential-like verifier diagnostic and assert the secret is absent from both
the ledger and persisted artifact payload.

Source: Path instructions

🤖 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 `@src/lab/fabric/executor.ts`:
- Around line 109-116: Move options.producePatch execution out of the caller’s
event loop into a terminable worker or equivalent isolated boundary, and update
the flow around createTimeoutController and controller.race to terminate it on
total or inactivity timeout. Avoid exposing scratch.root directly to an
unbounded producer; mediate filesystem access through the protected boundary.
Add a regression test using a non-terminating worker producer that verifies task
completion and scratch cleanup within the configured timeout.

In `@src/lab/fabric/observe.ts`:
- Around line 126-134: In src/lab/fabric/observe.ts lines 126-134, update
assertFabricOutcomeV1 to validate the complete nested TaskSubjectV1,
RouteSubjectV1, verifier, usage, limits, failure, artifact-digest, and
source-reference contracts before observation creation, and reject contradictory
top-level versus nested subjects with FabricTaskError. In
tests/lab-fabric-task.test.ts lines 323-329, add valid-baseline outcome cases
with malformed verifier, usage, and subject fields, asserting each call throws
FabricTaskError.

In `@src/lab/fabric/scratch.ts`:
- Around line 19-20: Update the scratch-file write flow around the path
validation and open logic to traverse each directory via file descriptors using
O_NOFOLLOW rather than reopening absolute pathnames after lstatSync validation.
Open the final file from the validated parent descriptor, then fstat that
descriptor and retain the existing scratch-root and file-mode checks.

In `@src/lab/ledger/store.ts`:
- Around line 35-58: Update withLedgerLock to record lock ownership and creation
metadata, and when acquisition encounters an existing lock, recover it only when
its metadata proves it is safely stale; otherwise continue retrying until the
existing deadline and error behavior. Ensure cleanup removes only the lock owned
by the current acquisition, and add a regression test that pre-creates an
expired lock and verifies appendLabEventIfAbsent succeeds.

In `@src/lab/observe/from-live.ts`:
- Around line 23-25: Update the environment-attribution classifications used by
failureFromLiveResult to include "inactivity_timeout", ensuring execution
timeouts persist with attribution "environment" rather than "route". Add a
regression test covering a persisted inactivity-timeout failure and asserting
its environment attribution.

In `@src/lab/paths.ts`:
- Around line 5-10: Update ensureRestrictedDir to reject symbolic links and
non-directory entries immediately after lstatSync, before any chmodSync call;
preserve the existing mode enforcement only for real directories. Add a
regression test covering a symlinked labScratchDir, asserting
createSyntheticScratch fails and no scratch data is written outside the Lab
root.

In `@src/lab/projection/verification.ts`:
- Around line 86-92: The requirements applicability logic in
src/lab/projection/verification.ts:86-92 must preserve the wildcard default by
treating omitted requirements.platforms as ["*"] rather than []. Update the
platform default used by the relevant verification function while preserving
explicit platform handling. Add a test case in
tests/lab-fabric-task.test.ts:351-378 with platforms omitted and a valid Fabric
capability, asserting that the scenario is applicable.

---

Outside diff comments:
In `@src/lab/fabric/observe.ts`:
- Around line 189-198: The verifier_summary artifact construction in observe
should not persist raw outcome.verifier data. Build verifier from an explicit
allowlist of validated fields, reject unknown nested properties, and sanitize
and truncate every diagnostic field before passing the payload to store.put. Add
a regression test covering a credential-like verifier diagnostic and assert the
secret is absent from both the ledger and persisted artifact payload.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6b9c3041-916f-4423-94cb-91c1577c2ea1

📥 Commits

Reviewing files that changed from the base of the PR and between ec275ee and 2f9c151.

📒 Files selected for processing (21)
  • devlog/_plan/260807_compatibility_lab/001_pr_stack_status.md
  • src/lab/conformance/types.ts
  • src/lab/events/types.ts
  • src/lab/events/validate.ts
  • src/lab/fabric/constants.ts
  • src/lab/fabric/executor.ts
  • src/lab/fabric/index.ts
  • src/lab/fabric/manifest.ts
  • src/lab/fabric/observe.ts
  • src/lab/fabric/patch.ts
  • src/lab/fabric/scratch.ts
  • src/lab/fabric/subject.ts
  • src/lab/fabric/types.ts
  • src/lab/ledger/store.ts
  • src/lab/observe/from-conformance.ts
  • src/lab/observe/from-live.ts
  • src/lab/paths.ts
  • src/lab/projection/verdicts.ts
  • src/lab/projection/verification.ts
  • src/lab/query/catalog.ts
  • tests/lab-fabric-task.test.ts

Comment thread src/lab/fabric/executor.ts Outdated
Comment thread src/lab/fabric/observe.ts Outdated
Comment thread src/lab/fabric/scratch.ts
Comment thread src/lab/ledger/store.ts
Comment thread src/lab/observe/from-live.ts
Comment thread src/lab/paths.ts Outdated
Comment thread src/lab/projection/verification.ts Outdated
Harden fabric observation validation and scratch IO, recover stale ledger locks, attribute inactivity_timeout as environment, and add regression tests.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

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

⚠️ Outside diff range comments (1)
src/lab/fabric/executor.ts (1)

119-147: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

usage.inactiveMs records total production time, not inactive time, and the success path never sets it at all.

Line 122 computes usage.inactiveMs = Math.max(0, completedAt - produceStarted). produceStarted is captured at Line 106, immediately before the producer starts. The expression therefore measures the entire wall-clock duration of patch production. It does not measure idle time.

Two consequences follow.

  1. Wrong value on every producer failure. This assignment runs for every FabricTaskError from the producer, including timeout, budget_exhausted, and malformed_producer_outcome. A producer that streams output continuously for four seconds and then fails a budget check records inactiveMs: 4000 while it was never inactive.
  2. Always zero on success. The success path at Line 161 sets only usage.elapsedMs. inactiveMs keeps its initial value of 0 from Line 95, even when the producer had real idle gaps that reportActivity observed.

src/lab/fabric/observe.ts validateFabricUsage only checks that the value is a non-negative integer, so neither case is rejected. The wrong value is sealed into FabricTaskOutcomeV1, persisted through the artifact store, and written to the ledger. Any later analysis of Fabric inactivity reads fabricated numbers.

createTimeoutController already tracks activity through reportActivity. Expose the measured idle time and use it on both paths.

🐛 Proposed fix — report measured inactivity

Add an accessor to the controller:

 function createTimeoutController(totalMs: number, inactivityMs: number, options: RunFabricTaskOptions) {
+  // Track the longest observed gap between reportActivity() calls so the
+  // outcome can report real inactivity instead of total elapsed time.
+  let maxInactiveMs = 0;

Then use it in both branches:

       const completedAt = options.now?.() ?? Date.now();
       usage.elapsedMs = completedAt - startedAt;
-      usage.inactiveMs = Math.max(0, completedAt - produceStarted);
+      usage.inactiveMs = controller.inactiveMs();
     const verifier = verifyExactTreeDiffV1(scratch.root);
     const completedAt = options.now?.() ?? Date.now();
     usage.elapsedMs = completedAt - startedAt;
+    usage.inactiveMs = controller.inactiveMs();

The controller binding must move out of the inner try so both paths can read it.

Add a regression test with a producer that calls reportActivity on a known cadence, then assert that the sealed usage.inactiveMs matches the largest injected gap rather than the total duration.

As per path instructions: "A behavior change in src/ should come with a focused regression test near the existing tests for that subsystem."

🤖 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 `@src/lab/fabric/executor.ts` around lines 119 - 147, Expose the measured idle
duration from createTimeoutController, then update the executor’s controller
binding so it is available on both success and FabricTaskError paths. Replace
the elapsed-duration assignment to usage.inactiveMs with the controller’s
measured inactivity accessor, and set it before sealing either outcome. Add a
focused regression test using periodic reportActivity calls to verify inactiveMs
reflects the largest injected gap rather than total production time.

Source: Path instructions

🤖 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 `@src/lab/fabric/observe.ts`:
- Around line 110-115: Change wrapValidationError to declare a never return
type, since every execution path throws. Remove the definite-assignment
assertions from taskSubject and routeSubject so TypeScript enforces their
initialization while preserving the existing catch-and-throw behavior.

In `@src/lab/fabric/scratch.ts`:
- Around line 77-89: Update revalidateScratchDir so its behavior no longer
implies that comparing fstatSync(dir.fd) with dir.identity detects directory
replacement: either document that the check only validates the descriptor and
detects invalid descriptors, or replace it with a descriptor-versus-path
comparison that can detect pathname entry replacement. Preserve the existing
descriptor-relative and O_NOFOLLOW protections, and anchor the change in
revalidateScratchDir and openTrustedScratchRoot.
- Around line 173-210: Update openScratchRelativePath to close all
intermediateFds on the successful final openAtScratch path as well as on errors,
while preserving the returned final descriptor; add a focused regression test
near the existing lab fabric tests that performs many writeScratchFileUtf8 calls
against one scratch tree and verifies the process descriptor count does not grow
monotonically.
- Around line 379-396: Remove the unreachable stats.isSymbolicLink() checks and
their symlink-rejection branches from both readScratchFileUtf8 and
writeScratchFileUtf8. Keep the existing assertRegularFile checks and all
surrounding descriptor cleanup, size validation, and read/write behavior
unchanged.
- Around line 150-171: Change getTrustedScratch to reject scratch roots absent
from trustedScratchRoots instead of opening and caching them lazily; only
createSyntheticScratch registration should establish trusted descriptors, while
releaseTrustedScratch remains responsible for cleanup. Add a focused regression
test covering createSyntheticScratch cleanup followed by readScratchFileUtf8 on
the same root, asserting the read fails rather than reopening it.
- Around line 398-415: Update writeScratchFileUtf8 to perform
resolveInsideScratch containment validation before any directory creation, and
replace the pathname-based ensureRestrictedDir call with trusted-descriptor,
mkdirat-style creation for each missing parent component. Preserve the guarded
openScratchRelativePath flow. Add a focused regression test covering an
intermediate scratch-directory symlink to an external target and assert that no
nested directory is created outside the scratch tree.
- Around line 297-308: Wrap the construction logic in createSyntheticScratch,
from openTrustedScratchRoot through file creation and writing, in failure
cleanup that calls releaseTrustedScratch and removes the created scratch tree
before rethrowing. Ensure cleanup runs for budget validation,
openScratchRelativePath, writeSync, and any later construction errors while
preserving the existing successful ScratchTree cleanup behavior.
- Around line 28-33: Remove the OpenSyncWithDir type, the "dirfd" mode, and
detectScratchIoMode from scratch I/O handling. Update the affected
scratch-directory operations to always use the existing validated pathname-based
branch, including nested scratch directories, without relying on unsupported
fs.openSync options.

In `@src/lab/ledger/store.ts`:
- Around line 59-75: Update tryAcquireLedgerLock to bound stale-lock retries,
propagate unlinkSync failures, and close the descriptor when writeSync fails;
replace time-based lock replacement with ownership held through the critical
section so live holders cannot be replaced and cleanup cannot remove a
replacement lock. Add coverage for deletion failure, concurrent writers, and
duplicate-event corruption. Update capability verification to treat "*" in
capability.platforms as matching every required platform, and strengthen
lab-fabric-task tests to assert FabricTaskError and expected error codes.

In `@src/lab/paths.ts`:
- Around line 6-18: Update ensureRestrictedDir to create and validate each path
component incrementally rather than calling recursive mkdirSync on the full
path, rejecting any existing symbolic-link component before proceeding; import
resolve, sep, and join from node:path, and tolerate EEXIST from per-component
creation. Add a focused regression test near the existing lab tests that makes a
scratch-directory ancestor link to an external directory, calls ensureLabDirs,
and verifies the link target remains untouched.

---

Outside diff comments:
In `@src/lab/fabric/executor.ts`:
- Around line 119-147: Expose the measured idle duration from
createTimeoutController, then update the executor’s controller binding so it is
available on both success and FabricTaskError paths. Replace the
elapsed-duration assignment to usage.inactiveMs with the controller’s measured
inactivity accessor, and set it before sealing either outcome. Add a focused
regression test using periodic reportActivity calls to verify inactiveMs
reflects the largest injected gap rather than total production time.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6f3c4a6b-ec8c-4f7d-a889-14acdb1b1a43

📥 Commits

Reviewing files that changed from the base of the PR and between 2f9c151 and 5dd527c.

📒 Files selected for processing (10)
  • src/lab/fabric/executor.ts
  • src/lab/fabric/observe.ts
  • src/lab/fabric/scratch.ts
  • src/lab/ledger/store.ts
  • src/lab/live/transport.ts
  • src/lab/observe/from-live.ts
  • src/lab/paths.ts
  • src/lab/projection/verification.ts
  • tests/lab-fabric-task.test.ts
  • tests/lab-live-probe.test.ts

Comment thread src/lab/fabric/observe.ts Outdated
Comment thread src/lab/fabric/scratch.ts Outdated
Comment thread src/lab/fabric/scratch.ts
Comment thread src/lab/fabric/scratch.ts Outdated
Comment thread src/lab/fabric/scratch.ts
Comment thread src/lab/fabric/scratch.ts Outdated
Comment thread src/lab/fabric/scratch.ts
Comment thread src/lab/fabric/scratch.ts Outdated
Comment thread src/lab/ledger/store.ts Outdated
Comment thread src/lab/paths.ts Outdated
Document exported and internal fabric helpers, scratch IO, observation validation, and ledger lock recovery.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@src/lab/fabric/observe.ts`:
- Around line 208-211: Update routeSubjectsMatch to compare canonical
representations instead of JSON.stringify output, using jcsStringify for both
RouteSubjectV1 values or the existing canonical subject ID mechanism. Preserve
the boolean equality result while making equivalent subjects with different key
insertion orders match.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2e4e0fc0-dad5-41b5-88fd-9fbbf3a4b823

📥 Commits

Reviewing files that changed from the base of the PR and between 5dd527c and bc00433.

📒 Files selected for processing (11)
  • src/lab/fabric/executor.ts
  • src/lab/fabric/index.ts
  • src/lab/fabric/manifest.ts
  • src/lab/fabric/observe.ts
  • src/lab/fabric/patch.ts
  • src/lab/fabric/scratch.ts
  • src/lab/fabric/subject.ts
  • src/lab/fabric/types.ts
  • src/lab/fabric/verifier.ts
  • src/lab/ledger/store.ts
  • src/lab/projection/verification.ts

Comment thread src/lab/fabric/observe.ts Outdated
Harden scratch IO and restricted dirs, improve ledger lock ownership, treat capability platform wildcard as universal, and strengthen regression tests.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (1)
src/lab/projection/verification.ts (1)

188-196: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the capability object shape into a named type.

Lines 192-196 repeat the exact structural literal that taskSubjectApplicableToRequirements declares at Lines 81-85. The two must stay identical, because the evaluator forwards this option straight into that predicate. A named type keeps them synchronized and documents the option on the public surface.

♻️ Proposed shared capability type
+export interface FabricCapability {
+  harnessFeatures: readonly string[];
+  platforms: readonly string[];
+  routePreconditions: readonly string[];
+}
+
 export function taskSubjectApplicableToRequirements(
   requirements: ScenarioRequirements,
-  capability: {
-    harnessFeatures: readonly string[];
-    platforms: readonly string[];
-    routePreconditions: readonly string[];
-  },
+  capability: FabricCapability,
 ): boolean {
-    fabricCapability?: {
-      harnessFeatures: readonly string[];
-      platforms: readonly string[];
-      routePreconditions: readonly string[];
-    };
+    fabricCapability?: FabricCapability;
🤖 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 `@src/lab/projection/verification.ts` around lines 188 - 196, Extract the
inline fabricCapability object shape into a shared named type, then reuse that
type both in the public projection options around subject/routeSupportedClaims
and in taskSubjectApplicableToRequirements. Preserve the existing readonly
harnessFeatures, platforms, and routePreconditions properties so the evaluator
can forward the option unchanged.
🤖 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 `@src/lab/fabric/scratch.ts`:
- Around line 247-267: Update ensureScratchRelativeDir to remove the
existsSync(next) pre-check and attempt mkdirSync(next, { mode: 0o700 }) directly
for each component. Match the sibling paths implementation by catching and
ignoring only EEXIST, while propagating other errors; retain the subsequent
lstatSync, symlink rejection, and assertRealDirectory checks.
- Around line 153-157: Consolidate intermediate descriptor cleanup around the
open/return flow in the scratch descriptor method, using one guarded helper or
finally path for intermediateFds. Ensure cleanup runs exactly once on both
success and failure, closes finalFd if cleanup fails after it is opened, and
preserves FabricTaskError wrapping for cleanup errors; remove the duplicated
unguarded and catch-path loops.

In `@src/lab/ledger/store.ts`:
- Around line 64-72: Update isLockHolderAlive to distinguish process.kill(pid,
0) errors: return false only for ESRCH, return true for EPERM, and preserve the
existing true result when no error occurs. Keep the documented predicate
behavior for other unexpected errors according to the surrounding error-handling
conventions.
- Around line 74-80: Update isLedgerLockStale to require the metadata-free lock
file to be at least LEDGER_LOCK_STALE_MS old before treating it as stale; use
the lock file’s modification time for this grace-period check and preserve
existing metadata-based holder and age handling. Add a focused regression test
near the expired-lock test in tests/lab-fabric-task.test.ts that creates a
current, metadata-free lock and verifies appendLabEventIfAbsent does not steal
it.
- Around line 82-109: Update tryAcquireLedgerLock so a failed unlinkSync waits
with sleepSyncMs(10) before retrying, while preserving immediate retry after
successful removal and rethrowing once the deadline is reached. Add a focused
regression test near the expired-lock test in tests/lab-fabric-task.test.ts that
forces lock removal to fail and verifies appendLabEventIfAbsent rejects within
the configured wait budget without spinning.

In `@src/lab/paths.ts`:
- Around line 11-41: Limit symlink rejection in the directory-creation helper to
the Lab root and its descendants, while treating ancestors above that boundary
as infrastructure. Add an explicit Lab-root boundary parameter to the helper and
pass it from ensureLabDirs and Fabric scratch creation; compare normalized path
components rather than string lengths. Preserve lstatSync validation for the Lab
root and child components, and add a regression test covering a symlinked
ancestor.

In `@tests/lab-fabric-task.test.ts`:
- Around line 498-512: Update the ensureLabDirs assertion in the “symlinked lab
root rejects directory escape via ensureLabDirs” test to require the specific
“restricted directory component is a symbolic link” error message, while
preserving the existing side-effect assertions that scratch and artifacts are
not created.
- Line 472: Replace the hard-coded PID in the stale-lock fixture of the relevant
test with a dynamically selected PID that is proven not to belong to a live
process, using a focused dead-PID helper near the existing ledger-lock tests.
Keep the stale timestamp and token unchanged, and ensure the fixture remains
compatible with isLedgerLockStale and tryAcquireLedgerLock recovery behavior.
- Around line 408-428: Replace the manual try/catch blocks around
observationFromFabricOutcome with direct object-form toThrow assertions, using
expect.objectContaining to assert name "FabricTaskError" and the expected
malformed_producer_outcome or layer_subject_mismatch code. Keep the existing
malformed usage and providerId mismatch inputs unchanged.

---

Outside diff comments:
In `@src/lab/projection/verification.ts`:
- Around line 188-196: Extract the inline fabricCapability object shape into a
shared named type, then reuse that type both in the public projection options
around subject/routeSupportedClaims and in taskSubjectApplicableToRequirements.
Preserve the existing readonly harnessFeatures, platforms, and
routePreconditions properties so the evaluator can forward the option unchanged.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9827a712-64c0-4d7a-adce-e4ba2476f946

📥 Commits

Reviewing files that changed from the base of the PR and between bc00433 and 1689466.

📒 Files selected for processing (6)
  • src/lab/fabric/observe.ts
  • src/lab/fabric/scratch.ts
  • src/lab/ledger/store.ts
  • src/lab/paths.ts
  • src/lab/projection/verification.ts
  • tests/lab-fabric-task.test.ts

Comment thread src/lab/fabric/scratch.ts Outdated
Comment thread src/lab/fabric/scratch.ts
Comment thread src/lab/ledger/store.ts
Comment thread src/lab/ledger/store.ts Outdated
Comment thread src/lab/ledger/store.ts
Comment thread src/lab/paths.ts
Comment thread tests/lab-fabric-task.test.ts
Comment thread tests/lab-fabric-task.test.ts Outdated
Comment thread tests/lab-fabric-task.test.ts
Limit symlink checks to Lab-owned paths, harden ledger lock recovery, consolidate scratch fd cleanup, and compare route subjects via JCS.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@src/lab/fabric/scratch.ts`:
- Around line 284-317: Update createSyntheticScratch so its try block begins
before the root and parent-directory setup, ensuring failures during any
construction phase reach cleanup. In the catch, close trusted when present, then
best-effort remove root with rmSync before rethrowing; preserve cleanup of
partial files such as SYNTHETIC_VALUE_PATH. Add a regression test that forces
failure after root creation and verifies labScratchDir contains no fabric-*
directory.

In `@src/lab/ledger/store.ts`:
- Around line 77-83: Update isLedgerLockStale to recover metadata-free lock
files only when their filesystem modification time exceeds LEDGER_LOCK_STALE_MS,
while treating recent empty locks as active; also remove the lock file when
metadata writing fails in the lock-creation flow. Add focused regression cases
near the expired-lock test in appendLabEventIfAbsent coverage for both stale
empty-lock recovery and protection of current empty locks.

In `@src/lab/paths.ts`:
- Around line 19-25: Update ensureRestrictedDir so labRootBoundary is a required
parameter, then remove the labRootBoundary ?? abs fallback and resolve the
supplied boundary directly. Preserve the existing Windows behavior and
downstream boundary checks.
- Around line 20-23: Update the path creation logic in src/lab/paths.ts to
remove the Windows early return and validate every path component on all
platforms, rejecting non-directories and Windows reparse points rather than
relying only on Stats.isSymbolicLink(). Keep chmodSync restricted to POSIX
systems, and add Windows coverage for the cases represented by the tests near
lines 487, 503, and 519 in lab-fabric-task.test.ts.

In `@src/lab/projection/verification.ts`:
- Around line 87-95: Update the platform applicability logic in the
requirements-checking function by replacing the `platforms.every(...)` condition
with allow-list overlap semantics: return true when the capability supports at
least one required platform, while preserving wildcard handling and the existing
feature/precondition checks. Add a focused regression test beside the existing
applicability test covering requirements `["linux", "darwin"]` with capability
`["linux"]` returning true and `["win32"]` returning false, with no wildcards.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3010842b-07e8-4d1f-b5b8-90c47f7a6055

📥 Commits

Reviewing files that changed from the base of the PR and between bc00433 and e00a640.

📒 Files selected for processing (6)
  • src/lab/fabric/observe.ts
  • src/lab/fabric/scratch.ts
  • src/lab/ledger/store.ts
  • src/lab/paths.ts
  • src/lab/projection/verification.ts
  • tests/lab-fabric-task.test.ts

Comment thread src/lab/fabric/scratch.ts
Comment thread src/lab/ledger/store.ts
Comment thread src/lab/paths.ts Outdated
Comment thread src/lab/paths.ts Outdated
Comment thread src/lab/projection/verification.ts
- Clean up partial scratch dirs on createSyntheticScratch failure

- Age out metadata-free ledger locks via mtime and unlink on write failure

- Require lab root boundary for ensureRestrictedDir; validate reparse points on Windows

- Use platforms.some for capability allow-list semantics

- Add junction/symlink and scratch cleanup regression tests

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
src/lab/ledger/store.ts (1)

97-120: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Propagate lock metadata write failures immediately.

If writeSync fails at Line 98, Lines 99-106 remove the lock and rethrow. The outer catch at Line 109 then treats that error as a lock-acquisition collision. It retries until the deadline and finally throws "ledger lock acquisition timed out".

Handle openSync collision errors separately from failures after exclusive lock creation. After cleanup, rethrow the metadata-write error directly. Add a regression test that forces the metadata write to fail and asserts that appendLabEventIfAbsent returns that error without waiting for the lock deadline.

🤖 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 `@src/lab/ledger/store.ts` around lines 97 - 120, Update the lock-acquisition
flow around openSync and writeSync so metadata-write failures are distinguished
from exclusive-open collisions: after the writeSync cleanup in the inner catch,
propagate that original error directly instead of letting the outer catch retry
until the deadline. Preserve stale-lock retry behavior only for openSync
acquisition collisions, and add a regression test proving appendLabEventIfAbsent
returns the forced metadata-write error without waiting for the lock timeout.

Source: Path instructions

🤖 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.

Outside diff comments:
In `@src/lab/ledger/store.ts`:
- Around line 97-120: Update the lock-acquisition flow around openSync and
writeSync so metadata-write failures are distinguished from exclusive-open
collisions: after the writeSync cleanup in the inner catch, propagate that
original error directly instead of letting the outer catch retry until the
deadline. Preserve stale-lock retry behavior only for openSync acquisition
collisions, and add a regression test proving appendLabEventIfAbsent returns the
forced metadata-write error without waiting for the lock timeout.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e5c59657-6408-40a3-96ff-b518de2d00d7

📥 Commits

Reviewing files that changed from the base of the PR and between e00a640 and 9edeeaf.

📒 Files selected for processing (5)
  • src/lab/fabric/scratch.ts
  • src/lab/ledger/store.ts
  • src/lab/paths.ts
  • src/lab/projection/verification.ts
  • tests/lab-fabric-task.test.ts

Separate openSync collision retries from writeSync metadata failures so appendLabEventIfAbsent surfaces the original error without waiting for the lock timeout. Add regression test.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@src/lab/ledger/store.ts`:
- Line 113: Update the lock-metadata write in the lock-acquisition flow around
writeSync to verify that the returned byte count equals the metadata buffer
length; throw on a short or zero write so the existing cleanup removes the lock.
Add a focused test in the lab evidence ledger tests that simulates an incomplete
metadata write and verifies appendLabEventIfAbsent fails without leaving the
lock file.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 614ac4ec-7202-4a4f-a76f-62fb2bbc7818

📥 Commits

Reviewing files that changed from the base of the PR and between 9edeeaf and 006f880.

📒 Files selected for processing (2)
  • src/lab/ledger/store.ts
  • tests/lab-evidence-ledger.test.ts

Comment thread src/lab/ledger/store.ts Outdated
Wibias added 2 commits August 11, 2026 01:29
Verify writeSync byte count for lock metadata and throw short_write so cleanup unlinks the lock. Add regression test for zero-byte metadata write.
Bind production task evidence to trusted route execution via buildRouteSubjectV1 and host-issued patch executors. Run patch producers in an isolated Bun child with hard kill on timeout. Separate harness vs trusted persistence, fix verifier infrastructure failure taxonomy, inactiveMs accounting, and privacy canary pattern.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 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 `@src/lab/artifacts/sanitize.ts`:
- Around line 11-12: Derive SECRETISH_GLOBAL from the single-match SECRETISH
pattern instead of duplicating the regular-expression source, while preserving
the global flag and existing non-global SECRETISH behavior used by
assertNoSecretMaterial.

In `@src/lab/fabric/executor.ts`:
- Around line 128-140: Update the deprecated runFabricSyntheticPatchTask
wrapper’s parameter type to use Omit<RunFabricTaskHarnessOptions, "harnessKind">
while retaining producePatch?: never, so harnessKind can be omitted and the
existing "deterministic_correct" fallback remains effective.

In `@src/lab/fabric/observe.ts`:
- Around line 441-454: Remove the exported authority-free persistence path by
making persistFabricOutcome private or requiring a host-branded trusted result
at its boundary. Update persistFabricRunResult to use that trusted path, and
route any required harness persistence through a separate non-production API so
runFabricSyntheticPatchTaskHarness output cannot write production
compatibility.jsonl. Add a regression test covering direct harness output
rejection.

In `@src/lab/fabric/producer-child.ts`:
- Around line 77-80: Replace the interval callback throw in
src/lab/fabric/producer-child.ts:77-80 with a rejecting timeout promise, race it
against mod.execute(input), clear the interval in finally, and return the
structured inactivity_timeout response. Update
tests/lab-fabric-task.test.ts:462-473 to assert result.outcome.failure?.code
equals "inactivity_timeout".
- Around line 51-57: Scope the declarations inside the "mutate_after_delay"
branch by wrapping that case’s statements in a block, including the dynamically
imported filesystem and path symbols. Preserve the existing delay, directory
creation, file write, and correctPatch() return behavior.

In `@src/lab/fabric/producer-isolate.ts`:
- Around line 104-118: The producer isolate cannot transmit reportActivity or
AbortSignal through JSON.stringify. In src/lab/fabric/producer-isolate.ts lines
104-118, either implement newline-delimited activity frames on child stdout and
consume them before the final result, or remove reportActivity and signal from
FabricPatchExecutorInput; in src/lab/fabric/executor.ts lines 204-225, align
lastActivityAt and controller.abort() with that chosen contract, using a real
timeout path or removing the controller; update the inactivity accounting
description in
devlog/_plan/260807_compatibility_lab/007_cl07_task_effectiveness.md lines
260-262 to match the implemented behavior.
- Around line 55-57: Bound stdout accumulation in the child.stdout data handler
using FABRIC_LIMITS.maxAggregateIoBytes, tracking byte length rather than string
characters; once the limit is exceeded, stop accepting further output and
terminate the child process early while preserving the existing result/error
handling path.
- Around line 119-120: Attach an error handler to child.stdin before writing
payload in the producer flow: ignore EPIPE errors and pass all other stream
errors to finish. Keep the existing child.on("error") handling and stdin
write/end sequence unchanged.
- Around line 30-53: Update runIsolatedFabricProducer to enforce
inactivity_timeout in the parent: add an explicit child-to-parent activity
heartbeat, handle heartbeat messages separately from the final result, and reset
a parent-side inactivity timer on each heartbeat. Do not use stdout chunks to
reset inactivity, and ensure the timer rejects with FabricTaskError using the
inactivity_timeout classification when heartbeats stop.

In `@src/lab/fabric/verifier.ts`:
- Around line 99-104: Remove the no-op try/catch wrapper surrounding the
verifier logic in the function containing the FabricTaskError check; delete the
redundant instanceof branch and matching try/catch, then de-indent the body so
errors propagate directly. Leave error classification to the
verifyExactTreeDiffV1 call site in the executor.

In `@tests/helpers/fabric-task-test.ts`:
- Around line 65-91: The fabricRouteBoundPatchExecutor helper currently writes
generated modules into the repository and reuses provider-specific filenames.
Add a temporary-home argument, create the generated executor module beneath that
directory using a unique or isolated path, and update its callers to provide the
test home. Align cleanup with fabricWrongPatchExecutor and
fabricOversizedPatchExecutor so the generated directory is removed during test
teardown.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ba3a6c8a-2143-4ac8-aa4b-7c3b7e5c7fe5

📥 Commits

Reviewing files that changed from the base of the PR and between f45cefc and 34777e6.

📒 Files selected for processing (14)
  • devlog/_plan/260807_compatibility_lab/007_cl07_task_effectiveness.md
  • src/lab/artifacts/sanitize.ts
  • src/lab/fabric/executor.ts
  • src/lab/fabric/index.ts
  • src/lab/fabric/observe.ts
  • src/lab/fabric/producer-child.ts
  • src/lab/fabric/producer-isolate.ts
  • src/lab/fabric/types.ts
  • src/lab/fabric/verifier.ts
  • src/lib/fabric-task-execution-authority.ts
  • src/lib/fabric-task-host.ts
  • tests/fixtures/fabric-executors/correct-patch.ts
  • tests/helpers/fabric-task-test.ts
  • tests/lab-fabric-task.test.ts

Comment thread src/lab/artifacts/sanitize.ts Outdated
Comment thread src/lab/fabric/executor.ts
Comment thread src/lab/fabric/observe.ts
Comment thread src/lab/fabric/producer-child.ts Outdated
Comment thread src/lab/fabric/producer-child.ts Outdated
Comment thread src/lab/fabric/producer-isolate.ts Outdated
Comment thread src/lab/fabric/producer-isolate.ts
Comment thread src/lab/fabric/producer-isolate.ts Outdated
Comment thread src/lab/fabric/verifier.ts Outdated
Comment thread tests/helpers/fabric-task-test.ts Outdated
Wibias added 2 commits August 11, 2026 02:21
Seal production task-effectiveness ingestion behind persistFabricRunResult, add parent-owned NDJSON child IPC with bounded protocol output, and move timeout authority to the parent with deterministic classification tests.
@Wibias
Wibias merged commit 02e62fc into dev Aug 11, 2026
55 of 60 checks passed
Wibias added a commit that referenced this pull request Aug 11, 2026
Back up Compatibility Lab CL-07 closure on dev at merge 02e62fc with accepted head 0efe2c6.
@Wibias
Wibias deleted the feat/cl-07-task-effectiveness-producer branch August 11, 2026 02:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant