Documentation
¶
Overview ¶
Package bootstrap runs the bootstrap loop: the fixed-point pass that runs inside one batch job and turns any repository into an archive an earlier csf binary runs. It is the "ask C" slice of the laser_bootstrap program.
The loop owns the fixed point and the keep/refuse decision. Its stages are function values registered in data (CS-6): the NewLoop constructor builds a pipeline of Entry values, and a sibling slice plugs a stage in by appending one Entry — mine, induce, lean, shell and the jev batch land that way without the loop changing. Each iteration measures the repository, runs the stages, measures again, and keeps the change only when it grew the seed without a refusal; otherwise the tree is rolled back and the refusal logged. It repeats until the reading stops changing, the cap is reached, or every chief row holds, then emits the archive.
The loop has no network, no database and no subprocess: it reads and writes one directory tree, so it runs locally (no AWS) against a fixture repository, which is how its acceptance is proven.
Index ¶
- Constants
- Variables
- func Measure(ctx context.Context, repo string) (prod.Reading, error)
- func NoFix(_ context.Context, _ *Run) error
- func PayloadDigest(entries []DigestEntry) string
- func TarGz(ctx context.Context, request EmitRequest) (string, error)
- type DigestEntry
- type EmitRequest
- type Emitter
- type Entry
- type Fixer
- type Loop
- func (l *Loop) Run(ctx context.Context, repo string) (Result, error)
- func (l *Loop) WithArchive(archive string) *Loop
- func (l *Loop) WithCap(cap int) *Loop
- func (l *Loop) WithCreated(created string) *Loop
- func (l *Loop) WithEmitter(emitter Emitter) *Loop
- func (l *Loop) WithFixer(fixer Fixer) *Loop
- func (l *Loop) WithLogger(logger *slog.Logger) *Loop
- func (l *Loop) WithMeasurer(measurer Measurer) *Loop
- func (l *Loop) WithPipeline(pipeline []Entry) *Loop
- func (l *Loop) WithSourceRevision(revision string) *Loop
- type Manifest
- type Measurer
- type Result
- type Run
- type Stage
- type StageID
Constants ¶
const ( // FormatVersion is the manifest's version. A reader that does not know a // version refuses the archive rather than guess. FormatVersion = 1 // ManifestName is the manifest's member name. It is the archive's first // member, so a reader learns the format before it reads any repository // byte. ManifestName = "manifest.json" // EntrypointName is the executable a runner runs, relative to the // extracted archive root. It is a manifest field, so a later format may // move it without a reader change. EntrypointName = "bin/csf" )
The archive format is frozen at version 1. A later bootstrapper release may add members to an archive, but it never changes what a version 1 manifest field means, so a csf binary from any earlier release runs a newer archive. The brief calls this the boot sector: frozen forever.
const ArchiveName = "bootstrap.tar.gz"
ArchiveName is the archive the loop emits beside the repository.
const DefaultCap = 32
DefaultCap bounds the loop's iterations when none is set.
Variables ¶
var Platforms = []string{"linux_amd64"}
Platforms are the platforms a version 1 archive may run on, as <goos>_<goarch>. A reader refuses an archive it cannot run.
Functions ¶
func Measure ¶
Measure reads a repository into a prod.Reading by the marker convention the merge quality gate and this loop share: a top-level directory's count for a chief row is the marker file named after the row's id inside it, and the files are every regular file under the repository, by slash path. The per-directory checker that computes the counts from the tree is not landed, so a directory with no markers reads clean — the loop and the gate agree because they read the convention through this one function.
func NoFix ¶
NoFix is a Fixer that proposes no change. The mine and induce slices supply the repairing one; until they land, a loop built with NoFix measures a repository and emits its archive without altering the tree.
func PayloadDigest ¶
func PayloadDigest(entries []DigestEntry) string
PayloadDigest is the frozen framing of the payload digest: each entry contributes its name, its kind and its content length, then its content, in the slice's order. The emitter sorts members by name, so the digest is a function of the tree alone and a rewrite of the manifest cannot be forged against altered content.
func TarGz ¶
func TarGz(ctx context.Context, request EmitRequest) (string, error)
TarGz writes the repository at request.Repo as a deterministic tar.gz archive at the destination beside its parent directory, and returns that path. The archive's first member is the version 1 manifest; the rest is the repository's tree, one member per regular file and directory, sorted by name, with fixed ownership, timestamps and gzip header. So two runs over the same tree, revision and timestamp are byte-identical, and the manifest's sha256 refuses an archive altered after it was written. The archive is built in memory and written whole through pkg/atomicfile, so it never leaves a half-written archive.
Types ¶
type DigestEntry ¶
DigestEntry is one archive member as the payload digest sees it: its slash name, whether it is a directory, and its content (a directory's is empty). The emitter and the runner both build these, so the digest each computes is one function of the same bytes.
type EmitRequest ¶
EmitRequest is the emitter's input: the repository to archive, the destination beside its parent directory (the loop's archive name), and the two manifest facts the tree does not carry — the source revision and the created timestamp. Same tree and same two facts is the same bytes.
type Emitter ¶
type Emitter func(ctx context.Context, request EmitRequest) (string, error)
Emitter writes a repository into a deterministic archive and returns its path.
type Fixer ¶
Fixer applies one candidate change to the working tree. It returns an error only when it cannot apply the change at all; a change the gates later refuse is a nil error and a rollback, not an error.
type Loop ¶
type Loop struct {
// contains filtered or unexported fields
}
Loop runs the bootstrap stages to a fixed point.
func NewLoop ¶
NewLoop builds a loop from a measurer and a fixer, with its default pipeline, archive name and cap; the With* methods replace them.
func (*Loop) WithArchive ¶
WithArchive replaces the archive destination, relative to the repository's parent directory.
func (*Loop) WithCreated ¶
WithCreated sets the timestamp the emitted archive's manifest records, as RFC 3339, or empty for none. It is part of the archive's bytes, so a caller that wants a reproducible archive fixes it.
func (*Loop) WithEmitter ¶
WithEmitter replaces the archive emitter.
func (*Loop) WithLogger ¶
WithLogger replaces the refusal logger.
func (*Loop) WithMeasurer ¶
WithMeasurer replaces the measurer.
func (*Loop) WithPipeline ¶
WithPipeline replaces the loop's pipeline of stages.
func (*Loop) WithSourceRevision ¶
WithSourceRevision sets the revision the emitted archive's manifest records.
type Manifest ¶
type Manifest struct {
FormatVersion int `json:"format_version"`
SourceRevision string `json:"source_revision"`
Created string `json:"created"`
SHA256 string `json:"sha256"`
Entrypoint string `json:"entrypoint"`
Platform []string `json:"platform"`
}
Manifest is the frozen version 1 archive manifest. Every field is fixed by the format; a later version adds fields, never reinterprets these. SHA256 is the digest of the archive's payload — every member but the manifest — so a reader refuses a tampered archive before it extracts a byte.
type Measurer ¶
Measurer measures a repository into a prod.Reading. A real caller wires the checker commands; a fixture injects a scripted measurer.
type Result ¶
type Result struct {
Done bool
Iterations int
Archive string
Initial prod.Reading
Final prod.Reading
Kept []prod.Reading
Refusals []prod.Refusal
}
Result reports how the loop finished. Kept holds the readings of the kept changes in order — every consecutive pair grew the seed — and Refusals holds every refusal, so every_kept_change_raised_seed and refusals_logged are both read off one run.
type Run ¶
type Run struct {
Repo string
Before prod.Reading
After prod.Reading
Refusals []prod.Refusal
Kept bool
Iteration int
}
Run is one iteration's state, handed to every stage.
type Stage ¶
Stage is one function value of the pipeline, mutating the working tree or the run's state. The loop measures before and after the stages and owns the keep/refuse decision, so a stage never decides whether to keep.
type StageID ¶
type StageID string
StageID names one stage of the loop, spelled as the brief names it.
const ( // StageWork turns csfc refusals into work items. StageWork StageID = "csfc_refusals_to_work" // StageFix applies mechanical, jev-picked and coder-session fixes. StageFix StageID = "fix" // StageScore measures the score after the fixes. StageScore StageID = "build_test_score" // StageKeep decides keep_if(seed_grows, nothing_breaks). StageKeep StageID = "keep_if" )