Skip to content

Phase 1 — 1.L.0: reconcile @relavium/shared to the 2026-06-05 contracts (+ sequencing plan)#6

Merged
cemililik merged 5 commits into
mainfrom
development
Jun 5, 2026
Merged

Phase 1 — 1.L.0: reconcile @relavium/shared to the 2026-06-05 contracts (+ sequencing plan)#6
cemililik merged 5 commits into
mainfrom
development

Conversation

@cemililik

@cemililik cemililik commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

First Phase-1 workstream. Brings @relavium/shared up to the agent-first + hardening
contracts (ADR-0024/0026/0027/0028/0029) that landed the day after the Phase-0 freeze, and
adds the Phase-1 execution-order plan. Additive, plus a few v1.0 tightenings — no engine
behavior
(@relavium/shared only, plus docs).

Commits

  • 2bda8d6 docs(roadmap): Phase-1 sequencing & parallelization plan — three lanes behind the 1.L.0 gate, the 1.O join, an ordered wave table, and a 31-row dependency matrix.
  • 45349cd feat(shared): 1.L.0 reconciliation — the schema catch-up.
  • 81728b5 fix(shared): address the two code reviews (the run/session correlation-key BLOCKER + 5 findings).

What changed (1.L.0)

Run/session events (run-event.ts ← sse-event-schema.md): run/session/dual envelope with exactly one of runId/sessionId enforced at the union level; the 5 missing run events (13→18); the SessionEvent union (5 session:*) + SessionContextSchema; the closed ErrorCode enum bound to node:failed/run:failed/session:turn_completed/RunSchema.error; retryable; attemptNumber?; StopReasonSchema (canonical home — the seam re-exports it).

Authored YAML (workflow.ts, node.ts ← workflow-yaml-spec.md): metadata, budget/timeout_ms/max_parallel, allowedCommandGlobs, WorkflowInput.validation, system_prompt_append, agent/transform output_schema. Reserved values now rejected at parse: expression_typejs, timeout_actionreject/approve.

Config (config.ts ← config-spec.md): defaults.max_tokens_estimate + the [chat] block.

