fabro/.chisel/calibration/work/validation-1.md
2026-07-27 11:58:54 -04:00

424 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Chisel calibration validation 1
Revision: `6bb6b5efcc0e36b52e3c097f532d9f2c00914c6c`
This is an independent reading of only the requested assignments. Scores use the
mapped purposes and the final calibration rubric. Boundary evidence is included
where it establishes whether a scoped mechanism is on a production common path.
## Summary
| Component | Lens | Score | Evidence confidence |
|---|---|---:|---|
| `fabro-workflow` | `ownership-boundaries` | 2 | High |
| `fabro-workflow` | `domain-model` | 2 | High |
| `fabro-http` | `domain-model` | 4 | High |
| `fabro-http` | `duplication-knowledge` | 4 | High |
| `fabro-web-app` | `ownership-boundaries` | 4 | Medium |
| `repository-ci` | `ownership-boundaries` | 4 | Medium |
| `repository-ci` | `domain-model` | 2 | High |
| `fabro-checkpoint` | `ownership-boundaries` | 2 | High |
| `fabro-checkpoint` | `simplicity` | 4 | Medium |
| `fabro-checkpoint` | `domain-model` | 2 | High |
| `fabro-checkpoint` | `duplication-knowledge` | 3 | Medium |
## `fabro-workflow`
### `ownership-boundaries`: 2
- **Evidence:** `lifecycle/mod.rs:53-80` presents `WorkflowLifecycle` as the
callback owner, and `lifecycle/git.rs:77-93, 397-401` gives `GitLifecycle`
its own `last_git_sha` state. The normal `RunSession::run` path nevertheless
creates a second `last_git_sha`, reconstructs it by listening to emitted
checkpoint, terminal, and Git events, then passes it back into finalization
(`operations/start.rs:821-856, 914-923`). Terminal responsibility is split
again: engine outcomes become terminal events in
`pipeline/finalize.rs:524-596`, while bootstrap, initialization, and
finalization errors become `run.failed` through the outer operation in
`operations/start.rs:176-285, 288-346`. These crossings occur on the normal
run and error paths, not at an optional edge.
- **Strongest counterevidence:** `operations/start.rs:796-953` is a recognizable
top-level owner for the initialize → execute → finalize → pull-request
sequence, and `WorkflowLifecycle` explicitly orders focused delegates for
each executor callback (`lifecycle/mod.rs:221-469`).
- **Why adjacent scores do not fit:** 3 does not fit because the caller always
mirrors and resupplies Git identity on the common run path, and terminal
failure handling routinely selects between two owners. 1 does not fit because
both the executor callback owner and the outer run-session owner are stable
and traceable; the problem is their competition, not the absence of owners.
- **Rule discrimination:** Decision rule 2 is decisive for the mirrored
`last_git_sha`. The phrase “complete lifecycle” is otherwise ambiguous about
whether an executor lifecycle may end before durability finalization; the
explicit state round-trip makes the result 2 without relying on that
ambiguity.
### `domain-model`: 2
- **Evidence:** The internal durable event shape stores
`Event::StageCompleted.status` as `String`
(`event/events.rs:264-272`). Both synthetic terminal-stage completion and
ordinary successful stage completion stringify the canonical
`StageOutcome` (`lifecycle/event.rs:215-240, 355-366`), after which the
mandatory event conversion reparses it and converts an unknown value to
`Failed` (`event/convert.rs:14-24, 309-333`). This typed → string → typed path
is part of every successful stage-completion event.
- **Strongest counterevidence:** `fabro_types::StageOutcome` is a stable
canonical type, most event fields are typed, and the fallback prevents an
unrecognized string from escaping into the stored projection.
- **Why adjacent scores do not fit:** 3 does not fit because common production
completion events depend on the invalid intermediate rather than using it as
a compatibility edge. 1 does not fit because the canonical status meaning is
clear and the conversion point is explicit.
- **Rule discrimination:** Decision rule 4 and the rubric's repository example
make this assignment unambiguous.
## `fabro-http`
### `domain-model`: 4
- **Evidence:** `ProxyPolicy` is a closed `System | Disabled` vocabulary;
parsing rejects every other boundary value
(`src/lib.rs:23-35`). Resolution gives explicit configuration precedence over
the environment, defaults absence to `System`, and rejects non-Unicode input
(`src/lib.rs:38-60`). Every async and blocking builder reaches that resolver
before construction (`src/lib.rs:160-166, 172-193`), while the deterministic
test helpers select the typed `Disabled` value
(`src/lib.rs:195-213`).
- **Strongest counterevidence:** The builder also exposes raw `no_proxy()` and
`proxy()` operations (`src/lib.rs:96-106`), so callers can combine an
underlying reqwest choice with `ProxyPolicy`; Unix-socket production callers
do use `no_proxy()` (`lib/foundation/fabro-client/src/client.rs:2123-2134`).
- **Why adjacent scores do not fit:** 3 does not fit because the common
policy-controlled constructors never interpret an invalid policy: they
return `HttpClientBuildError`. The raw builder operations represent valid
per-client transport configuration, not a second string vocabulary. 2 and 1
do not fit because no common-path conversion or unstable meaning is present.
- **Rule discrimination:** Decision rule 4 is potentially non-discriminating
if every forwarded low-level builder method is called an “escape hatch.”
Here `no_proxy()` carries no invalid intermediate and does not weaken
`ProxyPolicy::resolve`, so treating it as ordinary typed builder
configuration preserves the rule's distinction.
### `duplication-knowledge`: 4
- **Evidence:** `define_builder!` holds the complete shared async/blocking
builder policy once, including proxy resolution and construction
(`src/lib.rs:72-170`), and is instantiated for the two reqwest client kinds
(`src/lib.rs:172-193`). The four convenience constructors delegate to those
builders rather than reproducing policy (`src/lib.rs:195-213`).
- **Strongest counterevidence:** The generated facade necessarily lists each
forwarded reqwest method, and the test and non-test convenience constructors
have similar bodies.
- **Why adjacent scores do not fit:** 3 does not fit because the similar
forwarding and wrappers are syntax over one policy authority, not separately
maintained transport knowledge. 2 does not fit because a proxy-policy change
is made once in the macro/resolver, not synchronized across async and
blocking implementations. 1 does not fit because the authority is explicit.
- **Rule discrimination:** The rubric's `define_builder!` example directly
distinguishes shared macro expansion from semantic duplication; no material
ambiguity remains.
## `fabro-web-app`
### `ownership-boundaries`: 4
- **Evidence:** `entry.tsx:17-49` owns browser startup, chooses the normal or
installation route graph once, and installs shared SWR runtime policy.
`router.tsx:97-184` owns normal route composition. Shared transport and error
handling live in `lib/api-client.ts:64-160, 213-310`; shared reads such as
`useRun` and `useRunState` live in `lib/queries.ts:182-193`; run mutations and
their cache lifecycle live in `lib/mutations.ts:65-132`; and run-scoped SSE
subscription, invalidation, resync, and cleanup live in
`lib/run-events.ts:129-309`. The representative busy route composes those
owners rather than reimplementing them
(`routes/run-detail.tsx:79-145, 313-379`).
- **Strongest counterevidence:** Some route-local CRUD actions call the shared
API facade directly, and `run-detail.tsx:193-205` coordinates delete state,
cache invalidation, toast, and navigation in the route.
- **Why adjacent scores do not fit:** 3 does not fit because the counterevidence
is local page UX ownership; it does not split a shared transport, read,
mutation, or subscription lifecycle. 2 does not fit because routine run-page
changes use the established owners rather than coordinating competing ones.
1 does not fit because startup, routing, transport, caching, and streaming
each have readily identifiable homes.
- **Rule discrimination:** “One owner” is mildly non-discriminating for a large
browser application unless responsibility is evaluated at lifecycle
granularity. Using the rubric's `apiData`/`useRun` example, route composition
is not itself a second owner. Confidence is Medium because this is the
largest sampled scope.
## `repository-ci`
### `ownership-boundaries`: 4
- **Evidence:** `rust.yml:3-40` owns Rust branch/PR/manual triggers and
concurrency, while its jobs contain format, lint, generated-doc, Linux test,
twin E2E, and manual macOS lifecycles (`rust.yml:48-147`).
`typescript.yml:3-34` owns the corresponding TypeScript triggers and
concurrency, and its jobs contain typecheck, test, and integrated SPA/Rust
build lifecycles (`typescript.yml:36-77`). Delegation to `cargo dev` is the
mapped dependency on build tooling, not reverse ownership.
- **Strongest counterevidence:** The TypeScript build invokes a Rust build
(`typescript.yml:75-77`), and invalid path selectors mean some intended
changes do not start the declared workflows.
- **Why adjacent scores do not fit:** 3 does not fit because the cross-language
build is the intentional embedded-SPA integration boundary, not friction, and
selector validity is classified under domain model by decision rule 6. 2
does not fit because no routine job requires coordination between competing
CI owners. 1 does not fit because the two language validation homes and their
dependency direction are explicit.
- **Rule discrimination:** The score-4 phrase “complete lifecycle” is
non-discriminating for hosted CI if it is read to require repository
ownership of GitHub's runner lifecycle. This score treats the checked-in
trigger/job lifecycle as the mapped responsibility and the platform as an
intended boundary.
### `domain-model`: 2
- **Evidence:** Both Rust trigger selectors name `openapi/**`
(`rust.yml:18,34`), but that revision has no tracked target there; the actual
API contract is `docs/public/api-reference/fabro-api.yaml`, which the
TypeScript client generation command consumes
(`lib/packages/fabro-api-client/package.json:7`). The real contract path is
absent from both workflow path filters. In addition, all three zizmor
`stale-action-refs` identifiers target `rust.yml:37`, `:49`, and `:62`
(`zizmor.yml:1-6`), which are respectively the end of trigger setup, the
`fmt` job key, and a `run` command—not action references at this revision.
These invalid identifiers sit directly in trigger and static-validation
configuration.
- **Strongest counterevidence:** The workflow/job vocabulary itself is stable,
all jobs and action pins have clear meanings, and changes under the large
valid Rust and TypeScript source selectors do trigger their expected suites.
- **Why adjacent scores do not fit:** 3 does not fit because the dead OpenAPI
selector is present in both routine branch and PR paths, while every scoped
zizmor exception lacks a current target. 1 does not fit because the overall
workflow and job model remains stable; the defect is a recurring set of
invalid identifiers.
- **Rule discrimination:** Decision rule 6 is decisive that these are domain
pressure rather than ownership or duplication. It does not state when one or
more dead selectors move from 3 to 2; centrality in both trigger modes and
total staleness of the scoped zizmor selectors supply that discrimination
here.
## Control: `fabro-checkpoint`
### `ownership-boundaries`: 2
- **Evidence:** The mapped component claims metadata branches, but its
production boundary consumer owns the metadata writer's branch, parent OID,
discovery, remote, and push lifecycle
(`fabro-workflow/src/run_metadata.rs:272-282, 313-439`). On every snapshot,
that caller validates entries, individually drives `Store` through blobs,
tree, commit, and ref update, and retains the parent identity for the next
write (`run_metadata.rs:313-350`). `BranchStore` provides a contained
read-modify-write owner (`branch.rs:17-24, 42-81`) but has no production
caller at this revision.
- **Strongest counterevidence:** The dependency direction is intended
(`fabro-workflow` depends on `fabro-checkpoint`), and the low-level `Store`
consistently owns Git object/ref operations (`git.rs:101-227`).
- **Why adjacent scores do not fit:** 3 does not fit because the lifecycle
crossing occurs on every metadata snapshot, not in an isolated adapter. 1
does not fit because low-level Git ownership and the caller's higher-level
writer ownership are both stable; the problem is the split between them.
- **Rule discrimination:** Decision rule 2 applies because the caller retains
and resupplies branch/parent identity to complete successive writes. The
rubric does not say whether a deliberately low-level `Store` narrows the
mapped ownership claim; the explicit mapped claim to metadata branches makes
this crossing discriminating.
### `simplicity`: 4
- **Evidence:** The production `Store` has direct blob, tree, commit, and ref
operations (`git.rs:123-226`). Tree conversion is a single read recursion and
a single bottom-up write path (`git.rs:229-310`). At the higher level,
`BranchStore::write_with` is a linear resolve → read → mutate → write → commit
→ update sequence (`branch.rs:56-81`), and entry operations are small
delegates (`branch.rs:84-117`). Necessary Git layering is visible rather than
hidden behind competing configuration machinery.
- **Strongest counterevidence:** There are two entry levels, and the production
metadata writer uses the lower-level `Store` instead of `BranchStore`.
- **Why adjacent scores do not fit:** 3 does not fit because choosing the
low-level entry is required for replace-whole-tree and remote-parent behavior,
not unnecessary indirection. 2 does not fit because the scoped common
operations do not navigate competing implementations or configuration. 1
does not fit because both paths are directly traceable.
- **Rule discrimination:** Ownership rule 2 could otherwise cause the
out-of-scope metadata writer's machinery to be counted again as simplicity
friction. The lens exclusions make that non-discriminating evidence here;
within the scoped implementation, the production primitives are direct.
### `domain-model`: 2
- **Evidence:** `TreeEntries::set` accepts any `String` path without validation
(`git.rs:46-60`), and `write_tree` later interprets it by splitting on `/`
(`git.rs:149-153, 270-293`). The common metadata caller must therefore define
and apply `validate_metadata_path` outside this component before every
`TreeEntries` construction
(`fabro-workflow/src/run_metadata.rs:313-332, 471-480`). The component also
maps every unrecognized Git file mode to `Blob`
(`git.rs:21-35, 229-250`) rather than rejecting an unsupported state.
- **Strongest counterevidence:** `FileMode` is otherwise a closed enum, Git
object IDs use `git2::Oid`, and the current production metadata caller does
reject empty, absolute, dot-segment, and empty-segment paths before writing.
- **Why adjacent scores do not fit:** 3 does not fit because external path
validation is mandatory on every common metadata snapshot and the canonical
`TreeEntries` shape can always hold an invalid path. 1 does not fit because
the intended path and mode meanings remain clear and production does have a
validation step.
- **Rule discrimination:** Decision rule 4 clearly places the caller-validated
`TreeEntries` intermediate at 2. Whether unknown Git modes are a compatibility
escape hatch is ambiguous by itself, but it is not needed to choose the
score.
### `duplication-knowledge`: 3
- **Evidence:** Branch-to-full-ref formatting is repeated in `Store::update_ref`,
`resolve_ref`, and `delete_ref` (`git.rs:182-225`), and the boundary metadata
writer has another `full_ref` transformation
(`fabro-workflow/src/run_metadata.rs:364-439`). `BranchStore::read_entry`,
`read_entries`, `list_entries`, and `tip_tree` also repeat parts of branch-tip
resolution (`branch.rs:119-184`). These repetitions are local and stable, but
there is no single helper enforcing them.
- **Strongest counterevidence:** Mutation sequencing is authoritative in
`BranchStore::write_with` (`branch.rs:56-81`), metadata branch naming has one
`META_BRANCH_PREFIX` constant (`lib.rs:7`), Git-author defaults have one
`Default` implementation (`author.rs:13-20`), and the repeated ref syntax is a
fixed Git protocol form rather than frequently changing Fabro policy.
- **Why adjacent scores do not fit:** 4 does not fit because ref normalization
and branch-tip traversal are still represented in several places. 2 does not
fit because there is no direct evidence that a routine checkpoint change
must alter those stable protocol transformations in sync; the repetitions are
isolated implementation knowledge. 1 does not fit because each policy has an
identifiable local authority even where a helper is absent.
- **Rule discrimination:** Decision rule 5 leaves a real 3-versus-4 ambiguity:
repeated `refs/heads/` can be classified as harmless protocol syntax. I score
3 because the same branch-to-ref transformation crosses the component
boundary, but do not score 2 without evidence of routine synchronization.
## Overall rubric observations
- Decision rule 2 successfully distinguishes focused delegates from a lifecycle
that sends identity back through an event/caller round trip.
- Decision rule 6 prevents dead CI selectors from being double-counted as
ownership defects, but needs centrality/recurrence evidence to distinguish 2
from 3.
- “One owner” and “complete lifecycle” need responsibility-sized interpretation
for route trees and hosted CI; otherwise healthy composition cannot reach 4.
- Decision rule 5 correctly keeps stable protocol repetition from automatically
becoming score 2, but the line between harmless syntax and a repeated
transformation remains the least discriminating part of this sample.
## Round 2 revalidation
| Component | Lens | Score | Confidence |
|---|---|---:|---|
| `fabro-http` | `duplication-knowledge` | 3 | Medium |
| `repository-ci` | `ownership-boundaries` | 2 | High |
| `fabro-checkpoint` | `ownership-boundaries` | 2 | High |
| `fabro-checkpoint` | `simplicity` | 3 | High |
| `fabro-checkpoint` | `domain-model` | 2 | High |
| `fabro-checkpoint` | `duplication-knowledge` | 3 | Medium |
### `fabro-http` × `duplication-knowledge`: 3
- **Decisive evidence:** Proxy disabling has two concrete semantic
representations in the mapped entry layer: callers may set
`ProxyPolicy::Disabled` (`src/lib.rs:23-27, 90-94`), or call the separately
exposed `no_proxy()` builder operation (`src/lib.rs:96-100`). The former is
interpreted by calling the same underlying `inner.no_proxy()` transformation
during `build` (`src/lib.rs:160-165`). Both forms are used on direct boundary
paths: test constructors select the enum (`src/lib.rs:199-213`), while the
Unix-socket transport selects `no_proxy()`
(`lib/foundation/fabro-client/src/client.rs:2123-2134`).
- **Adjacent scores:** 4 does not fit revised rule 6 because there is a concrete
second representation of the same no-proxy decision. 2 does not fit because
an ordinary proxy-policy extension does not require manually synchronizing
those call sites; async and blocking policy construction still share the one
`define_builder!` mechanism (`src/lib.rs:72-193`). 1 does not fit because the
resolver remains a stable authority.
- **Remaining ambiguity:** `no_proxy()` can reasonably be viewed as a lower-level
reqwest operation rather than a second Fabro policy. Revised rule 6 makes 3
the conservative result because `ProxyPolicy::Disabled` is implemented by
that exact operation, but this classification keeps confidence at Medium.
### `repository-ci` × `ownership-boundaries`: 2
- **Decisive evidence:** The Rust check explicitly scans
`docs/public/api-reference/fabro-api.yaml` in its legacy-identity guard
(`rust.yml:80-92`), but neither push nor pull-request triggers include that
real path (`rust.yml:3-35`); they include the nonexistent `openapi/**`
selector instead (`rust.yml:18,34`). A routine API-contract change can
therefore change a scanned target without starting its owning check.
- **Adjacent scores:** 3 does not fit because the non-triggering target is on a
routine branch/PR check path, not an isolated manual edge. 1 does not fit
because the workflow, jobs, and intended trigger owner remain identifiable.
4 is directly excluded by revised rule 3's trigger-coverage requirement.
- **Remaining ambiguity:** `typescript.yml:76` also invokes a Rust build from a
narrower trigger set, but that broader interpretation is unnecessary; the
explicitly scanned, non-triggering API contract is sufficient for 2.
### `fabro-checkpoint` × `ownership-boundaries`: 2
- **Decisive evidence:** The mapped owner exposes low-level `Store` primitives,
while the routine metadata caller reconstructs the mapped branch lifecycle:
`RunMetadataWriter` owns branch, parent, and discovery state
(`fabro-workflow/src/run_metadata.rs:272-282`), then validates entries and
sequences blob, tree, commit, ref update, and retained parent state on every
snapshot (`run_metadata.rs:313-350`). No production boundary uses the
component's higher-level `BranchStore`.
- **Adjacent scores:** 3 does not fit because every metadata snapshot traverses
the split. 1 does not fit because the low-level Git owner and caller-side
lifecycle are both stable. 4 is directly excluded by revised rule 2: the
routine caller reconstructs a lifecycle the map assigns to this component.
- **Remaining ambiguity:** A narrower map that assigned only Git object
primitives to `fabro-checkpoint` could make this healthy delegation, but the
actual map explicitly assigns metadata branches and checkpoint commits.
### `fabro-checkpoint` × `simplicity`: 3
- **Decisive evidence:** `Cargo.toml:16-24` carries `fabro-store` as a production
dependency, but scoped production code does not use it. The component also
exposes `BranchStore` as a parallel entry layer (`branch.rs:17-24`) that has
no production caller at this revision; the common metadata path uses `Store`
directly. The active `Store` path itself remains linear and direct
(`git.rs:123-226`).
- **Adjacent scores:** 4 is explicitly capped at 3 by revised rule 4 for the
unused production dependency and parallel unused entry layer. 2 does not fit
because routine production work does not repeatedly navigate those unused
elements; its `Store` path is direct. 1 does not fit because a stable common
path is easy to trace.
- **Remaining ambiguity:** Either isolated fact independently supplies the
revised rule's cap, so there is no material score ambiguity.
### `fabro-checkpoint` × `domain-model`: 2
- **Decisive evidence:** `TreeEntries::set` accepts arbitrary string paths
(`git.rs:46-60`) before `write_tree` interprets them structurally
(`git.rs:149-153, 270-293`). Every common metadata snapshot must validate
those paths outside the mapped entry before constructing `TreeEntries`
(`fabro-workflow/src/run_metadata.rs:313-332, 471-480`).
- **Adjacent scores:** 3 does not fit revised rule 5 because caller validation
does not isolate an invalid-capable mapped entry used on every snapshot. 1
does not fit because path meaning is stable and the caller does enforce it.
4 is excluded because the canonical entry type itself admits invalid states.
- **Remaining ambiguity:** Unknown Git modes also collapse to `Blob`
(`git.rs:21-35`), but that compatibility question is not needed for the
score; the routine path shape is decisive.
### `fabro-checkpoint` × `duplication-knowledge`: 3
- **Decisive evidence:** The short branch name is converted to
`refs/heads/{branch}` independently in `Store::update_ref`, `resolve_ref`, and
`delete_ref` (`git.rs:182-225`), while the routine boundary writer carries a
second `full_ref` conversion
(`fabro-workflow/src/run_metadata.rs:364-439`). These are concrete repeated
representations, but of stable Git protocol knowledge.
- **Adjacent scores:** 4 does not fit revised rule 6 because the
branch-to-full-ref transformation has a concrete second representation. 2
does not fit because no ordinary mapped change is shown to require
synchronizing the stable Git namespace transformations; repeated call sites
alone are insufficient. 1 does not fit because the transformation and its
local authorities are clear.
- **Remaining ambiguity:** The literal can also be classified as harmless Git
syntax, which the lens excludes. Its repetition across the mapped boundary
supports 3, but the harmless-syntax distinction keeps confidence at Medium.