Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3e18553
The merge driver's repair recipes: one refuses, one is mangled by the…
Sep 4, 2026
e8a593a
Hold the failure-mode row out of this branch: roster.dag and docs/des…
Sep 4, 2026
fb2d9f2
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 4, 2026
50cf62b
The extractor may not take $1: the driver's own argv was substituting…
Sep 4, 2026
a2a9c62
Merge remote-tracking branch 'origin/session/calm-owl-417' into sessi…
Sep 4, 2026
0f53ad6
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 4, 2026
ae2af2c
Dissolve the second escaper into the shared authority, and declare th…
Sep 4, 2026
6dafe7c
My own witness was written against the authored string, not the emitt…
Sep 4, 2026
026d4e8
Merge remote-tracking branch 'origin/main' into session/calm-owl-417
Sep 4, 2026
5cf893e
Execute the merge driver's printed recipe, do not read it
Sep 5, 2026
0649a5d
Merge remote-tracking branch 'origin/session/calm-owl-417' into sessi…
Sep 5, 2026
6fed2cd
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
5b4fee3
Execute the merge driver's printed recipe, do not read it
Sep 5, 2026
80cebab
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
9f68fe7
File the class the driver's own defect belongs to, and hoist an annot…
Sep 5, 2026
8347884
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
84a8dec
Enroll the positive control and both mutation controls: cited but une…
Sep 5, 2026
1b0f07f
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
e77236b
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 5, 2026
eb9bfb7
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
452a9ac
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
ccd8795
Regenerate the ledger projection locally, and record the substitution…
Sep 5, 2026
0debb8a
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
5ed9075
Regenerate the projection from the merged authority: neither side's b…
Sep 5, 2026
081bc1d
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
4aa3ab3
Regenerate the projection from the merged authority (three rows, two …
Sep 5, 2026
0410429
Merge remote-tracking branch 'origin/main' into session/wise-bat-147
Sep 5, 2026
754f472
Regenerate the failure-mode projection over the merged roster
Sep 5, 2026
bfa4c91
Merge main into session/wise-bat-147; defer projection to CI heal
Sep 5, 2026
e3d6d50
chore: regenerate drifted generated artifacts (ci auto-heal)
Sep 5, 2026
37abab7
Merge main into session/wise-bat-147; defer projection to CI heal
Sep 5, 2026
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
38 changes: 37 additions & 1 deletion dag/extdeps/tools/sed.dag
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module extdeps.tools.sed

import std.types { NonEmptyStr, String, Bool }
import std.types { NonEmptyStr, String, Bool, Int }
import extdeps.external_authority { ExternalAuthority }
import extdeps.uri { Uri, Https }
import extdeps.exec.command { ArgvCommand, argv_command }
Expand All @@ -19,6 +19,21 @@ data sed_cli_tool: CliTool = CliTool {
installable_via: [SourceCoreutils],
}

// ScriptsSuppressAutoPrint -- sed -n with its scripts passed as ARGUMENTS: auto-print suppressed, so the only output is what
// a script's own `p` flag prints. GNU sed manual, Overview / Command-Line Options: -n ('--quiet',
// '--silent') 'suppress automatic printing of pattern space', and -e ('--expression') 'add the
// script to the commands to be executed', which is what makes a multi-clause program ONE program
// rather than a pipeline of them. The scripts are argv entries rather than text spliced into a
// shell word, which is the whole reason this operation exists as a modeled row: a caller
// executing a program it received from somewhere else must not have that program re-read by a
// shell on the way in.
//
// `arguments` takes the output of sed_script_arguments below and nothing else. The -e spelling
// lives there, next to the -i spelling, for the same reason: one place per flag.
//
// stdout_lines rather than stdout, because the consumer question is HOW MANY rows the program
// extracted and WHICH -- and a zero-length stdout and a refusal are indistinguishable as one
// string, which is the failure this operation's first consumer exists to catch.
service sed.Sed {
operation InPlaceSubstitute {
input { expression: NonEmptyStr, path: NonEmptyStr }
Expand All @@ -29,6 +44,17 @@ service sed.Sed {
nonzero => String "sed -i failed"
}
}

operation ScriptsSuppressAutoPrint {
input { arguments: List<String>, path: NonEmptyStr }
output {
lines: List<String> from "stdout_lines"
exit_code: Int from "exit_code"
stderr: String from "stderr"
}
readonly
transport shell { argv: ["sed", "-n", arguments, "{path}"] }
}
}

// The same in-place substitution the service operation above declares, addressed as an ArgvCommand
Expand All @@ -43,3 +69,13 @@ data sed_program: NonEmptyStr = "sed"
fn sed_in_place_command(expression: String, path: String) -> ArgvCommand {
argv_command(program: sed_program, arguments: ["-i", expression, path])
}

// The -e flag pairing, spelled once. A caller names the scripts its program is made of; this
// derives the argv sed reads them from, so a consumer that also RENDERS the program as text can
// build both from one list of expressions rather than keeping a rendered copy beside an executed
// one.
fn sed_script_arguments(expressions: List<String>) -> List<String> {
fold(expressions, init: [], f: (acc, e) => append(acc, items: [sed_script_expression_flag, e]))
}

data sed_script_expression_flag: String = "-e"
5 changes: 5 additions & 0 deletions dag/gunbc/ci/ci_layer_roots.dag
Original file line number Diff line number Diff line change
Expand Up @@ -1329,7 +1329,12 @@ data bin_witness_wet_entries: List<ScheduleWitnessEntry> = [
bin_wet(entry: "dag/test/claim/contract_identity/required_ci_epoch_real_execution_witness_test.dag", f: "a_run_of_the_contract_at_the_required_epoch_admits_by_real_execution"),
bin_wet(entry: "dag/test/claim/contract_identity/required_ci_epoch_real_execution_witness_test.dag", f: "a_commit_that_is_not_in_the_repository_is_unreadable_not_absent_by_real_execution"),
bin_wet(entry: "dag/test/claim/contract_identity/required_ci_epoch_real_execution_witness_test.dag", f: "a_readable_commit_without_the_workflow_is_path_absent_not_commit_unreadable_by_real_execution"),
bin_wet(entry: "dag/test/claim/generated_artifact_merge_driver_real_execution_witness_test.dag", f: "row_extractor_names_a_row_that_went_dark_by_real_execution"),
bin_wet(entry: "dag/test/claim/generated_artifact_merge_driver_real_execution_witness_test.dag", f: "row_extractor_reconciles_with_both_rosters_by_real_execution"),
bin_wet(entry: "dag/test/claim/generated_artifact_merge_driver_real_execution_witness_test.dag", f: "row_extractor_refuses_a_duplicated_identity_by_real_execution"),
bin_wet(entry: "dag/test/claim/generated_artifact_merge_driver_real_execution_witness_test.dag", f: "row_extractor_refuses_a_substituted_identity_by_real_execution"),
bin_wet(entry: "dag/test/claim/generated_artifact_merge_driver_real_execution_witness_test.dag", f: "divergent_generated_artifact_merge_refuses_by_real_execution"),
bin_wet(entry: "dag/test/claim/generated_artifact_merge_driver_real_execution_witness_test.dag", f: "driver_printed_step_two_carries_the_row_extractor_by_real_execution"),
bin_wet(entry: "dag/test/claim/generated_artifact_merge_driver_real_execution_witness_test.dag", f: "divergent_generated_artifact_merge_under_true_driver_silently_drops_theirs_red_control_by_real_execution"),
bin_wet(entry: "dag/test/claim/generated_artifact_merge_driver_real_execution_witness_test.dag", f: "one_sided_generated_artifact_change_merges_clean_by_real_execution"),
bin_wet(entry: "dag/test/claim/commit_writer_heal_admission_real_execution_witness_test.dag", f: "clean_staged_index_admits_by_real_execution"),
Expand Down
60 changes: 59 additions & 1 deletion dag/gunbc/generated_artifact_merge_driver.dag
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module gunbc.generated_artifact_merge_driver

import gunbc.shell_bash_runner { bash_escape_double_quote_specials_except_expansion }
import extdeps.tools.sed { sed_script_arguments }
import extdeps.posix.shell_command_language { posix_single_quote }
import std.dissolution { DissolutionCondition, unbound_dissolution }

// THE MERGE DRIVER FOR merge=generated-artifact PATHS, AND WHY IT REFUSES INSTEAD OF ANSWERING
Expand Down Expand Up @@ -133,10 +135,66 @@ fn generated_artifact_merge_driver_repair_steps(regen_command: String) -> List<S
// authority-ahead-of-artifact by exactly this branch's own rows, which is the state heal exists
// to repair and which the generated-artifact gate can still see. What it removes is the DELETION,
// which nothing downstream can see at all.
// THE EXTRACTOR IS THE ONE PRINTED LINE THAT IS A PROGRAM RATHER THAN PROSE, AND IT IS DECLARED
// RATHER THAN SPELLED so that the program a lane is told to run and the program a witness executes
// are ONE declaration. This is the same one-concept-two-names problem the escaper above had, one
// layer up: the recipe now carries TWO sed clauses because the two delegated projections spell a row
// identity differently, and two clauses inside a prose sentence are two things any executed copy can
// drift from. `-e` is not spelled here -- extdeps.tools.sed sed_script_arguments owns that pairing,
// beside the `-i` it already owned -- and the single-quote wrapping is
// extdeps.posix.shell_command_language posix_single_quote rather than a literal quote pair, because
// the recipe is placing a program inside a shell word and that encoding has an authority.
//
// WHAT THE DECLARATION BUYS, concretely: test.claim.generated_artifact_merge_driver_real_execution
// runs THESE expressions through real sed over a fixture built from the two rosters and requires the
// extraction to name every rostered row. That is a coverage join rather than a non-emptiness check,
// and it is the enrolled form of the hole this recipe carried on docs/design-rung-drops.md -- a
// correct program pointed at a row shape it could not match, which rendered perfectly and read zero
// of 35 rows. Dropping either clause reds that witness; the recipe reading as sensible English does
// not.
//
// THE EMITTED BYTES ARE UNCHANGED by this lift, which is the point: the recipe a lane pastes is the
// same recipe, now derived from the expressions instead of restating them.

data generated_artifact_merge_driver_row_identity_extraction_expressions: List<String> = [
"s/^- `\\([a-z0-9_]*\\)`.*/\\1/p",
"s/^### \\(.*\\) — .*/\\1/p",
]

fn generated_artifact_merge_driver_row_extractor_function() -> String {
join(
[
"rows() { sed -n ",
join(
sed_script_arguments(
expressions: map(
generated_artifact_merge_driver_row_identity_extraction_expressions,
e => posix_single_quote(spelling: e)
)
),
" "
),
" | sort; }",
],
""
)
}

fn generated_artifact_merge_driver_dark_row_set_difference_step() -> String {
join(
[
"2. VERIFY BY SET DIFFERENCE THAT NO ROW WENT DARK, never by count. The two projections carry DIFFERENT row identities -- a failure mode is a `slug` bullet, a rung drop is a `### Title — declared ...` heading -- so one extractor must name both, or the check reads zero rows on the file it cannot parse and reports a pass it never measured: ",
generated_artifact_merge_driver_row_extractor_function(),
"; comm -23 <(git show <base-ref>:$merged_path | rows) <(git show HEAD:$merged_path | rows) MUST BE EMPTY. A count tells you a number moved; only the difference names WHICH rows went dark, and the name is the whole finding",
],
""
)
}

fn generated_artifact_merge_driver_heal_repair_steps() -> List<String> {
[
"1. take the BASE side's projection verbatim -- git checkout <base-ref> -- $merged_path -- and do NOT stage the bytes sitting in your worktree: those are the OURS side, and staging them commits your rows over the base's, deleting every row the base added since the merge base",
"2. VERIFY BY SET DIFFERENCE THAT NO ROW WENT DARK, never by count. The two projections carry DIFFERENT row identities -- a failure mode is a `slug` bullet, a rung drop is a `### Title — declared ...` heading -- so one extractor must name both, or the check reads zero rows on the file it cannot parse and reports a pass it never measured: rows() { sed -n -e 's/^- `\\([a-z0-9_]*\\)`.*/\\1/p' -e 's/^### \\(.*\\) — .*/\\1/p' | sort; }; comm -23 <(git show <base-ref>:$merged_path | rows) <(git show HEAD:$merged_path | rows) MUST BE EMPTY. A count tells you a number moved; only the difference names WHICH rows went dark, and the name is the whole finding",
generated_artifact_merge_driver_dark_row_set_difference_step(),
"3. DO NOT CHECK FOR CONFLICT MARKERS AND CONCLUDE ANYTHING: zero markers is exactly what this driver GUARANTEES on a refusal -- it leaves clean marker-free bytes and marks the path unmerged -- so a marker count reports that the DRIVER worked, never that its SUBJECT is intact. Read the index stages if you want the truth: stage 2 carries your rows and none of the base's, stage 3 the base's and none of yours",
"4. finish the authority merge and push the branch; do not regenerate this projection locally",
"5. heal-generated-artifacts derives it from the merged authorities, pushes the healed head, and dispatches revalidation; the generated-artifact gate must then agree on that exact head",
Expand Down
Loading
Loading