Review handling

  • 🔴 BLOCKER (dual events accepted neither/both correlation keys) → enforced via a union-level .superRefine (a discriminatedUnion member can't be refined, but the union can); .innerType() for the count test; neither/both reject tests.
  • 5 findings addressed or tracked: comment-softening (×2), the condition/output_schema spec fix, config-strictness parity (deferred), the agent-session "validated by" clarification.
  • Verified by a 3-skeptic adversarial workflow (xor correctness, findings completeness, regressions) — all confirmed.

Conformance

  • TypeScript-first, strict; no any/unsafe as
  • No vendor SDK type crosses the @relavium/llm seam (fence airtight; StopReason/ContentPart kept shared-owned)
  • No new runtime dependency
  • No secret in any event payload / error message (ErrorCode is a closed generic-cause enum)
  • Canonical colon-namespaced event names + sequenceNumber
  • Canonical-home docs consistent with the schema (workflow-yaml-spec / agent-session-spec clarified)
  • pnpm turbo run lint typecheck test build green · 156 shared tests · format clean · seam fence airtight · no DB migration drift (run_events.event_type is unconstrained text)

Notes

  • No migration needed; the count-pinned unit test (13→18) is the enforcement, not the drift gate.
  • Deferred (tracked in docs/roadmap/deferred-tasks.md): config-schema strictness parity; codifying ContentPart's canonical home in the seam doc at 1.V/1.X.
  • SessionMessageSchema/AgentSessionSchema deliberately deferred to the agent-first sub-spine (1.V/1.X) — they reference the seam's ContentPart, which lands with 1.A.

Refs: ADR-0023, ADR-0024, ADR-0026, ADR-0027, ADR-0028, ADR-0029

🤖 Generated with Claude Code

Summary by Sourcery

Reconcile the shared contracts with the latest agent-first and hardening ADRs, extending run/session event schemas, workflow YAML, and config to support governance and agent-session use cases while adding a Phase-1 execution sequencing plan.

New Features:

  • Introduce session event schemas and shared session context for agent sessions, including dual-use events shared with run streams.
  • Add new run and budget governance events, extended error taxonomy, stop-reason vocabulary, and attempt tracking across tool and node execution.
  • Extend workflow YAML with metadata, resource-governance (budget, timeout, max_parallel), input validation, tool-policy globs, and node-level output schemas and prompts.
  • Add chat-mode configuration and project defaults for agent sessions, including fs_scope and pre-egress cost caps.

Bug Fixes:

  • Enforce exactly-one correlation key for dual run/session events and bind run and node errors to a closed ErrorCode taxonomy with retryability.

Enhancements:

  • Align node expression types, gate timeout actions, and shared enums with the v1.0 contracts, rejecting reserved values at parse time.
  • Refine run and session schemas to share canonical enums for filesystem scope tiers, stop reasons, and on-exceed actions.
  • Harden tests around event coverage, error handling, budgeting, and configuration to pin behavior to the updated contracts.

Documentation:

  • Add a Phase-1 sequencing and parallelization plan for engine and LLM workstreams, including lane structure, waves, and dependency matrix updates.
  • Clarify workflow, agent-session, and seam documentation to reflect new metadata, output-schema, and session-schema staging, and record deferred follow-ups in the roadmap.

Tests:

  • Expand run-event and session-event tests to cover new event types, correlation invariants, error taxonomy, and attempt-number semantics.
  • Add workflow, node, config, and run schema tests for metadata round-tripping, resource governance, validation strictness, and reserved-field enforcement.

Chores:

  • Record deferred tasks for config strictness and ContentPart ownership in the roadmap to track future hardening work.

Summary by CodeRabbit

  • New Features

    • Chat defaults config (model, filesystem-scope tiers, message/cost limits, approval actions).
    • Workflow governance: budget, timeout, max-parallel, per-input validation (format/pattern/enum/numeric/length).
    • Tool policies accept glob patterns; agent and transform nodes may emit optional output schemas.
    • New session/run event types (file-patch proposals, pauses, timeouts, budget alerts) and tightened error-code taxonomy.
  • Documentation

    • Clarified workflow YAML node behaviors and SSE event payloads (non-empty patches, output_schema usage).
  • Tests

    • Expanded coverage across configs, workflows, nodes, run/session events.

cemililik and others added 3 commits June 5, 2026 13:40
The phase doc had a per-workstream logical DAG (Work breakdown) and a Milestones
table, but no explicit execution-order view. Add a "Sequencing & parallelization"
section between them that answers: what order to build in, what blocks what, and
what runs concurrently.

- Three lanes behind one gate: 1.L.0 (do first) → Lane A (@relavium/llm, the binding
  critical path), Lane B (@relavium/core, concurrent), Lane C (agent-first sub-spine,
  additive — never gates M2).
- The one scheduling insight: Lane B sprints ahead to 1.N/1.R then idles at the 1.O
  JOIN until Lane A delivers 1.K (which needs M1), so wall-clock to M2 is Lane A's length.
- A complete lanes Mermaid (incl. 1.L.0, 1.L2, and 1.V–1.AA — which the Work-breakdown
  DAG omits), an ordered wave table (W0–W4 + Lane C), and a 31-row dependency matrix
  (depends-on / enables / on-the-M2-path).
- Solo vs. two-track build guidance; a reconciliation note vs. the inline *critical path*
  tags. Single home for the execution plan — links to, not restates, the DAG/milestones.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(1.L.0)

Phase-1 workstream 1.L.0 — make the Zod schema set match the agent-first + hardening
contracts (ADR-0024/0026/0027/0028/0029) that landed after the Phase-0 freeze.
Additive, plus a few v1.0 tightenings; no engine behavior.

Run/session events (run-event.ts ← sse-event-schema.md):
- Split the base envelope into run / session / dual: run events require `runId`,
  session events require `sessionId`, the four reused events (agent:token / tool_call /
  tool_result / cost:updated) carry either. "Exactly one" is an emit-time invariant
  (a discriminatedUnion member cannot carry a cross-field refinement).
- Add the 5 missing run events: run:paused, run:timeout, budget:warning, budget:paused,
  agent:file_patch_proposed (13 -> 18; count test updated).
- Add the SessionEvent union (5 session:* variants) + SessionContextSchema.
- Add the closed ErrorCode enum; bind node:failed / run:failed / session:turn_completed /
  RunSchema.error to it; add `retryable` to run:failed + RunSchema.error. Add attemptNumber?
  to agent:tool_call / tool_result / node:completed. Define StopReasonSchema (canonical
  home; the @relavium/llm seam re-exports it).

Authored YAML (workflow.ts, node.ts <- workflow-yaml-spec.md):
- workflow.metadata (ADR-0026 export transcript), budget / timeout_ms / max_parallel
  (ADR-0028), tools.allowedCommandGlobs (ADR-0029), WorkflowInput.validation,
  agent.system_prompt_append, agent/transform output_schema.
- Drop reserved enum members so an authored value is rejected at parse: expression_type
  -> js only (jmespath/jsonlogic reserved), timeout_action -> reject/approve (escalate reserved).

Config (config.ts <- config-spec.md): defaults.max_tokens_estimate + the [chat] block.

+26 shared tests (130 -> 156). No migration (run_events.event_type is unconstrained text);
tsc, the seam fence, and the db drift gate stay green.

Flagged: workflow-yaml-spec.md says output_schema is "(also on transform / condition)"; the
1.L.0 task scopes it to agent/transform, so condition is omitted — a minor spec
inconsistency for the maintainer to resolve.

Refs: ADR-0024, ADR-0026, ADR-0027, ADR-0028, ADR-0029

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…L.0 review

Two reviews of the 1.L.0 reconciliation. The BLOCKER: the four dual-envelope events
(agent:token / tool_call / tool_result / cost:updated) declared both runId and sessionId
optional, so RunEventSchema accepted payloads with neither or both — violating the canonical
"exactly one" rule (sse-event-schema.md §"Correlation key").

- Enforce the invariant at the UNION level: RunEventSchema is now the discriminated union
  wrapped in a .superRefine requiring exactly one of runId / sessionId. (A discriminatedUnion
  *member* can't carry a cross-field refinement, but the union can.) Run-only / session-only
  events satisfy it by construction; the refine only constrains the four dual events. The
  count test reaches the raw union via RunEventSchema.innerType().options. New tests: neither
  and both are rejected (asserting the error is on the correlation key), each of run/session
  flavor accepted.
- Document the deliberate input-leniency: a stray opposite key on a run-only/session-only
  event is stripped by its z.object before the refine runs, so the parsed output stays
  compliant (the non-strict, forward-compatible posture) — recorded, not an oversight.
- Soften the dualBase comment (a union-level refine IS feasible) and the SessionContext
  comment (ContentPart must be shared-owned + seam-re-exported, never imported by shared from
  llm — the dependency must not invert).

Docs (keep the canonical specs consistent with the shared code):
- workflow-yaml-spec.md: drop "/ condition" from the output_schema note — a condition node
  selects a branch, it has no shaped output; the schema scopes output_schema to agent/transform.
- agent-session-spec.md: clarify that only SessionContextSchema lands in 1.L.0;
  SessionMessageSchema / AgentSessionSchema land with the sub-spine (1.V/1.X).
- deferred-tasks.md: track config-schema strictness parity, and codifying ContentPart's
  canonical home in the seam doc at 1.V/1.X.

Verified by a 3-skeptic adversarial workflow (xor correctness, findings completeness,
regressions): the fix holds, no finding dropped, no regression. Full gate green; +xor tests
(156 shared tests); seam fence + db drift gate unchanged.

Refs: ADR-0011, ADR-0024, ADR-0026

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Reviewer's Guide

Reconciles @relavium/shared contracts to the 2026-06-05 ADRs by restructuring run/session event envelopes with strict correlation-key invariants, introducing new governance and session event types, tightening error and budget taxonomies, and extending workflow/node/config schemas for agent-first and resource-governance features, plus documenting the Phase-1 execution sequencing plan.

File-Level Changes

Change Details Files
Refactor run and session event schemas to support dual run/session correlation, new event types, and a closed error/stop-reason taxonomy with validation tests.
  • Split the base run-event envelope into run-only, session-only, and dual variants with shared timestamp/sequence fields and export a non-strict BaseEventSchema
  • Introduce ErrorCodeSchema, StopReasonSchema, SessionContextSchema, and session event union schemas with corresponding TypeScript types
  • Extend run event union with new events (governance, budgeting, file patch proposal) and wrap it in a superRefine enforcing exactly one of runId/sessionId for dual-envelope events
  • Update run-event tests to cover the expanded event set, correlation-key invariants, ErrorCode/attemptNumber behavior, and add a separate SessionEvent test matrix
packages/shared/src/run-event.ts
packages/shared/src/run-event.test.ts
Extend shared constants with new event namespaces and governance enums reused across run/session, workflow, and config schemas.
  • Add RUN_EVENT_TYPES entries for new events and introduce SESSION_EVENT_TYPES, ERROR_CODES, STOP_REASONS, FS_SCOPE_TIERS, and ON_EXCEED_ACTIONS enums with typed aliases
  • Document the relationship between these enums and their consumers (run events, session events, workflow budgets, config fs_scope and on_exceed)
packages/shared/src/constants.ts
Add workflow-level metadata, tool/budget guardrails, and input validation to align authored YAML with ADR-0026/0028/0029.
  • Introduce InputValidationSchema and wire it into WorkflowInputSchema as an optional validation block
  • Extend WorkflowSpecSchema with metadata, budget, timeout_ms, and max_parallel fields using a new BudgetSchema and ON_EXCEED_ACTIONS enum
  • Strengthen ToolPolicySchema and tests to support allowedCommandGlobs and validate tool/budget/validation behavior including strictness on unknown keys
packages/shared/src/workflow.ts
packages/shared/src/workflow.test.ts
Tighten node schemas around expression types, gate timeout actions, and node-level output schema support for agents and transforms.
  • Restrict ExpressionTypeSchema to js only and adjust docs to clarify that condition nodes no longer carry output_schema
  • Constrain TimeoutActionSchema to reject reserved escalate and document timeout handling semantics
  • Add OutputSchemaSchema and hook system_prompt_append and output_schema into agent and transform node schemas with tests for reserved expression_type values and new fields
packages/shared/src/node.ts
packages/shared/src/node.test.ts
docs/reference/contracts/workflow-yaml-spec.md
Extend project/global configuration schemas to support agent-first chat defaults and budget estimation while noting deferred strictness decisions.
  • Derive FsScopeSchema from shared FS_SCOPE_TIERS and add ChatConfigSchema with chat-specific defaults including max_cost_microcents/on_exceed
  • Extend ProjectConfigSchema defaults with max_tokens_estimate and wire in the optional chat block, with tests for valid/invalid max_tokens_estimate and chat.on_exceed values
  • Document config strictness parity as a deferred decision in the roadmap/deferred-tasks doc
packages/shared/src/config.ts
packages/shared/src/config.test.ts
docs/roadmap/deferred-tasks.md
Align RunSchema error handling with the closed ErrorCode taxonomy and retryable semantics used by run events.
  • Swap RunSchema.error.code to use ErrorCodeSchema, add a required retryable field, and update tests to assert the closed taxonomy and retryable requirement
packages/shared/src/run.ts
packages/shared/src/run.test.ts
Document Phase-1 engine/LLM sequencing, parallelization, and dependencies with a unified execution plan.
  • Add a sequencing & parallelization section describing the three post-1.L.0 lanes, the join at 1.O, ordered waves, and a dependency matrix with critical-path markings
  • Clarify solo vs multi-track execution strategies and reconcile per-workstream critical-path tags with the consolidated plan
docs/roadmap/phases/phase-1-engine-and-llm.md
Clarify agent-session spec ownership and landing phases for session-related schemas and ContentPart.
  • Update agent-session-spec to state which schemas land in 1.L.0 vs 1.V/1.X and to note ContentPart ownership and its relation to the seam
  • Align this documentation with new comments in run-event.ts regarding SessionContextSchema and future session schema placement
docs/reference/contracts/agent-session-spec.md

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

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f12c99fb-0a72-43ad-9833-40a46b831a21

📥 Commits

Reviewing files that changed from the base of the PR and between 3eac2f3 and 73800ee.

📒 Files selected for processing (7)
  • docs/roadmap/deferred-tasks.md
  • docs/roadmap/phases/phase-1-engine-and-llm.md
  • packages/shared/src/config.test.ts
  • packages/shared/src/constants.ts
  • packages/shared/src/node.ts
  • packages/shared/src/run-event.test.ts
  • packages/shared/src/run.test.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/roadmap/deferred-tasks.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/shared/src/run.test.ts
  • packages/shared/src/config.test.ts
  • docs/roadmap/phases/phase-1-engine-and-llm.md
  • packages/shared/src/node.ts

📝 Walkthrough

Walkthrough

Expands shared Zod schemas: adds dual-correlation run/session event envelopes and closed error/stop vocabularies; tightens run error shapes; adds node output-schema support; extends workflow input validation, tool globs, and budget controls; adds config chat defaults; and updates tests and docs.

Changes

Documentation and Roadmap

Layer / File(s) Summary
Spec clarifications and workflow YAML note
docs/reference/contracts/agent-session-spec.md, docs/reference/contracts/workflow-yaml-spec.md, docs/reference/contracts/sse-event-schema.md
Maps agent-session schemas to their shared locations; clarifies output_schema applies to transform nodes and not to condition nodes; documents agent:file_patch_proposed.patches must be non-empty.
Roadmap decisions and Phase 1 scheduling
docs/roadmap/deferred-tasks.md, docs/roadmap/phases/phase-1-engine-and-llm.md
Adds four maintainer decision checklist entries and inserts a Phase 1 sequencing/parallelization section with lanes, join dependency, wave build order, and dependency matrix.

Shared Package Schemas: Constants, Nodes, Events, Workflow, Config, and Tests

Layer / File(s) Summary
Constants: event & governance vocabularies
packages/shared/src/constants.ts
Adds/extends canonical tuples and derived union types: extends RUN_EVENT_TYPES, and adds SESSION_EVENT_TYPES, ERROR_CODES, STOP_REASONS, FS_SCOPE_TIERS, and ON_EXCEED_ACTIONS.
Node schema: expression/timeout restrictions and output_schema
packages/shared/src/node.ts, packages/shared/src/node.test.ts
Restricts expression language to js, reduces timeout actions to reject/approve, introduces OutputSchemaSchema, and adds optional output_schema to Agent and Transform nodes with tests.
Config: chat defaults and FsScope derivation
packages/shared/src/config.ts, packages/shared/src/config.test.ts
Imports validators/constants, derives FsScopeSchema from FS_SCOPE_TIERS, adds exported ChatConfigSchema, extends ProjectConfigSchema with top-level chat and optional defaults.max_tokens_estimate, and adds tests.
Run/Session event envelope and error taxonomy
packages/shared/src/run-event.ts
Rewires base envelope to a dual-correlation model (optional runId/sessionId), introduces ErrorCodeSchema, StopReasonSchema, SessionContextSchema, adds agent:file_patch_proposed and new run/budget lifecycle event schemas, and changes RunEventSchema to enforce exactly one correlation key.
Run schema: error shape tightening
packages/shared/src/run.ts, packages/shared/src/run.test.ts
RunSchema.error.code now uses ErrorCodeSchema; error.retryable is required; error.nodeId tightened to non-empty string; tests updated accordingly.
Run & Session event tests and invariants
packages/shared/src/run-event.test.ts
Expands run-event variants (now 18), adds session-event suite (five session:* names), pins canonical event-name list, and adds cross-event invariants and negative tests (e.g., empty patches).
Workflow schema: input validation, tool globs, and budget controls
packages/shared/src/workflow.ts, packages/shared/src/workflow.test.ts
Adds InputValidationSchema with bound-consistency superRefine, wires optional validation into WorkflowInputSchema, extends ToolPolicySchema with allowedCommandGlobs, adds BudgetSchema, and workflow-level metadata, budget, timeout_ms, and max_parallel; tests added.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • HodeTech/Relavium#2: touches SSE run-event contract areas such as attemptNumber and related event tests.

Poem

🐰 With dual-key envelopes and error codes sealed tight,
Session events hop alongside runs through the night,
Nodes learn to shape outputs, workflows count their cost,
Constants line up neatly — nothing lost!
A tiny rabbit cheers the shared schema's new light.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: reconciling @relavium/shared to 2026-06-05 contracts as Phase 1 milestone 1.L.0, plus adding a sequencing plan. It is specific, relates directly to the changeset, and conveys the primary objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch development

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request reconciles the @relavium/shared package schemas with the latest specifications, introducing support for agent sessions, closed error code taxonomies, resource-governance budgets, and input validation rules. It also updates documentation and tests to align with these schema additions. The reviewer feedback suggests enhancing schema validation strictness by ensuring logical bounds on line selections and input validation limits, requiring at least one patch in proposed file events, and validating that allowed domains are exact FQDNs.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +88 to +97
export const SessionContextSchema = z.object({
workingDir: nonEmptyString,
activeFile: nonEmptyString.optional(),
selection: z
.object({ file: nonEmptyString, startLine: nonNegativeInt, endLine: nonNegativeInt })
.optional(),
gitRef: nonEmptyString.optional(),
fsScopeTier: z.enum(FS_SCOPE_TIERS),
variables: z.record(z.string(), z.string()).optional(),
});

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

The selection object in SessionContextSchema defines startLine and endLine as non-negative integers. However, there is no validation ensuring that startLine is less than or equal to endLine. Adding a refinement prevents logical errors where a selection's start line exceeds its end line.

export const SessionContextSchema = z.object({
  workingDir: nonEmptyString,
  activeFile: nonEmptyString.optional(),
  selection: z
    .object({ file: nonEmptyString, startLine: nonNegativeInt, endLine: nonNegativeInt })
    .superRefine((val, ctx) => {
      if (val.startLine > val.endLine) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'startLine must be <= endLine',
          path: ['startLine'],
        });
      }
    })
    .optional(),
  gitRef: nonEmptyString.optional(),
  fsScopeTier: z.enum(FS_SCOPE_TIERS),
  variables: z.record(z.string(), z.string()).optional(),
});

