Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 168 additions & 16 deletions dag/extdeps/filesystem/filesystem_io.dag

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions dag/gunbc/deploy_transition.dag
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import extdeps.filesystem.filesystem_io {
FilesystemFileRead,
FilesystemFileIndeterminate,
FilesystemFileObservationsDisagree,
FilesystemFileSubjectRefused,
filesystem_read_outcome,
filesystem_listing_observation,
filesystem_file_observation,
Expand Down Expand Up @@ -389,6 +390,10 @@ type TransitionFileObservation
// disagreement are all decided by `filesystem_file_observation`; what is genuinely this module's is
// that a file which read cleanly may still not be a transition record, which is a fourth way to be
// indeterminate and is not a filesystem fact.
// A REFUSED SUBJECT IS THIS FUNCTION'S CALLER'S DEFECT, NOT THE HOST'S. `FilesystemFileSubjectRefused`
// lands in the indeterminate arm here because a transition that cannot be observed must not proceed
// either way -- but the cause names the ARGUMENT rather than the host, so the two remedies stay
// separable to whoever reads the refusal.
fn transition_file_observation_of(
observed: FilesystemFileObservation,
path: String,
Expand All @@ -403,6 +408,13 @@ fn transition_file_observation_of(
TransitionFileObservationsDisagree {
cause: join(["gunbc.deploy_transition: ", why], ""),
}
FilesystemFileSubjectRefused { directory: d, name: n, cause: why } =>
TransitionFileIndeterminate {
cause: join([
"gunbc.deploy_transition: the marker ", n, " was requested under ", d,
", which is not a directory subject, so the supplied outcomes establish no observation of it -- ", why,
], ""),
}
FilesystemFileRead { path: _, content: c } =>
match transition_record_decode(text: c) {
TransitionRecordUndecodable { cause: why } =>
Expand Down
13 changes: 13 additions & 0 deletions dag/gunbc/devboot/build.dag
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import extdeps.filesystem.filesystem_io {
FilesystemFileRead,
FilesystemFileIndeterminate,
FilesystemFileObservationsDisagree,
FilesystemFileSubjectRefused,
}
import extdeps.git
import extdeps.git.plumbing
Expand Down Expand Up @@ -190,6 +191,11 @@ type TextFileReadOutcome
// say" and carries on. Presence is now decided by a successful listing of the directory the caller
// already names, so TextFileAbsent is reachable only from an established absence and every failure
// to look lands in TextFileReadFailed.
// THE COLLAPSE IS DECIDED HERE RATHER THAN INHERITED. This reader has three states and no fourth to
// offer, so a refused subject stops it the same way an unmakeable observation does -- but the cause
// says WHICH, so the reader of the failure is not left guessing whether to fix the host or the
// argument. That is the difference between collapsing a distinction visibly at the policy-owning
// consumer and losing it inside a generic fold.
fn read_text_file(dir: String, name: String) -> TextFileReadOutcome {
let path = join([dir, "/", name], "")
let listing = Filesystem.List(path: dir)
Expand All @@ -213,6 +219,13 @@ fn read_text_file(dir: String, name: String) -> TextFileReadOutcome {
FilesystemFileRead { path: _, content: text } => TextFilePresent { text: trim(s: text) }
FilesystemFileIndeterminate { cause: c } => TextFileReadFailed { error: c }
FilesystemFileObservationsDisagree { path: _, cause: c } => TextFileReadFailed { error: c }
FilesystemFileSubjectRefused { directory: d, name: n, cause: c } =>
TextFileReadFailed {
error: join([
"gunbc.devboot.build was asked to read ", n, " under a directory that is not a directory ",
"subject (", d, "), so the supplied outcomes establish no read of it -- ", c,
], ""),
}
}
}

Expand Down
21 changes: 21 additions & 0 deletions dag/gunbc/fleet/fleet_converge_plan_cli.dag
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import extdeps.filesystem.filesystem_io {
FilesystemEntryAbsent,
FilesystemEntryListed,
FilesystemEntryPresenceIndeterminate,
FilesystemEntrySubjectRefused,
}
import extdeps.exec.command { ArgvCommand, LocalExec }
import extdeps.tools.hostname { hostname_short_read_command }
Expand Down Expand Up @@ -209,6 +210,10 @@ fn fleet_converge_apply_spark_admission(host: HostIdentity) -> FleetConvergeAppl
// fleet_converge_apply_spark_admission stays a separate pure declaration because a wet func carries
// no executable evidence. It is not a helper standing beside the production path: it is the only
// thing between the FullHost arm and a constructed request.
// A REFUSED SUBJECT IS THE SPEC'S DEFECT, NOT THE HOST'S. Both observation paths below take the same
// stop they already took for an unmakeable observation, and that collapse is written down here rather
// than inherited: the cause names the spec's own path so the remedy is the spec rather than a hunt
// through host permissions.
fn spark_axis_for_unobserved_cli(
host: HostIdentity,
) -> SparkServingAxisDisposition<FleetConvergeSparkServingTypedAction> {
Expand Down Expand Up @@ -458,6 +463,14 @@ func observe_allocation_store_substrate_wet() -> AllocationStoreSubstrateObserva
) {
FilesystemEntryPresenceIndeterminate { cause: why } =>
AllocationStoreSubstrateObservationRefused { path: spec.namespace_path, cause: why }
FilesystemEntrySubjectRefused { directory: d, name: n, cause: why } =>
AllocationStoreSubstrateObservationRefused {
path: spec.namespace_path,
cause: join([
"the spec asked about ", n, " under ", d,
", which is not a directory subject, so the supplied outcomes establish no listing of it -- ", why,
], ""),
}
FilesystemEntryAbsent(established) => AllocationStoreSubstrateObserved {
prestate: AllocationStoreNamespaceAbsent {
namespace: allocation_store_directory_absent(path: spec.namespace_path, evidence: established),
Expand Down Expand Up @@ -515,6 +528,14 @@ func observe_allocation_store_under_namespace_wet(
) {
FilesystemEntryPresenceIndeterminate { cause: why } =>
AllocationStoreSubstrateObservationRefused { path: spec.path, cause: why }
FilesystemEntrySubjectRefused { directory: d, name: n, cause: why } =>
AllocationStoreSubstrateObservationRefused {
path: spec.path,
cause: join([
"the spec asked about ", n, " under ", d,
", which is not a directory subject, so the supplied outcomes establish no listing of it -- ", why,
], ""),
}
FilesystemEntryAbsent(established) => AllocationStoreSubstrateObserved {
prestate: AllocationStoreNamespacePresent {
namespace: namespace,
Expand Down
13 changes: 13 additions & 0 deletions dag/gunbc/generated_artifact_observation.dag
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import extdeps.filesystem.filesystem_io {
FilesystemFileRead,
FilesystemFileIndeterminate,
FilesystemFileObservationsDisagree,
FilesystemFileSubjectRefused,
filesystem_listing_observation,
filesystem_read_outcome,
filesystem_file_observation,
Expand Down Expand Up @@ -79,6 +80,9 @@ fn observe_directory_listings(directories: List<String>) -> List<DirectoryListin
// precise error this whole change removes. The empty case therefore refuses and names itself, so a
// bookkeeping defect surfaces as a defect rather than as a verdict about the repository tree.

// A REFUSED SUBJECT REACHES THE REFUSAL STATE THIS MODULE ALREADY OWNS, and the cause says the
// artifact's own path was inadmissible rather than that the host misbehaved. The stop is the same;
// the remedy it points at is not.
fn observe_generated_artifact_with(a: GeneratedArtifact, rows: List<DirectoryListingRow>) -> GeneratedArtifactObservation {
let loc = artifact_location(a: a)
let path = artifact_path(a: a)
Expand Down Expand Up @@ -107,6 +111,15 @@ fn observe_generated_artifact_with(a: GeneratedArtifact, rows: List<DirectoryLis
GeneratedArtifactObservationRefused { artifact: a, path: path, cause: cause }
FilesystemFileObservationsDisagree { path: _, cause } =>
GeneratedArtifactObservationRefused { artifact: a, path: path, cause: cause }
FilesystemFileSubjectRefused { directory: d, name: n, cause } =>
GeneratedArtifactObservationRefused {
artifact: a,
path: path,
cause: join([
"the artifact path names ", n, " under ", d,
", which is not a directory subject, so the supplied outcomes establish no observation of it -- ", cause,
], ""),
}
FilesystemFileRead { path: _, content: committed_content } =>
match artifact_generate(a: a) {
ArtifactGenerationRefused { reason } =>
Expand Down
19 changes: 19 additions & 0 deletions dag/gunbc/roadmap/roadmap_belt_actuate.dag
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,12 @@ import extdeps.filesystem.filesystem_io {
FilesystemEntryAbsent,
FilesystemEntryListed,
FilesystemEntryPresenceIndeterminate,
FilesystemEntrySubjectRefused,
FilesystemFileAbsent,
FilesystemFileRead,
FilesystemFileIndeterminate,
FilesystemFileObservationsDisagree,
FilesystemFileSubjectRefused,
filesystem_listing_observation,
filesystem_entry_presence,
filesystem_read_outcome,
Expand Down Expand Up @@ -3497,6 +3499,9 @@ fn provider_event_projection_error(
// mint consumes a successful directory listing; this module carries neither a prose copy of that
// law nor a second spelling of List's membership encoding. Listing refusal, listed-but-unreadable,
// and disagreeing observations all project to ReceiptSourceUnreadable.
// A REFUSED SUBJECT IS UNREADABLE, NEVER ABSENT. A subject that was never admitted established no
// absence, so answering `ReceiptSourceAbsent` for it would be exactly the fail-open the filesystem
// fold exists to prevent -- a receipt reported as not-there on outcomes that establish nothing.
fn belt_publication_receipt_source(
instance: HostDashboardInstance,
node_id: RoadmapNodeId,
Expand All @@ -3523,6 +3528,13 @@ fn belt_publication_receipt_source(
) {
FilesystemEntryPresenceIndeterminate { cause: c } =>
ReceiptSourceUnreadable { detail: c }
FilesystemEntrySubjectRefused { directory: d, name: n, cause: c } =>
ReceiptSourceUnreadable {
detail: join([
"the attempt directory ", d, " is not a directory subject, so ", n,
" is established by nothing the fold received -- ", c,
], ""),
}
FilesystemEntryAbsent(_) => ReceiptSourceAbsent
FilesystemEntryListed { directory: _, name: _ } => {
let publication_dir = dispatch_attempt_publication_dir_for_instance(
Expand Down Expand Up @@ -3558,6 +3570,13 @@ fn belt_publication_receipt_source(
ReceiptSourceUnreadable { detail: c }
FilesystemFileObservationsDisagree { path: _, cause: c } =>
ReceiptSourceUnreadable { detail: c }
FilesystemFileSubjectRefused { directory: d, name: n, cause: c } =>
ReceiptSourceUnreadable {
detail: join([
"the publication directory ", d, " is not a directory subject, so ", n,
" is established by nothing the fold received -- ", c,
], ""),
}
FilesystemFileAbsent(_) => ReceiptSourceAbsent
FilesystemFileRead { path: _, content: text } =>
ReceiptSourcePresent { text: text }
Expand Down
28 changes: 28 additions & 0 deletions dag/gunbc/roadmap/roadmap_verification_receipt.dag
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,14 @@ import extdeps.filesystem.filesystem_io {
FilesystemEntryAbsent,
FilesystemEntryListed,
FilesystemEntryPresenceIndeterminate,
FilesystemEntrySubjectRefused,
filesystem_entry_presence,
FilesystemFileObservation,
FilesystemFileAbsent,
FilesystemFileRead,
FilesystemFileIndeterminate,
FilesystemFileObservationsDisagree,
FilesystemFileSubjectRefused,
filesystem_file_observation,
}
import gunbc.git_diff_change_window { git_diff_window_absent_identity }
Expand Down Expand Up @@ -443,6 +445,10 @@ fn current_verification_selection_decode_document(
// arms below are a translation into this module's vocabulary rather than a second statement of the
// rule -- and a future edit here cannot reintroduce the conflation, because there is no way to
// construct the absent arm from a read.
// A REFUSED SUBJECT IS UNREADABLE, NEVER ABSENT. The verification root was not a directory
// subject, so the outcomes handed to the fold establish no absence -- and reading an absence off
// them anyway would be fail-open. This says nothing about whether the host was asked; the fold is
// pure over outcomes its caller already obtained.
fn current_verification_selection_observe(
attempt_dir: String,
verification_dir: String,
Expand All @@ -458,6 +464,13 @@ fn current_verification_selection_observe(
),
name: verification_directory_segment,
) {
FilesystemEntrySubjectRefused { directory: d, name: n, cause: c } =>
SelectionUnreadable {
cause: join([
"the verification root ", d, " is not a directory subject, so ", n,
" is established by nothing the fold received: ", c,
], ""),
}
FilesystemEntryPresenceIndeterminate { cause: c } =>
SelectionUnreadable {
cause: join([
Expand Down Expand Up @@ -491,6 +504,10 @@ fn current_verification_selection_observe(
FilesystemFileIndeterminate { cause: c } => SelectionUnreadable { cause: c }
FilesystemFileObservationsDisagree { path: _, cause: c } =>
SelectionUnreadable { cause: c }
FilesystemFileSubjectRefused { directory: d, name: n, cause: c } =>
SelectionUnreadable {
cause: join([d, " is not a directory subject, so ", n, " is established by nothing the fold received: ", c], ""),
}
FilesystemFileAbsent(_) => SelectionAbsent
FilesystemFileRead { path: _, content: text } =>
current_verification_selection_decode_document(
Expand Down Expand Up @@ -519,6 +536,13 @@ fn exact_verification_receipt_source_read(
),
name: verification_directory_segment,
) {
FilesystemEntrySubjectRefused { directory: d, name: n, cause: c } =>
ExactVerificationReceiptUnreadable {
detail: join([
"the verification root ", d, " is not a directory subject, so ", n,
" is established by nothing the fold received: ", c,
], ""),
}
FilesystemEntryPresenceIndeterminate { cause: c } =>
ExactVerificationReceiptUnreadable {
detail: join([
Expand Down Expand Up @@ -549,6 +573,10 @@ fn exact_verification_receipt_source_read(
ExactVerificationReceiptUnreadable { detail: c }
FilesystemFileObservationsDisagree { path: _, cause: c } =>
ExactVerificationReceiptUnreadable { detail: c }
FilesystemFileSubjectRefused { directory: d, name: n, cause: c } =>
ExactVerificationReceiptUnreadable {
detail: join([d, " is not a directory subject, so ", n, " is established by nothing the fold received: ", c], ""),
}
FilesystemFileAbsent(_) => ExactVerificationReceiptAbsent
FilesystemFileRead { path: _, content: text } =>
ExactVerificationReceiptPresent { text: text }
Expand Down
16 changes: 16 additions & 0 deletions dag/gunbc/scm/init.dag
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import extdeps.filesystem.filesystem_io {
FilesystemFileRead,
FilesystemFileIndeterminate,
FilesystemFileObservationsDisagree,
FilesystemFileSubjectRefused,
filesystem_listing_observation,
filesystem_read_outcome,
filesystem_file_observation
Expand Down Expand Up @@ -235,6 +236,11 @@ fn init_outcome_of_save(save: RepositorySave) -> ScmInitOutcome {
// the write arm left every enrolled claim green. Separating the fold from the two operations that
// feed it makes the four arms drivable one fact apart, which is the difference between a tested
// decision and a tested renderer.
// INIT REFUSES RATHER THAN CREATING, WHICH IS THE ONLY SAFE ARM FOR A REFUSED SUBJECT.
// `ScmInitMayCreate` is reachable only from an ESTABLISHED absence, and a subject that was never
// admitted established nothing -- so a subject refusal cannot fall through to the create. It
// collapses into this module's unobserved cause VISIBLY, and the text says the repository path was
// not a directory subject, so the operator fixes the argument rather than hunting a host fault.
fn scm_init_decision(observation: FilesystemFileObservation, path: String) -> ScmInitDecision {
match observation {
FilesystemFileAbsent(absence) => ScmInitMayCreate(absence)
Expand All @@ -244,5 +250,15 @@ fn scm_init_decision(observation: FilesystemFileObservation, path: String) -> Sc
ScmInitDecided { cause: ScmInitPathUnobserved { path: path, cause: c } }
FilesystemFileObservationsDisagree { path: p, cause: c } =>
ScmInitDecided { cause: ScmInitPathUnobserved { path: p, cause: c } }
FilesystemFileSubjectRefused { directory: d, name: n, cause: c } =>
ScmInitDecided {
cause: ScmInitPathUnobserved {
path: path,
cause: join([
"the repository ", n, " was requested under ", d,
", which is not a directory subject, so the supplied outcomes establish no observation of it, and no create is authorized -- ", c,
], ""),
},
}
}
}
Loading
Loading