mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
24 KiB
24 KiB
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-80presentsWorkflowLifecycleas the callback owner, andlifecycle/git.rs:77-93, 397-401givesGitLifecycleits ownlast_git_shastate. The normalRunSession::runpath nevertheless creates a secondlast_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 inpipeline/finalize.rs:524-596, while bootstrap, initialization, and finalization errors becomerun.failedthrough the outer operation inoperations/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-953is a recognizable top-level owner for the initialize → execute → finalize → pull-request sequence, andWorkflowLifecycleexplicitly 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.statusasString(event/events.rs:264-272). Both synthetic terminal-stage completion and ordinary successful stage completion stringify the canonicalStageOutcome(lifecycle/event.rs:215-240, 355-366), after which the mandatory event conversion reparses it and converts an unknown value toFailed(event/convert.rs:14-24, 309-333). This typed → string → typed path is part of every successful stage-completion event. - Strongest counterevidence:
fabro_types::StageOutcomeis 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:
ProxyPolicyis a closedSystem | Disabledvocabulary; parsing rejects every other boundary value (src/lib.rs:23-35). Resolution gives explicit configuration precedence over the environment, defaults absence toSystem, 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 typedDisabledvalue (src/lib.rs:195-213). - Strongest counterevidence: The builder also exposes raw
no_proxy()andproxy()operations (src/lib.rs:96-106), so callers can combine an underlying reqwest choice withProxyPolicy; Unix-socket production callers do useno_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 weakenProxyPolicy::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-49owns browser startup, chooses the normal or installation route graph once, and installs shared SWR runtime policy.router.tsx:97-184owns normal route composition. Shared transport and error handling live inlib/api-client.ts:64-160, 213-310; shared reads such asuseRunanduseRunStatelive inlib/queries.ts:182-193; run mutations and their cache lifecycle live inlib/mutations.ts:65-132; and run-scoped SSE subscription, invalidation, resync, and cleanup live inlib/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-205coordinates 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/useRunexample, 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-40owns 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-34owns the corresponding TypeScript triggers and concurrency, and its jobs contain typecheck, test, and integrated SPA/Rust build lifecycles (typescript.yml:36-77). Delegation tocargo devis 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 isdocs/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 zizmorstale-action-refsidentifiers targetrust.yml:37,:49, and:62(zizmor.yml:1-6), which are respectively the end of trigger setup, thefmtjob key, and aruncommand—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 drivesStorethrough blobs, tree, commit, and ref update, and retains the parent identity for the next write (run_metadata.rs:313-350).BranchStoreprovides 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-workflowdepends onfabro-checkpoint), and the low-levelStoreconsistently 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
Storenarrows the mapped ownership claim; the explicit mapped claim to metadata branches makes this crossing discriminating.
simplicity: 4
- Evidence: The production
Storehas 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_withis 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
Storeinstead ofBranchStore. - 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::setaccepts anyStringpath without validation (git.rs:46-60), andwrite_treelater interprets it by splitting on/(git.rs:149-153, 270-293). The common metadata caller must therefore define and applyvalidate_metadata_pathoutside this component before everyTreeEntriesconstruction (fabro-workflow/src/run_metadata.rs:313-332, 471-480). The component also maps every unrecognized Git file mode toBlob(git.rs:21-35, 229-250) rather than rejecting an unsupported state. - Strongest counterevidence:
FileModeis otherwise a closed enum, Git object IDs usegit2::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
TreeEntriesshape 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
TreeEntriesintermediate 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, anddelete_ref(git.rs:182-225), and the boundary metadata writer has anotherfull_reftransformation (fabro-workflow/src/run_metadata.rs:364-439).BranchStore::read_entry,read_entries,list_entries, andtip_treealso 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 oneMETA_BRANCH_PREFIXconstant (lib.rs:7), Git-author defaults have oneDefaultimplementation (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 exposedno_proxy()builder operation (src/lib.rs:96-100). The former is interpreted by calling the same underlyinginner.no_proxy()transformation duringbuild(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 selectsno_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 becauseProxyPolicy::Disabledis 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.yamlin 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 nonexistentopenapi/**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:76also 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
Storeprimitives, while the routine metadata caller reconstructs the mapped branch lifecycle:RunMetadataWriterowns 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-levelBranchStore. - 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-checkpointcould make this healthy delegation, but the actual map explicitly assigns metadata branches and checkpoint commits.
fabro-checkpoint × simplicity: 3
- Decisive evidence:
Cargo.toml:16-24carriesfabro-storeas a production dependency, but scoped production code does not use it. The component also exposesBranchStoreas a parallel entry layer (branch.rs:17-24) that has no production caller at this revision; the common metadata path usesStoredirectly. The activeStorepath 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
Storepath 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::setaccepts arbitrary string paths (git.rs:46-60) beforewrite_treeinterprets them structurally (git.rs:149-153, 270-293). Every common metadata snapshot must validate those paths outside the mapped entry before constructingTreeEntries(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 inStore::update_ref,resolve_ref, anddelete_ref(git.rs:182-225), while the routine boundary writer carries a secondfull_refconversion (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.