Comment on lines +145 to 152
export const AgentFilePatchProposedEventSchema = z.object({
type: z.literal('agent:file_patch_proposed'),
...runBase,
nodeId: nonEmptyString,
// Gated — no write until the user accepts (e.g. the VS Code inline-diff review).
patches: z.array(z.object({ uri: nonEmptyString, unifiedDiff: z.string() })),
attemptNumber: positiveInt.optional(),
});

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

The patches array in AgentFilePatchProposedEventSchema is currently allowed to be empty. Proposing an event with zero patches is logically invalid. Adding a .min(1) constraint ensures that at least one file patch is proposed, aligning with other non-empty array schemas like RunPausedEventSchema.gateIds.

Suggested change
export const AgentFilePatchProposedEventSchema = z.object({
type: z.literal('agent:file_patch_proposed'),
...runBase,
nodeId: nonEmptyString,
// Gated — no write until the user accepts (e.g. the VS Code inline-diff review).
patches: z.array(z.object({ uri: nonEmptyString, unifiedDiff: z.string() })),
attemptNumber: positiveInt.optional(),
});
export const AgentFilePatchProposedEventSchema = z.object({
type: z.literal('agent:file_patch_proposed'),
...runBase,
nodeId: nonEmptyString,
// Gated — no write until the user accepts (e.g. the VS Code inline-diff review).
patches: z.array(z.object({ uri: nonEmptyString, unifiedDiff: z.string() })).min(1),
attemptNumber: positiveInt.optional(),
});

