Skip to content

[structure-boundaries-v1] 2 — The configuration schema is a kernel schema plus a Vinaya-owned section, composed into the same validation, with identical results on every recorded configuration #1726

Closed

Description

@daniboomerang

Tier: 1
Project: vinaya, cli
Type: refactor

Objectives

O1. Before any code changes, a golden snapshot records, for every configuration in the corpus (the repository's own vinaya.config.json, every tracked vinaya.config*.json fixture, and every configuration value the existing configuration tests parse), whether the schema accepts it, the exact error text when it refuses, and the values every exported resolver returns when it accepts.
O2. The kernel owns the configuration schema and loader for the keys that name no process or role (checks and their environment declarations, runtime directory, logs, agents, managed files, continuous-integration setup, workspaces and the file, local-override and trust-anchor loading), under harness/kernel/config/schema/ and harness/kernel/config/loader/, and exports a process configuration section interface: the keys a section owns, its object fragment, its cross-key refinements and its resolvers.
O3. Vinaya's section, under harness/processes/vinaya-strict/integration/config/, owns the review policy, gate cutovers, prose rules, collision threshold, release actor, principals, tokens collection and command-emitter paths, with their refinements and resolvers.
O4. The composition of the kernel schema with Vinaya's section lives in the process, under harness/processes/vinaya-strict/integration/config/, and apps/cli/src/lib/config.ts becomes a re-export of it that keeps every export it has today under the same name and type, so none of its importers changes.
O5. Kernel code reads configuration only through a configuration provider the kernel defines: a composition root (the CLI entry point and each process runner entry) installs Vinaya's composed loader before any command or run starts, a kernel read with no installed provider is refused with an error naming it, and the files a later task moves into the kernel (run-paths.ts, log-sink.ts and every other kernel-bound importer of the configuration module) read through the provider from this task on.
O6. The golden snapshot is identical after the split, the exported configuration shape's key set is unchanged, and the existing configuration tests pass unchanged in assertions.
O7. Each executable test this task moves, splits or adds has one architecture owner and one suite kind in the test inventory; moved or split tests keep all assertions, expanded cases, fixtures and setup and cleanup semantics, and their inventory entries and input paths are updated in the same change; compiler-resolved dependencies stay authoritative, and fixtures, schemas, doctrine, spawned programs and tree scans keep their modeled input edges or an explained conservative fallback; continuous integration schedules each required test exactly once per intended configuration under its actual runner, working directory and preload; internal tests import existing narrow owner modules, and dedicated compatibility tests exercise public package exports; no required test is deferred and no production behaviour changes. Generic schema, loader and provider tests live with the kernel owner, Vinaya section and resolver tests with the process, and the golden composition and the CLI export tests with the process integration consumer; the golden configurations and snapshot are recorded as input edges, and the full golden parity check stays required. The pull request shows four selection plans for the moved area, each with selected test identities and reasons: an isolated implementation edit, a public boundary or policy edit, a fixture, schema or spawned-input edit, and an unrelated edit that selects none of the area's tests unless a stated conservative reason applies.

Documentation

  • apps/cli/src/lib/config.ts — the one schema, its refinements and resolvers this task splits (O2, O3, O4)
  • apps/cli/tests/config.test.ts — the existing accept and refuse cases the golden corpus includes (O1, O5)
  • docs/adr/0012-harness-and-processes-sit-at-the-repository-root.md — today's layout, superseded by the target-tree record whose kernel rule this split serves (O2)

Planner's rationale

Boundary — Split the one configuration schema along the kernel and process line with a bounded internal interface, not the public Loop contract. The golden snapshot is recorded first, from the unchanged schema, and committed; the split must reproduce it exactly, including the order and text of refinement errors. A refinement that reads both kernel and Vinaya keys belongs to the section and receives the kernel keys it reads. The composition sits in the process from this task on, and the CLI's configuration module only re-exports it, so its importers are untouched; kernel-bound importers switch to the provider in this task, so the kernel moves that follow never import the CLI or the process for configuration. Pinned files: apps/cli/src/lib/config.ts, apps/cli/tests/config.test.ts, apps/cli/tests/config-golden.test.ts, apps/cli/tests/fixtures/config-golden/snapshot.json, harness/kernel/config/schema/config-schema.ts, harness/kernel/config/loader/config-loader.ts, harness/kernel/config/schema/process-config-section.ts, harness/processes/vinaya-strict/integration/config/vinaya-config-section.ts, harness/processes/vinaya-strict/integration/config/compose.ts, harness/kernel/config/loader/config-provider.ts, apps/cli/src/lib/run-paths.ts, apps/cli/src/lib/log-sink.ts. Out: no key is added, removed or renamed; no default or error text changes; the importers of the configuration module, across the CLI, the process package and packages/aeg-core, are run and never edited, except the kernel-bound readers that switch to the provider.

Sizing — One verification story: the golden snapshot recorded before the split equals the one after it. Thirteen pinned files, eight new; one failure mode (a validation, message or resolved value differs). Passes all four tests.

Project(s) + blast radius — Project: vinaya, cli. Every CLI command reads configuration through the composition module, whose exports are unchanged, so consumers are re-verified by the golden snapshot rather than edited.

Dependency rationale — Depends-on: #1723 — the command-emitter paths the schema imports must already sit in the process. Conflicts-with: #1723 — that task rewrites the configuration module's emitter imports.

Traps to avoid — Do NOT record the snapshot after starting the split; record it from the unchanged schema in the first commit. Do NOT reorder refinements; zod reports issues in the order they are added. Do NOT let a kernel file import Vinaya's section; the composition module imports both. Do NOT name a role or a process in kernel files.

doc-claims: no claim anchor names a line this task changes, and the configuration module keeps every export a claim anchor cites, so every anchor still resolves.

reader-resolvable-prose: the new files' comments name keys and things, never a forge number or planning label.

Suggested agent-class — high: a schema split that must reproduce every error text and resolved value exactly.

Stop-and-escalate — Stop if a refinement cannot be placed in one side without changing its error text or order, and quote it. Stop if a kernel key's resolver needs a Vinaya key.

Docs to keep coherent — apps/cli/specs/config-reference.md names keys, not files, so it is unaffected; doc-owners derivation for the pinned files fired no binding.

atta-labs/process-version-bump: files under the process folder change, so the definition's version in harness/processes/vinaya-strict/process.yaml is raised by one patch step in the same change, with no other edit to it.

Premises

  • apps/cli/src/lib/config.ts contains const VinayaConfigObjectSchema = z.object({
  • apps/cli/src/lib/config.ts contains export const VinayaConfigSchema = VinayaConfigObjectSchema.superRefine((config, ctx) => {
  • apps/cli/src/lib/config.ts contains export function resolveReviewPolicy(config: VinayaConfig | null): ReviewPolicy {

Surface

in: apps/cli/src, apps/cli/scripts, apps/cli/tests, harness, scripts/ci, scripts/test-suites
out: packages, apps/log-server, apps/vinaya-portal, aeg-root

Parts

Part 1 (O1) — The golden corpus and snapshot are recorded from the unchanged schema.
Part 2 (O2) — The kernel schema, loader and section interface are written.
Part 3 (O3) — Vinaya's section holds its keys, refinements and resolvers.
Part 4 (O4, O5) — The composition lives in the process, the configuration module re-exports it, and kernel-bound readers use the installed provider.
Part 5 (O6) — The snapshot, key set and existing tests match.
Part 6 (O7) — Test ownership, inputs and scheduling are updated with the move.

Test plan

cd apps/cli && bun test --timeout=30000 tests/config-golden.test.ts tests/config.test.ts tests/lib/config-local-override.test.ts → 0 fail; the golden snapshot is unchanged
cd harness/kernel && bun test tests/architecture.test.ts → 0 fail
bun harness/kernel/tests/architecture-ratchet.ts --compare-base "$(git merge-base origin/main HEAD)" → exits 0
bunx turbo run typecheck --affected → exits 0
bun scripts/test-suites/inventory-check.ts → exits 0; every moved or new test classified once

Stop conditions

  • A refinement cannot be placed without changing its error text or order.
  • A kernel key's resolver needs a Vinaya key.

Origin

Principal-directed, 2026-10-29: the configuration boundary belongs in this structural refactor through a bounded internal interface that preserves existing validation behaviour; the public Loop contract stays separate.

Activity

  1. daniboomerang commented on Nov 2, 2026

    @daniboomerang
    MemberAuthor

    Brief hash: 8884df0159c15a5ca34542ab35f8d6eef8f5457187b10f6691a2801d8c9c811d
    For: [model] (coding-agent CLI on a dev machine, dispatched locally, unattended)
    Reason: Suggested agent-class — high: a schema split that must reproduce every error text and resolved value exactly.
    Owner: the Principal
    Goal: The configuration schema is a kernel schema plus a Vinaya-owned section, composed into the same validation, with identical results on every recorded configuration
    Project: vinaya, cli
    Tier: 1

    Closes #1726

    You are the AEG Developer. Run bun apps/cli/src/index.ts doctrine --role developer --print and read its output first. Mandatory.

    Objectives

    O1. Before any code changes, a golden snapshot records, for every configuration in the corpus (the repository's own vinaya.config.json, every tracked vinaya.config*.json fixture, and every configuration value the existing configuration tests parse), whether the schema accepts it, the exact error text when it refuses, and the values every exported resolver returns when it accepts.
    O2. The kernel owns the configuration schema and loader for the keys that name no process or role (checks and their environment declarations, runtime directory, logs, agents, managed files, continuous-integration setup, workspaces and the file, local-override and trust-anchor loading), under harness/kernel/config/schema/ and harness/kernel/config/loader/, and exports a process configuration section interface: the keys a section owns, its object fragment, its cross-key refinements and its resolvers.
    O3. Vinaya's section, under harness/processes/vinaya-strict/integration/config/, owns the review policy, gate cutovers, prose rules, collision threshold, release actor, principals, tokens collection and command-emitter paths, with their refinements and resolvers.
    O4. The composition of the kernel schema with Vinaya's section lives in the process, under harness/processes/vinaya-strict/integration/config/, and apps/cli/src/lib/config.ts becomes a re-export of it that keeps every export it has today under the same name and type, so none of its importers changes.
    O5. Kernel code reads configuration only through a configuration provider the kernel defines: a composition root (the CLI entry point and each process runner entry) installs Vinaya's composed loader before any command or run starts, a kernel read with no installed provider is refused with an error naming it, and the files a later task moves into the kernel (run-paths.ts, log-sink.ts and every other kernel-bound importer of the configuration module) read through the provider from this task on.
    O6. The golden snapshot is identical after the split, the exported configuration shape's key set is unchanged, and the existing configuration tests pass unchanged in assertions.
    O7. Each executable test this task moves, splits or adds has one architecture owner and one suite kind in the test inventory; moved or split tests keep all assertions, expanded cases, fixtures and setup and cleanup semantics, and their inventory entries and input paths are updated in the same change; compiler-resolved dependencies stay authoritative, and fixtures, schemas, doctrine, spawned programs and tree scans keep their modeled input edges or an explained conservative fallback; continuous integration schedules each required test exactly once per intended configuration under its actual runner, working directory and preload; internal tests import existing narrow owner modules, and dedicated compatibility tests exercise public package exports; no required test is deferred and no production behaviour changes. Generic schema, loader and provider tests live with the kernel owner, Vinaya section and resolver tests with the process, and the golden composition and the CLI export tests with the process integration consumer; the golden configurations and snapshot are recorded as input edges, and the full golden parity check stays required. The pull request shows four selection plans for the moved area, each with selected test identities and reasons: an isolated implementation edit, a public boundary or policy edit, a fixture, schema or spawned-input edit, and an unrelated edit that selects none of the area's tests unless a stated conservative reason applies.

    Documentation

    • apps/cli/src/lib/config.ts — the one schema, its refinements and resolvers this task splits (O2, O3, O4)
    • apps/cli/tests/config.test.ts — the existing accept and refuse cases the golden corpus includes (O1, O5)
    • docs/adr/0012-harness-and-processes-sit-at-the-repository-root.md — today's layout, superseded by the target-tree record whose kernel rule this split serves (O2)

    Premises

    Checked against the code when this task Issue was cut, and again against the default branch at dispatch — facts, not claims.

    • apps/cli/src/lib/config.ts contains const VinayaConfigObjectSchema = z.object({
    • apps/cli/src/lib/config.ts contains export const VinayaConfigSchema = VinayaConfigObjectSchema.superRefine((config, ctx) => {
    • apps/cli/src/lib/config.ts contains export function resolveReviewPolicy(config: VinayaConfig | null): ReviewPolicy {

    2. Context — read before doing anything

    • Tranche: structure-boundaries-v1, task 2, Issue [structure-boundaries-v1] 2 — The configuration schema is a kernel schema plus a Vinaya-owned section, composed into the same validation, with identical results on every recorded configuration #1726. Branch task/structure-boundaries-v1/2. Depends-on: #1723, Conflicts-with: #1723.
    • Read Issue [structure-boundaries-v1] 2 — The configuration schema is a kernel schema plus a Vinaya-owned section, composed into the same validation, with identical results on every recorded configuration #1726 in full for the complete rationale — do not re-derive it.
    • Revision: rendered at 1cadb745f62031077331eac3e7e3c8ccdbc85774 — the checkout's HEAD equaled the remote default branch, and no pinned file below carried an uncommitted change, when these facts were read.
    • Boundary — Split the one configuration schema along the kernel and process line with a bounded internal interface, not the public Loop contract. The golden snapshot is recorded first, from the unchanged schema, and committed; the split must reproduce it exactly, including the order and text of refinement errors. A refinement that reads both kernel and Vinaya keys belongs to the section and receives the kernel keys it reads. The composition sits in the process from this task on, and the CLI's configuration module only re-exports it, so its importers are untouched; kernel-bound importers switch to the provider in this task, so the kernel moves that follow never import the CLI or the process for configuration. Pinned files: apps/cli/src/lib/config.ts, apps/cli/tests/config.test.ts, apps/cli/tests/config-golden.test.ts, apps/cli/tests/fixtures/config-golden/snapshot.json, harness/kernel/config/schema/config-schema.ts, harness/kernel/config/loader/config-loader.ts, harness/kernel/config/schema/process-config-section.ts, harness/processes/vinaya-strict/integration/config/vinaya-config-section.ts, harness/processes/vinaya-strict/integration/config/compose.ts, harness/kernel/config/loader/config-provider.ts, apps/cli/src/lib/run-paths.ts, apps/cli/src/lib/log-sink.ts. Out: no key is added, removed or renamed; no default or error text changes; the importers of the configuration module, across the CLI, the process package and packages/aeg-core, are run and never edited, except the kernel-bound readers that switch to the provider.
    • Traps to avoid — Do NOT record the snapshot after starting the split; record it from the unchanged schema in the first commit. Do NOT reorder refinements; zod reports issues in the order they are added. Do NOT let a kernel file import Vinaya's section; the composition module imports both. Do NOT name a role or a process in kernel files.

    doc-claims: no claim anchor names a line this task changes, and the configuration module keeps every export a claim anchor cites, so every anchor still resolves.

    reader-resolvable-prose: the new files' comments name keys and things, never a forge number or planning label.

    3. Technical dependencies

    Dependency rationale — Depends-on: #1723 — the command-emitter paths the schema imports must already sit in the process. Conflicts-with: #1723 — that task rewrites the configuration module's emitter imports.

    4. Technical surface map

    Create:

    • (none — every surface file already exists)

    Modify:

    • apps/cli/src
    • apps/cli/scripts
    • apps/cli/tests
    • harness
    • scripts/ci
    • scripts/test-suites

    Out of surface: packages, apps/log-server, apps/vinaya-portal, aeg-root — a change there, or to any path no Surface in: glob covers, is still published: the review-loop driver records each such path in the pull request body's beyond-Surface block, and the reviewers judge it like any change.

    Premise pins

    Premise:

    • apps/cli/src/lib/config.ts sha256: c283c116e70854c8cb69d5be0993d076acca1a31d581f033f0de5c96eb1d32c2
    • apps/cli/src/lib/log-sink.ts sha256: 47cdbaa1a5a42949505566ffe8990c04ad7a6cddbb5b31614dc095e6709aa253
    • apps/cli/src/lib/run-paths.ts sha256: ab20d29ca7ab37320a517b3be67750d3c6cd1b7e0008b3650b097bb6b662925e
    • apps/cli/tests/config.test.ts sha256: 8aaaec6b9ab7cd5e8e310f562b1484755395f45a778155160c57786acac6a8b5

    5. Pre-flight checks

    Step 0 (mandatory, verbatim):

    bun install --frozen-lockfile --silent
    
    1. Clean status; parent origin/main; branch suffix literal-matches the task id.
    2. Under the review loop (bun apps/cli/src/index.ts task run), the driver has already run the dispatch-readiness gate plus, on this repository toolchain, its own fuller derivation from its own unsandboxed process before dispatching you (re-derived at render time: it was ready), and dispatches you only when that verdict is READY — a NOT READY verdict refuses the turn before it starts, so being dispatched is the verdict: look for no file and run neither script, whose own gh call fails inside your sandbox. Working manually, with no driver behind you, fall back to roles/developer.md's own items 3/5/7 prose — each a complete, hand-run forge check in its own right.

    On any failure: STOP and report.

    6. Numbered parts — publish once with publish_changes when every Part is done, then open_pull_request

    1. Part 1 (O1): The golden corpus and snapshot are recorded from the unchanged schema.

      Files (touches @attalabs/vinaya):

      • apps/cli/src/lib/config.ts
      • apps/cli/src/lib/log-sink.ts
      • apps/cli/src/lib/run-paths.ts
      • apps/cli/tests/config.test.ts

      The pre-push hook runs the affected suite on your one push and refuses it on failure — do not run it yourself per Part.

    2. Part 2 (O2): The kernel schema, loader and section interface are written.

    3. Part 3 (O3): Vinaya's section holds its keys, refinements and resolvers.

    4. Part 4 (O4, O5): The composition lives in the process, the configuration module re-exports it, and kernel-bound readers use the installed provider.

    5. Part 5 (O6): The snapshot, key set and existing tests match.

    6. Part 6 (O7): Test ownership, inputs and scheduling are updated with the move.

    7. Documentation-update list

    • apps/cli/specs/log.md

    8. Verification before claiming done

    • Under the review loop, the controller runs the static gates: the commit hook applies safe format and lint fixes to staged files, typechecks affected packages, and runs the Vinaya checks; the pre-push hook runs the affected suite; run_checks and CI provide the authoritative results. Do not hand-run or paste static-gate commands. Working manually, run this repository's declared typecheck, lint/format, build, and documentation-gate commands yourself.
    • The pre-push hook runs the affected suite once, on your one push, and refuses it on failure; CI runs the full suite.
    • Every blast-radius consumer named in §4, re-verified by name.
    • The tier checklist in bun apps/cli/src/index.ts doctrine --role developer --print genuinely satisfied; use the controller's run_checks result, hooks, and CI as gate evidence.

    9. Test Plan

    cd apps/cli && bun test --timeout=30000 tests/config-golden.test.ts tests/config.test.ts tests/lib/config-local-override.test.ts → 0 fail; the golden snapshot is unchanged
    cd harness/kernel && bun test tests/architecture.test.ts → 0 fail
    bun harness/kernel/tests/architecture-ratchet.ts --compare-base "$(git merge-base origin/main HEAD)" → exits 0
    bunx turbo run typecheck --affected → exits 0
    bun scripts/test-suites/inventory-check.ts → exits 0; every moved or new test classified once
    

    10. Stop conditions

    • A refinement cannot be placed without changing its error text or order.
    • A kernel key's resolver needs a Vinaya key.

    Stop-and-escalate — Stop if a refinement cannot be placed in one side without changing its error text or order, and quote it. Stop if a kernel key's resolver needs a Vinaya key.

    11. Constraints

    Autonomy: Do not stop to ask clarifying questions. For any ambiguity not covered by a Section 10 stop condition, choose the most reasonable option consistent with this brief, record the choice in the PR body at open, and continue. Halt only for the explicit Section 10 stop conditions — and when you halt, report the blocker in your turn result (the loop posts it); post no PR or Issue comment yourself, and do not wait interactively for input.

    12. Deliverable

    • PR title (exact): [structure-boundaries-v1] 2 — The configuration schema is a kernel schema plus a Vinaya-owned section, composed into the same validation, with identical results on every recorded configuration
    • Open the PR only via the open_pull_request tool (title and body); publish your commits with publish_changes and update the body with update_pull_request_body/refresh_evidence — you hold no gh/git push credential.
    • Publish once, with publish_changes, when every Part is done; then open the pull request with open_pull_request. Publish again only to answer review findings or a red gate — a refused hook, a failing check, a merge conflict.
    • PR body = the Developer's PR report (print it with bun apps/cli/src/index.ts doctrine --template pr-report --print), with Closes #1726 at the top of the header block. This brief stays frozen on the task Issue and never rides in the body.
    • Pre-open: tier checklist satisfied. The documentation gate is the controller's — run_checks and CI run it.
    • Include git diff origin/main...HEAD --stat as context only; Surface is judged by the driver's surface-scope check, never by this hand-run diff. Token use needs no report — the Vinaya log records it.
    • Then STOP. Review and Verification are separate invocations.
  2. self-assigned this
    on Nov 2, 2026
  3. daniboomerang commented on Nov 2, 2026

    @daniboomerang
    MemberAuthor

    The dev-review-loop paused: ready_push_failed — the ready push failed 3 consecutive times; failing test files: ~/Work/Repositories/Me/atta-labs/vinaya/.worktrees/task/structure-boundaries-v1/2/harness/processes/vinaya-strict/tests/standalone/lib/task-worktree-install.test.ts.

    No pull request exists yet for this task, so the pause is recorded on this Issue instead.
    A Principal ruling is needed before this can continue. Post it as a comment on this Issue whose FIRST line is exactly this marker — the second number is the ordinal, and it must exceed the one this pause recorded:

    <!-- aeg:principal:ruling:1726-1 -->
    Your ruling text here.
    

    Then continue with:

    vinaya task run structure-boundaries-v1 2 --agent claude --model opus --runner atta-engine
    

    The Operator's own task_resume clears this pause too, reading that same ruling from this Issue; task_cancel ends it instead.

  4. daniboomerang commented on Nov 2, 2026

    @daniboomerang
    MemberAuthor

    Ruling: proceed_as_briefed — retry the ready push; change nothing.

    The run's record leaves one file unproven, harness/processes/vinaya-strict/tests/standalone/lib/task-worktree-install.test.ts. On this branch's head that file passes on its own, 9 pass and 0 fail, with the push's own --timeout=30000; it also passes on the default branch. The failing push ran while the host was out of memory. Retry: the next ready push re-runs only that file plus any change since. If it fails again there, find what in the shared run affects it (the other files in its group) and fix that; change no assertion.

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions