Repository navigation
Wave-1 Worker C — infer lens-import cleanup + std/outcome.dag traverse + extdeps/file_system.dag effects #3441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
2aa2868
d44629b
43b6fda
4db730c
e7e1df1
c732809
88b792c
3e05fb5
d175557
4dea97e
e2be249
2030009
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,24 @@ | ||
| // src/v4/extdeps/file_system.dag | ||
| // Scope: file system substrate — paths, file kinds, read/write/list/kind operations. | ||
| // Owns: PosixByteString, NamedPathComponent, PathComponent, AbsolutePath, RelativePathHead, RelativePath, Path, FileKind, FileKindResolutionPolicy, Filesystem, FileBody, file-system request/result/operation carriers. | ||
| // Consumes: Diagnostic, Outcome, Byte, FreeMonoid, List. | ||
| // Status: T-4.5 modeled 2026-05-16. | ||
| // Scope: file system substrate — paths, file kinds, modeled peripheral I/O effects. | ||
| // Owns: PosixByteString, NamedPathComponent, PathComponent, AbsolutePath, RelativePathHead, RelativePath, Path, FileKind, FileKindResolutionPolicy, Filesystem, FileBody, FileResource, FilePath, FileContent, FileRead, FileWrite, NodeFileBinding, FileEffectWitness, FileWriteWitness, file-system request/result/operation carriers, file_read, file_write. | ||
| // Consumes: std diagnostic, std outcome, std node, std algebra, std machine. | ||
| // Status: T-4.5 modeled; peripheral effect surface per design-v4-compiler-homomorphism (not compile-core). | ||
|
|
||
|
|
||
| module v4.extdeps.file_system | ||
|
|
||
|
|
||
| import v4.std.algebra { FreeMonoid } | ||
| import v4.std.diagnostic { Outcome } | ||
| import v4.std.diagnostic { | ||
| Diagnostic, | ||
| ExternalContractUnknown, | ||
| Outcome, | ||
| PortLocus, | ||
| Rejected, | ||
| Unavailable | ||
| } | ||
| import v4.std.machine { Byte } | ||
| import v4.std.node { Node, Symbol } | ||
|
|
||
|
|
||
| // Anchor: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap03.html#tag_03_241 | ||
|
|
@@ -71,6 +80,37 @@ type Filesystem | |
| // coincides: finite POSIX byte sequence. | ||
| type FileBody = FreeMonoid<Byte> | ||
|
|
||
| // Modeled resource — effects are explicit parameters against this carrier (B-5 DI). | ||
| type FileResource { | ||
| filesystem: Filesystem | ||
| } | ||
|
|
||
| // Peripheral effect path coordinate (absolute path for MVP shims). | ||
| type FilePath { | ||
| absolute: AbsolutePath | ||
| } | ||
|
|
||
| // Effect payload for read results. | ||
| type FileContent = FileBody | ||
|
|
||
| type FileWriteWitness { | ||
| resource: FileResource | ||
| path: FilePath | ||
| } | ||
|
|
||
| type NodeFileBinding { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BLOCKING: NodeFileBinding puts a compiler Node-to-path dependency fact inside an extdeps POSIX file-system model, violating the extdeps fidelity/layering invariant. |
||
| node: Node | ||
| path: FilePath | ||
| } | ||
|
|
||
| // 🟡 coproduct dissolution — W-TRAVERSE-OUTCOME-FILE-EFFECT-WITNESS. | ||
| // Trigger: ResourceDependsOn/EffectDependsOn wiring when std/dependency.dag lands (Worker A A1). | ||
| type FileEffectWitness | ||
This comment was marked as resolved.
Sorry, something went wrong.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BLOCKING: FileEffectWitness is not a single effect-coordinate authority: ReadWitness drops FileResource and FileWriteWitness drops content, so resource/path/payload facts do not flow forward for both effects. |
||
| = ReadWitness { path: FilePath, content: FileContent } | ||
| | WriteWitness { witness: FileWriteWitness } | ||
|
|
||
| data file_effect_dependency_wiring_deferred: Symbol = file_effect_dependency_wiring_deferred | ||
|
|
||
| type ReadFileRequest { | ||
| filesystem: Filesystem | ||
| path: AbsolutePath | ||
|
|
@@ -107,3 +147,36 @@ type FileSystemOperations { | |
| list_dir: fn(ListDirRequest) -> ListDirResult | ||
| file_kind: fn(FileKindRequest) -> FileKindResult | ||
| } | ||
|
|
||
| data file_read_effect_not_wired: Symbol = file_read_effect_not_wired | ||
|
|
||
| data file_write_effect_not_wired: Symbol = file_write_effect_not_wired | ||
|
|
||
| fn file_effect_not_wired_diagnostic(reason: Symbol) -> Diagnostic { | ||
| Diagnostic { | ||
| reason: reason, | ||
| at: PortLocus { port: reason }, | ||
| correction: Unavailable { reason: ExternalContractUnknown } | ||
| } | ||
| } | ||
|
|
||
| fn file_read( | ||
| resource: FileResource, | ||
| path: FilePath, | ||
| ops: FileSystemOperations | ||
| ) -> Outcome<FileContent> { | ||
| Rejected { | ||
| diagnostic: file_effect_not_wired_diagnostic(reason: file_read_effect_not_wired) | ||
| } | ||
| } | ||
|
|
||
| fn file_write( | ||
| resource: FileResource, | ||
| path: FilePath, | ||
| content: FileContent, | ||
| ops: FileSystemOperations | ||
| ) -> Outcome<FileWriteWitness> { | ||
| Rejected { | ||
| diagnostic: file_effect_not_wired_diagnostic(reason: file_write_effect_not_wired) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| // src/v4/std/outcome.dag | ||
| // Scope: Outcome traverse combinators + diagnostic policy carriers + traverse law witnesses. | ||
| // Owns: DiagnosticAccumulationPolicy, StageDiagnosticPolicy, NodeOutcomeFold, traverse_node, sequence_node, map_node_outcome, traverse_outcome, map_outcome, bind_outcome, append_non_empty, TraverseIdentityLaw, TraverseCompositionLaw, TraverseFailureMonotonicityLaw. | ||
| // Consumes: std diagnostic, std node, std collection, std algebra. | ||
| // Status: W-TraverseOutcome substrate (design-v4-compiler-homomorphism Ratified Q4 companion). | ||
|
|
||
|
|
||
| module v4.std.outcome | ||
|
|
||
|
|
||
| import v4.std.algebra { Empty, Cons } | ||
| import v4.std.collection { List } | ||
| import v4.std.diagnostic { | ||
| Diagnostic, | ||
| ExternalContractUnknown, | ||
| More, | ||
| NonEmptyDiagnostics, | ||
| One, | ||
| Outcome, | ||
| PortLocus, | ||
| Produced, | ||
| Rejected, | ||
| Unavailable | ||
| } | ||
| import v4.std.node { Edge, Node, Symbol } | ||
|
|
||
|
|
||
| // 🟡 coproduct dissolution — W-TRAVERSE-OUTCOME-DIAGNOSTIC-POLICY. | ||
| // Trigger: per-stage policy drives accumulate vs short-circuit in traverse_node fill. | ||
| type DiagnosticAccumulationPolicy | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
| = Accumulate | ||
| | ShortCircuit | ||
|
|
||
|
|
||
| type StageDiagnosticPolicy { | ||
| accumulation: DiagnosticAccumulationPolicy | ||
| } | ||
|
|
||
|
|
||
| data traverse_identity_law: TraverseIdentityLaw = traverse_identity_law | ||
|
|
||
|
|
||
| data traverse_composition_law: TraverseCompositionLaw = traverse_composition_law | ||
|
|
||
|
|
||
| data traverse_failure_monotonicity_law: TraverseFailureMonotonicityLaw = traverse_failure_monotonicity_law | ||
|
|
||
|
|
||
| type TraverseIdentityLaw {} | ||
|
|
||
|
|
||
| type TraverseCompositionLaw {} | ||
|
|
||
|
|
||
| type TraverseFailureMonotonicityLaw {} | ||
|
|
||
|
|
||
| fn append_non_empty(front: NonEmptyDiagnostics, back: NonEmptyDiagnostics) -> NonEmptyDiagnostics { | ||
| match front { | ||
| One { diagnostic: d } => match back { | ||
| One { diagnostic: d2 } => More { head: d, tail: One { diagnostic: d2 } } | ||
| More { head: h, tail: t } => More { head: d, tail: More { head: h, tail: t } } | ||
| } | ||
| More { head: h, tail: t } => More { head: h, tail: append_non_empty(front: t, back: back) } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| type NodeOutcomeFold<R> { | ||
| policy: StageDiagnosticPolicy | ||
| init: fn(Node) -> Outcome<R> | ||
| step: fn(Outcome<R>, Edge, Node) -> Outcome<R> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BLOCKING: NodeOutcomeFold.step receives Outcome, so each fold algebra can independently implement short-circuit or accumulation despite StageDiagnosticPolicy, duplicating the failure-policy authority and violating P2/API-level enforcement. |
||
| } | ||
|
|
||
|
|
||
| data traverse_node_not_realized: Symbol = traverse_node_not_realized | ||
|
|
||
|
|
||
| fn traverse_node_not_realized_diagnostic() -> Diagnostic { | ||
| Diagnostic { | ||
| reason: traverse_node_not_realized, | ||
| at: PortLocus { port: traverse_node_not_realized }, | ||
| correction: Unavailable { reason: ExternalContractUnknown } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| fn traverse_node<R>(n: Node, algebra: NodeOutcomeFold<R>) -> Outcome<R> { | ||
| Rejected { diagnostic: traverse_node_not_realized_diagnostic() } | ||
| } | ||
|
|
||
|
|
||
| fn sequence_node<R>(nodes: List<Node>, algebra: NodeOutcomeFold<R>) -> Outcome<List<R>> { | ||
| Rejected { diagnostic: traverse_node_not_realized_diagnostic() } | ||
| } | ||
|
|
||
|
|
||
| fn map_node_outcome<T, U>(o: Outcome<T>, f: fn(T) -> Outcome<U>) -> Outcome<U> { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BLOCKING: map_node_outcome has the same generic signature and behavior as bind_outcome, creating two authorities for Outcome bind and violating P2 single-authority. |
||
| match o { | ||
| Rejected { diagnostic: d } => Rejected { diagnostic: d } | ||
| Produced { value: v } => f(v) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| fn traverse_outcome<T, U>(xs: List<T>, f: fn(T) -> Outcome<U>) -> Outcome<List<U>> { | ||
| match xs { | ||
| Empty => Produced { value: Empty } | ||
| Cons { head: h, tail: t } => match f(h) { | ||
| Rejected { diagnostic: d } => Rejected { diagnostic: d } | ||
| Produced { value: u } => | ||
| match traverse_outcome(xs: t, f: f) { | ||
| Rejected { diagnostic: d } => Rejected { diagnostic: d } | ||
| Produced { value: rest } => Produced { value: Cons { head: u, tail: rest } } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| fn map_outcome<T, U>(o: Outcome<T>, f: fn(T) -> U) -> Outcome<U> { | ||
| match o { | ||
| Rejected { diagnostic: d } => Rejected { diagnostic: d } | ||
| Produced { value: v } => Produced { value: f(v) } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| fn bind_outcome<T, U>(o: Outcome<T>, f: fn(T) -> Outcome<U>) -> Outcome<U> { | ||
| match o { | ||
| Rejected { diagnostic: d } => Rejected { diagnostic: d } | ||
| Produced { value: v } => f(v) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BLOCKING: InferredFacts now removes cost as lens-side, but unchanged constructors in src/v4/test/claim/manual/infer_emit_compile_anchor.dag:75 and src/v4/test/claim/workflow/pipeline_rejections.dag:177 still set cost, so the stage boundary is not migrated and violates facts-flow-forward/API-level enforcement.