Comment thread packages/shared/src/workflow.ts Outdated
Comment on lines +65 to +75
export const InputValidationSchema = z
.object({
format: nonEmptyString.optional(), // e.g. 'email'
pattern: nonEmptyString.optional(), // a regex source
enum: z.array(z.unknown()).optional(),
min: z.number().optional(),
max: z.number().optional(),
min_length: nonNegativeInt.optional(),
max_length: nonNegativeInt.optional(),
})
.strict();

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

The InputValidationSchema defines optional min/max and min_length/max_length fields, but does not validate their logical relationships. Adding a refinement ensures that min is less than or equal to max, and min_length is less than or equal to max_length, preventing invalid validation rules from being declared.

export const InputValidationSchema = z
  .object({
    format: nonEmptyString.optional(), // e.g. 'email'
    pattern: nonEmptyString.optional(), // a regex source
    enum: z.array(z.unknown()).optional(),
    min: z.number().optional(),
    max: z.number().optional(),
    min_length: nonNegativeInt.optional(),
    max_length: nonNegativeInt.optional(),
  })
  .strict()
  .superRefine((val, ctx) => {
    if (val.min !== undefined && val.max !== undefined && val.min > val.max) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'min must be <= max',
        path: ['min'],
      });
    }
    if (val.min_length !== undefined && val.max_length !== undefined && val.min_length > val.max_length) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'min_length must be <= max_length',
        path: ['min_length'],
      });
    }
  });

Comment on lines 104 to 110
export const ToolPolicySchema = z
.object({
allowedCommands: z.array(nonEmptyString).optional(),
allowedCommandGlobs: z.array(nonEmptyString).optional(),
allowedDomains: z.array(nonEmptyString).optional(),
})
.strict();

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

The allowedDomains field in ToolPolicySchema is intended to be an exact-FQDN allowlist. However, users might mistakenly include protocols (e.g., https://) or paths (e.g., /v1). Adding a refinement to validate that the domains do not contain slashes, colons, or start with http prevents runtime matching failures.

export const ToolPolicySchema = z
  .object({
    allowedCommands: z.array(nonEmptyString).optional(),
    allowedCommandGlobs: z.array(nonEmptyString).optional(),
    allowedDomains: z
      .array(
        nonEmptyString.refine((dom) => !dom.includes('/') && !dom.includes(':') && !dom.startsWith('http'), {
          message: 'allowedDomains must be exact FQDNs (no protocol, port, or path)',
        }),
      )
      .optional(),
  })
  .strict();

@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 2 issues

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

## Individual Comments

### Comment 1
<location path="packages/shared/src/workflow.ts" line_range="119-122" />
<code_context>
+ * (integer micro-cents) and applies `on_exceed`. The whole-run `timeout_ms` and the concurrency
+ * cap `max_parallel` live alongside `budget` on the workflow spec.
+ */
+export const BudgetSchema = z
+  .object({
+    max_cost_microcents: nonNegativeInt,
+    on_exceed: z.enum(ON_EXCEED_ACTIONS),
+  })
+  .strict();
</code_context>
<issue_to_address>
**question:** Clarify whether a zero budget is valid and, if not, tighten the type

`max_cost_microcents` currently uses `nonNegativeInt`, so `0` is allowed. For workflows, is `0` intended as “no budget” or should it be rejected as invalid? `ChatConfigSchema` documents `0/absent` as unbounded, but there’s no similar note here. If `0` isn’t a meaningful value for workflow budgets, consider using `positiveInt` instead, or document the intended semantics to avoid inconsistent expectations between chat and workflow budgets.
</issue_to_address>

### Comment 2
<location path="docs/roadmap/deferred-tasks.md" line_range="75-79" />
<code_context>
+  never imported by shared from llm — which would invert the package dependency. The seam doc
+  ([llm-provider-seam.md](../reference/shared-core/llm-provider-seam.md)) currently shows
+  `ContentPart` only as a TS shape with no ownership statement; codify it there so the code
+  comment in `run-event.ts` and the spec stay aligned. *(nit → 1.V/1.X · llm-provider-seam.md)*

 ## Test depth
</code_context>
<issue_to_address>
**nitpick (typo):** Fix subject–verb agreement in "the spec stay aligned."

This should be “the spec stays aligned” to agree with the singular subject (“so the code comment in `run-event.ts` and the spec stays aligned”).

```suggestion
  `@relavium/shared`** and re-exported by the `@relavium/llm` seam (the `StopReason` precedent),
  never imported by shared from llm — which would invert the package dependency. The seam doc
  ([llm-provider-seam.md](../reference/shared-core/llm-provider-seam.md)) currently shows
  `ContentPart` only as a TS shape with no ownership statement; codify it there so the code
  comment in `run-event.ts` and the spec stays aligned. *(nit → 1.V/1.X · llm-provider-seam.md)*
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread packages/shared/src/workflow.ts
Comment thread docs/roadmap/deferred-tasks.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
packages/shared/src/run-event.test.ts (1)

197-200: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the partialOutputs negative case single-cause.

This payload now also violates the closed error.code and required retryable rules, so it no longer proves that partialOutputs is required. Use a valid error object here to keep that contract covered.

🧪 Proposed fix
   'run:failed (missing partialOutputs)': {
     type: 'run:failed',
     ...env,
-    error: { code: 'E', message: 'm' },
+    error: { code: 'internal', message: 'm', retryable: false },
   },
🤖 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 `@packages/shared/src/run-event.test.ts` around lines 197 - 200, The failing
negative test case labeled 'run:failed (missing partialOutputs)' currently uses
an error object that also violates the closed error.code and missing retryable
rules; update the error payload in that test to be a valid error object (include
a permitted code string and the required retryable boolean plus message) so the
test only asserts the absence of partialOutputs, e.g. change the error value
used in that case inside run-event.test.ts to a compliant error shape.
🧹 Nitpick comments (2)
packages/shared/src/run-event.ts (1)

339-352: ⚡ Quick win

Export a schema for the complete session stream.

SessionEventSchema currently covers only the session:* lifecycle variants, but the shared turn events (agent:token, agent:tool_call, agent:tool_result, cost:updated) are still session-correlated. Without a first-class union here, downstream code has to duplicate this composition or parse session traffic with RunEventSchema, which also accepts run-only variants.

♻️ Proposed addition
 export const SessionEventSchema = z.discriminatedUnion('type', [
   SessionStartedEventSchema,
   SessionTurnStartedEventSchema,
   SessionTurnCompletedEventSchema,
   SessionCancelledEventSchema,
   SessionExportedEventSchema,
 ]);
 export type SessionEvent = z.infer<typeof SessionEventSchema>;
+
+export const SessionStreamEventSchema = z.union([
+  SessionEventSchema,
+  AgentTokenEventSchema,
+  AgentToolCallEventSchema,
+  AgentToolResultEventSchema,
+  CostUpdatedEventSchema,
+]);
+export type SessionStreamEvent = z.infer<typeof SessionStreamEventSchema>;
🤖 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 `@packages/shared/src/run-event.ts` around lines 339 - 352, SessionEventSchema
only includes the five session:* lifecycle schemas but must also include the
shared turn event schemas so downstreams can parse a full session stream; update
the discriminated union for SessionEventSchema to include the four shared turn
schemas (e.g., AgentTokenEventSchema, AgentToolCallEventSchema,
AgentToolResultEventSchema, CostUpdatedEventSchema—or the exact names used in
the file) alongside SessionStartedEventSchema, SessionTurnStartedEventSchema,
SessionTurnCompletedEventSchema, SessionCancelledEventSchema, and
SessionExportedEventSchema, then keep exporting the inferred SessionEvent type
so it represents the complete session stream.
packages/shared/src/workflow.test.ts (1)

356-377: ⚡ Quick win

Add regression cases for semantic validation failures.

These tests only cover the happy path and unknown-key strictness. Please also lock down contradictory bounds and type-incompatible validation blocks so the new contract doesn't regress once the schema is tightened.

🤖 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 `@packages/shared/src/workflow.test.ts` around lines 356 - 377, Add tests to
cover semantic validation failures by extending workflow.test.ts: use the
existing accepts and withWorkflow helpers to assert that validation objects with
contradictory bounds (e.g., validation: { min: 10, max: 5 } on an input like
name: 'sev', type: 'number') are rejected, and that type-incompatible validation
keys are rejected (e.g., apply string-only keys like format or max_length to a
number input, or numeric keys like min/max to a string input). Place these new
expect(...).toBe(false) cases next to the existing tests so
accepts(withWorkflow({...})) returns false for both contradictory min/max and
mismatched validation-key vs input type.
🤖 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 `@packages/shared/src/run.ts`:
- Around line 56-62: The error object schema currently allows an empty nodeId
(nodeId: z.string().optional()); change it to use the same non-empty identifier
contract as the rest of the package (e.g., replace with
nonEmptyString().optional() or z.string().min(1).optional() using the existing
nonEmptyString helper) inside the error schema and make the identical change in
RunFailedEventSchema.error.nodeId so both contracts remain aligned with
ErrorCodeSchema and other node id validations.

In `@packages/shared/src/workflow.ts`:
- Around line 65-85: Add schema-level validations to reject contradictory or
type-incompatible constraints: update InputValidationSchema to include
refinements that enforce numeric bounds (if both min and max are present,
require min <= max) and length bounds (if both min_length and max_length are
present, require min_length <= max_length), and update WorkflowInputSchema to
superRefine the pair (type, validation) so string-only constraints (format,
pattern, min_length, max_length) are only allowed when the declared
InputTypeSchema corresponds to a string-type; use z.refine/z.superRefine on
InputValidationSchema and WorkflowInputSchema respectively, referencing the
existing symbols InputValidationSchema, WorkflowInputSchema, validation, min,
max, min_length, max_length, format, and pattern to find where to add the
checks.

---

Outside diff comments:
In `@packages/shared/src/run-event.test.ts`:
- Around line 197-200: The failing negative test case labeled 'run:failed
(missing partialOutputs)' currently uses an error object that also violates the
closed error.code and missing retryable rules; update the error payload in that
test to be a valid error object (include a permitted code string and the
required retryable boolean plus message) so the test only asserts the absence of
partialOutputs, e.g. change the error value used in that case inside
run-event.test.ts to a compliant error shape.

---

Nitpick comments:
In `@packages/shared/src/run-event.ts`:
- Around line 339-352: SessionEventSchema only includes the five session:*
lifecycle schemas but must also include the shared turn event schemas so
downstreams can parse a full session stream; update the discriminated union for
SessionEventSchema to include the four shared turn schemas (e.g.,
AgentTokenEventSchema, AgentToolCallEventSchema, AgentToolResultEventSchema,
CostUpdatedEventSchema—or the exact names used in the file) alongside
SessionStartedEventSchema, SessionTurnStartedEventSchema,
SessionTurnCompletedEventSchema, SessionCancelledEventSchema, and
SessionExportedEventSchema, then keep exporting the inferred SessionEvent type
so it represents the complete session stream.

In `@packages/shared/src/workflow.test.ts`:
- Around line 356-377: Add tests to cover semantic validation failures by
extending workflow.test.ts: use the existing accepts and withWorkflow helpers to
assert that validation objects with contradictory bounds (e.g., validation: {
min: 10, max: 5 } on an input like name: 'sev', type: 'number') are rejected,
and that type-incompatible validation keys are rejected (e.g., apply string-only
keys like format or max_length to a number input, or numeric keys like min/max
to a string input). Place these new expect(...).toBe(false) cases next to the
existing tests so accepts(withWorkflow({...})) returns false for both
contradictory min/max and mismatched validation-key vs input type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a1845718-46dd-4a46-bd59-c2097d5bae69

📥 Commits

Reviewing files that changed from the base of the PR and between 43f7348 and 81728b5.

📒 Files selected for processing (15)
  • docs/reference/contracts/agent-session-spec.md
  • docs/reference/contracts/workflow-yaml-spec.md
  • docs/roadmap/deferred-tasks.md
  • docs/roadmap/phases/phase-1-engine-and-llm.md
  • packages/shared/src/config.test.ts
  • packages/shared/src/config.ts
  • packages/shared/src/constants.ts
  • packages/shared/src/node.test.ts
  • packages/shared/src/node.ts
  • packages/shared/src/run-event.test.ts
  • packages/shared/src/run-event.ts
  • packages/shared/src/run.test.ts
  • packages/shared/src/run.ts
  • packages/shared/src/workflow.test.ts
  • packages/shared/src/workflow.ts

Comment thread packages/shared/src/run.ts
Comment on lines +65 to +85
export const InputValidationSchema = z
.object({
format: nonEmptyString.optional(), // e.g. 'email'
pattern: nonEmptyString.optional(), // a regex source
enum: z.array(z.unknown()).optional(),
min: z.number().optional(),
max: z.number().optional(),
min_length: nonNegativeInt.optional(),
max_length: nonNegativeInt.optional(),
})
.strict();
export type InputValidation = z.infer<typeof InputValidationSchema>;

export const WorkflowInputSchema = z
.object({
name: nonEmptyString,
type: InputTypeSchema,
required: z.boolean().optional(),
default: z.unknown().optional(),
description: z.string().optional(),
validation: InputValidationSchema.optional(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject contradictory and type-incompatible input constraints.

validation currently only checks field presence, so impossible or nonsensical authored inputs still parse here — e.g. { min: 10, max: 1 }, { min_length: 8, max_length: 3 }, or a non-string input carrying string-only constraints. Since this package is the contract boundary, these should fail during schema validation instead of being deferred to the engine.

🤖 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 `@packages/shared/src/workflow.ts` around lines 65 - 85, Add schema-level
validations to reject contradictory or type-incompatible constraints: update
InputValidationSchema to include refinements that enforce numeric bounds (if
both min and max are present, require min <= max) and length bounds (if both
min_length and max_length are present, require min_length <= max_length), and
update WorkflowInputSchema to superRefine the pair (type, validation) so
string-only constraints (format, pattern, min_length, max_length) are only
allowed when the declared InputTypeSchema corresponds to a string-type; use
z.refine/z.superRefine on InputValidationSchema and WorkflowInputSchema
respectively, referencing the existing symbols InputValidationSchema,
WorkflowInputSchema, validation, min, max, min_length, max_length, format, and
pattern to find where to add the checks.

cemililik and others added 2 commits June 5, 2026 15:46
Triage of a batch of PR #6 review comments on the 1.L.0 reconciliation. Verified each
against the canonical contracts; fixed the valid ones, skipped the rest with reasons.

Fixed:
- error.nodeId is now nonEmptyString (run:failed.error + RunSchema.error) — a node id is
  never empty, matching every other nodeId field.
- agent:file_patch_proposed.patches is .min(1) — an empty proposal is meaningless (mirrors
  run:paused.gateIds.min(1)); noted in sse-event-schema.md.
- SessionContext.selection enforces startLine <= endLine.
- BudgetSchema.max_cost_microcents is positiveInt — a declared workflow budget caps at a
  positive value; omit `budget` for no cap. (Distinct from [chat].max_cost_microcents, an
  always-present default where 0 = unbounded — documented inline.)
- InputValidationSchema rejects contradictory bounds (min > max, min_length > max_length)
  at parse (ADR-0023).
- Test: the run:failed (missing partialOutputs) reject fixture now uses a compliant error,
  so it isolates the intended failure. +reject tests for every refinement (160 shared tests).

Skipped, with reason:
- Add the 4 reused turn events to SessionEventSchema: the spec NAMES `SessionEvent` as
  exactly the 5 session:* lifecycle events; the reused four validate via RunEventSchema
  (sessionId). Widening it would diverge from the canonical contract.
- Per-input-type validation-key matrix (e.g. `format` only on string): the contract defines
  no such matrix — tracked in deferred-tasks.md for a follow-up.
- allowedDomains FQDN/SSRF format check: the egress guard is engine-side (ADR-0029, 1.T);
  shared owns the shape.

Verified by a 2-skeptic adversarial workflow (triage correctness + over-rejection /
regression): both clean — no fix over-reaches, no skip should have been a fix, and no
refinement rejects a contract-valid payload (min==max, single-line selections, omitted
optionals all pass). Full gate green; seam fence + db drift gate unchanged.

Refs: ADR-0023, ADR-0028, ADR-0029

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… accuracy

A final comprehensive multi-agent review (8 dimensions → adversarial verify ×2 → completeness
critic) surfaced 12 confirmed items on the 1.L.0 change set — no blockers; test-coverage gaps
(testing.md accept+reject rule) and comment/doc-accuracy nits. All addressed.

Test coverage (every new schema constraint now has a reject that fails on revert):
- The four governance events (run:paused, run:timeout, budget:warning, budget:paused) get
  targeted rejects: empty gateIds, pendingGateCount 0, negative elapsedMs, thresholdPct > 100,
  negative spentMicrocents.
- StopReason closed-enum reject (session:turn_completed); SessionEvent per-variant required-field
  rejects (session:exported empty workflowPath, session:started missing model,
  session:turn_completed missing tokensUsed).
- attemptNumber loop now covers all five carriers (adds cost:updated, agent:file_patch_proposed).
- RunSchema.error.nodeId empty-string reject; [chat].max_cost_microcents: 0 accept (locks the
  "0 = unbounded" semantic that deliberately differs from the workflow budget's positiveInt).

Comment / doc accuracy:
- constants.ts: RUN_EVENT_TYPES order comment (agent:file_patch_proposed sits mid-list; only the
  four governance events close it); StopReason "canonical home" softened to not over-assert
  (the seam doc still defines it locally — tracked).
- node.ts: ExpressionTypeSchema JSDoc drops merge_fn (merge_fn is always js, no expression_type).
- phase-1 doc: the 1.L.0 dependency-matrix Enables cell is now the direct-edge set (1.A, 1.L, 1.W)
  with a transitive-gating note; a footnote marks the matrix authoritative for Lane-C cross-lane
  feeder edges the waves Mermaid omits.

Deferred (tracked, not silently dropped):
- AgentSchema input_schema/output_schema (pre-existing spec gap; agent.ts untouched by 1.L.0).
- Broadened the ContentPart seam-doc-codification entry to also cover StopReason.

160 -> 167 shared tests. Full gate green; seam fence + db drift gate unchanged.

Refs: ADR-0023, ADR-0028

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jun 5, 2026

Copy link
Copy Markdown

@cemililik cemililik merged commit 21b2f9c into main Jun 5, 2026
7 checks passed
cemililik added a commit that referenced this pull request Jun 5, 2026
Phase 1 Wave 0 — the @relavium/shared reconciliation (1.L.0) — is merged. Flip the phase
status to In progress, mark the 1.L.0 workstream ✅ Done, and rewrite current.md's immediate
next steps to the two Wave-1 lanes per the sequencing plan: 1.A (freeze the LLMProvider seam
types, scaffold packages/llm) and 1.L (WorkflowYAMLParser, scaffold packages/core).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cemililik added a commit that referenced this pull request Jun 21, 2026
… and milestones

- Mark Phase 1 as complete with all workstreams (1.A–1.AH) merged (PR #6#38).
- Achieve global milestones M1 (LLM seam proven) and M2 (engine end-to-end).
- Detail the completion of the critical path and additive sub-spines, including Lane C and multimodal sub-spine.
- Document the decision on multimodal I/O and its integration into the roadmap.
cemililik added a commit that referenced this pull request Jun 25, 2026
… status, defer log, concurrency)

Five review findings on the CLI media surface (all low/nit):

- #12 (nit, 3-lens): wireSaveToPort called mkdirSync on every write (blocking sync I/O in an async
  port) while the JSDoc implied once-only. Switch to await mkdir (node:fs/promises) — matches the
  FilesystemMediaStore.put pattern, keeps the port non-blocking — and reword the JSDoc to "every write".
- #13 (nit): TERMINAL_RUN_STATUSES typed Set<RunStatus> (was Set<string>), so a misspelled status is a
  compile error and .has() narrows the closed union.
- #7 (low): createWorkflowModelCatalog deferred silently on a CapabilityFlagsSchema.safeParse failure —
  indistinguishable from "model absent". Add an optional, per-model-deduped, secret-free warn sink
  (model id + Zod issue messages) threaded from run/gate via io.writeErr, so a future schema evolution
  that invalidates previously-valid rows is observable. Still fail-open (FallbackChain backstop).
- #6 (low): document the grace-window soft-delete→unlink resurrection gap (within ADR-0042 §3
  best-effort) so a future graceMs shortening triggers a re-verify-before-delete.
- #5 companion (low, PERF-CONCURRENCY-2): the grace-reclaim and orphan-sweep CAS deletes ran one await
  at a time on the exit path — fan them out with Promise.all (independent unlinks).

Refs: ADR-0042

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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