Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
| Comment: | A watcher that decides its run waits hands that run on itself once it has let go of its locks, so a run from a user holding R alone that the run it waited for read in the node's care, its watcher still holding it, is not left waiting
Intent: an adversarial review of 3869da228e, which has a node take one run from a user holding R alone at a time, found a run left waiting, unstarted, with no watcher to hand it on, shown by a spec. Two such runs, X and Y, of different process.user, are handed to watchers together; X's watcher takes the node's lock of such runs and X runs; Y's watcher decides Y waits, then, still holding Y's run lock, takes the node's lock again to write its answer, which Crystal's blocking flock takes by trying again every tenth of a second with no queue, so X's watcher, X ending meanwhile, can take it first. X's following then read Y in the node's care and handed on nothing, and Y's own following left Y out, so Y waited until the node's deliberate check, since a round decides only the runs that arrived (HISTORY.md decision 39). Expression: src/ocx/watcher.cr: Watched gains waited, false unless the watcher decided its run waits; decided returns waited: decision.act.wait? when the run is not started, and says a run that waits is written no answer; watched passes watched.waited to following; following takes the watcher's own run among those it may hand on when waited, `(waited || run.said.artifact_hash != hash)`, so of X's and Y's followings, each run under the node's lock once its own watcher has let go of its locks, the second reads both free and hands Y on when Y is to start; should both hand it on, Y's run lock takes one watcher, the other writing nothing. Its comments say so: following's, reflowed, that only Y's lock kept it in the node's care; watched's, that the locks are let go as the watcher's process dies, killed too. spec/support/held_watcher.cr, new: a seam that reopens OCX::Watcher and, through previous_def, holds the next watcher of the run held_run once decided has returned, before watched lets go of its locks, until told to go on, so the spec puts Y's watcher where the review found it, in one process, with nothing timed. spec/ocx/watcher_spec.cr: the setup of the example of runs from a user holding R alone moved, unchanged, into the helpers build and alone, which the new example shares. HISTORY.md decision 121, amending decision 108 and naming the review; GLOSSARY.md's Watcher: it hands on its own run when it found that run waits. Within precept C1 (File Boundedness): src/ocx/watcher.cr 400 lines, spec/ocx/watcher_spec.cr 399. Review: Gemma (gemma4:31b) read the change nine times (scratchpad gemma-alone-race-1.txt to -9.txt, requests and replies in gemma-reviews/alone-race-1 to -9), the first three given the full intent, the rest a shorter one asking for every interleaving of the two watchers' steps. The first three found nothing. Held: none. Misread, each a clarity finding, the code changed and asked again: the fourth's, that a killed watcher's lock stays held: watched's comment now says its locks are let go as its process dies, and the ninth reading said so itself. The sixth's, that the watcher a waiting run is handed to finds it still in the node's care, a waiting run being kept so: following's comment now says only the run's lock kept it in care, decided's that a run that waits is written no answer, and the new example now runs the watcher it is handed to, which ends it exited 0; the seventh and ninth still spoke in passing of a waiting run kept in care, which nothing keeps: a run that waits is written nothing, and its care is read from its run's lock alone (Node.care). The seventh's, that two watchers handed one run both start it: following's comment now says its run's lock takes one watcher, the other writing nothing, as the example of a second watcher leaving the first's lock as it is shows; not raised again. Wrong: the fourth's, fifth's, eighth's and ninth's, that a watcher killed after deciding its run waits, before its following, strands the run: the kernel lets go of a dead process's locks, so the following of the run it waited for, in each order given there after the death, reads the run free and hands it on; only a death after that following read it in care leaves it, which the node's deliberate check mends, as it does any watcher's death between its steps (decision 39; docs/protocol-v1-failures.md, case 3), with no sweep or timer (the causation precept), and an ensure, as the fourth proposed, does not run on KILL. The seventh's, as a defect: a run handed on twice is by design, as decision 108 had it. Demonstrates: spec/ocx/watcher_spec.cr, "hands on a run from a user holding R alone that waited by its own watcher when the run it waited for ended while that watcher held it": X, of builder, runs until the file go is in its workspace; Y's watcher, of coder, held by spec/support/held_watcher.cr once it decided Y waits, Y reads in the node's care; go is written and X's watcher returns, its next_runs empty, its following having read Y in care; Y's watcher goes on and returns next_runs [Y]; the watcher Y is handed to ends it exited 0. With following's test reverted to `run.said.artifact_hash != hash` the example fails, "Expected: [Y] got: []" (tried). "takes one run from a user holding R alone at a time..." passes as before through the helpers. src/ocx/watcher.cr holds the change; spec/guards/size_spec.cr holds src/ocx/watcher.cr at 400 lines and spec/ocx/watcher_spec.cr at 399; spec/guards/documents_spec.cr renders HISTORY.md and GLOSSARY.md with their links. crystal run ci.cr green: 507 examples, 0 failures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | agent-tools |
| Files: | files | file ages | folders |
| SHA3-256: |
488aecd89faa4031d64f6b14d39eec35 |
| User & Date: | opus-ocx2 2026-10-23 11:57:05.430 |
|
2026-10-23
| ||
| 12:36 |
A watcher turned away at its user's lock lets go of its run's lock in the same hold of the node's lock as its failed take, so the run of that user ending meanwhile hands that run on, and it is not left waiting with no watcher
Intent: an adversarial review of 488aecd89f, which has a watcher that decides its run waits hand that run on itself, found a run left waiting, unstarted, with no watcher to hand it on, shown by the reviewer's spec and by a stress run, in 3 rounds of 12. Two runs of one user, first and second, are handed to watchers together; the first's watcher holds the user's lock and runs it; the second's watcher takes its run's lock, then, under the node's lock, finds the user's lock held (Node.take) and is turned away, but held its run's lock until watch closed the file as it returned. If the first run ended in that gap, its following read the second in the node's care and handed on nothing, and the watcher turned away returns nil with no following of its own, so the second waited until the node's deliberate check (HISTORY.md decision 39). Expression: src/ocx/care.cr: Node.take gains letting_go : File? = nil, let go in the same hold of the node's lock as a take that fails, `locked(dir) { took?(file) || (letting_go.try(&.flock_unlock); false) }`; its comment says why: a take that fails comes while the run holding the user's lock still holds it, so before that run lets go of it and before its following reads, under the node's lock, which runs to hand on, and that reading finds the run turned away free. src/ocx/watcher.cr: watched calls Node.take(dir, user_lock, letting_go: run_lock), a comment at the call saying so; watched's comment, reflowed, says the run's lock is let go as the watcher is turned away; watch still answers nil for it. Nothing is timed. spec/support/held_watcher.cr: the seam also reopens Watcher.watched through previous_def and holds the next watcher of held_run when its answer is nil, turned away after its failed take, before watch closes the file of the run's lock; its hold once decided has returned is unchanged, and a watcher held there answers non-nil, so none is held twice. spec/ocx/turned_away_spec.cr, new, its private helpers named apart from every other spec file's; spec/ocx/watcher_spec.cr's header names it; docs/survey/functionality.json lists it under the node's behavior. HISTORY.md decision 122, naming the review and decision 121; GLOSSARY.md's Watcher: one turned away lets go of its run as it finds its user's other run in the node's care. Within precept C1 (File Boundedness): src/ocx/watcher.cr 400 lines, spec/ocx/watcher_spec.cr 400. Review: Gemma (gemma4:31b) read the change four times (scratchpad gemma-turned-away-1.txt to -4.txt, requests and replies in gemma-reviews/turned-away to turned-away-4), the first given the full intent, the rest asked for every interleaving of the two watchers' steps and of a round or the node's check. The first found nothing. Held: none. Misread, each a clarity finding, the code changed and asked again: the second and third listed a take of the user's lock failing after the run holding it had let go of it, a take that then succeeds, and said the seam holds the watcher before its take. Take's comment now says a take that fails comes while the holder still holds the lock, so before it lets go and before its following; a comment at the call in watched says the same; the seam names what previous_def answers `answer` and says nil is a watcher turned away after its failed take; and the question's step for the take no longer presumed it fails. The fourth read both right, a take after the holder let go succeeding and the watcher running its run itself, the seam holding after the failed take, and found no defect. Wrong: none. Demonstrates: spec/ocx/turned_away_spec.cr, "is handed on by the watcher of its user's run in the node's care, that run ending before the watcher turned away returns (case 26)": two builds of builder's that stone sent, both decided to start by one round; the first's watcher runs it until the file go is in its workspace; the second's watcher, turned away at builder's lock, is held by spec/support/held_watcher.cr before watch closes the file of its run's lock; go is written and the first's watcher returns next_runs [second]; the held watcher returns nil; the watcher the second is handed to ends it exited 0. With the call in src/ocx/watcher.cr reverted to Node.take(dir, user_lock) the example fails at the first's next_runs, "got: []" (tried). spec/ocx/watcher_spec.cr's example holding a watcher once decided, and spec/ocx/care_spec.cr's take of a run's lock, given no letting_go, pass as before. src/ocx/care.cr and src/ocx/watcher.cr hold the change; spec/guards/size_spec.cr holds src/ocx/watcher.cr and spec/ocx/watcher_spec.cr at 400 lines; spec/guards/survey_spec.cr finds the new spec in docs/survey/functionality.json; spec/guards/documents_spec.cr renders HISTORY.md and GLOSSARY.md with their links. crystal run ci.cr green: 508 examples, 0 failures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: f9b1e9ba26 user: opus-ocx2 tags: agent-tools | |
| 11:57 |
A watcher that decides its run waits hands that run on itself once it has let go of its locks, so a run from a user holding R alone that the run it waited for read in the node's care, its watcher still holding it, is not left waiting
Intent: an adversarial review of 3869da228e, which has a node take one run from a user holding R alone at a time, found a run left waiting, unstarted, with no watcher to hand it on, shown by a spec. Two such runs, X and Y, of different process.user, are handed to watchers together; X's watcher takes the node's lock of such runs and X runs; Y's watcher decides Y waits, then, still holding Y's run lock, takes the node's lock again to write its answer, which Crystal's blocking flock takes by trying again every tenth of a second with no queue, so X's watcher, X ending meanwhile, can take it first. X's following then read Y in the node's care and handed on nothing, and Y's own following left Y out, so Y waited until the node's deliberate check, since a round decides only the runs that arrived (HISTORY.md decision 39). Expression: src/ocx/watcher.cr: Watched gains waited, false unless the watcher decided its run waits; decided returns waited: decision.act.wait? when the run is not started, and says a run that waits is written no answer; watched passes watched.waited to following; following takes the watcher's own run among those it may hand on when waited, `(waited || run.said.artifact_hash != hash)`, so of X's and Y's followings, each run under the node's lock once its own watcher has let go of its locks, the second reads both free and hands Y on when Y is to start; should both hand it on, Y's run lock takes one watcher, the other writing nothing. Its comments say so: following's, reflowed, that only Y's lock kept it in the node's care; watched's, that the locks are let go as the watcher's process dies, killed too. spec/support/held_watcher.cr, new: a seam that reopens OCX::Watcher and, through previous_def, holds the next watcher of the run held_run once decided has returned, before watched lets go of its locks, until told to go on, so the spec puts Y's watcher where the review found it, in one process, with nothing timed. spec/ocx/watcher_spec.cr: the setup of the example of runs from a user holding R alone moved, unchanged, into the helpers build and alone, which the new example shares. HISTORY.md decision 121, amending decision 108 and naming the review; GLOSSARY.md's Watcher: it hands on its own run when it found that run waits. Within precept C1 (File Boundedness): src/ocx/watcher.cr 400 lines, spec/ocx/watcher_spec.cr 399. Review: Gemma (gemma4:31b) read the change nine times (scratchpad gemma-alone-race-1.txt to -9.txt, requests and replies in gemma-reviews/alone-race-1 to -9), the first three given the full intent, the rest a shorter one asking for every interleaving of the two watchers' steps. The first three found nothing. Held: none. Misread, each a clarity finding, the code changed and asked again: the fourth's, that a killed watcher's lock stays held: watched's comment now says its locks are let go as its process dies, and the ninth reading said so itself. The sixth's, that the watcher a waiting run is handed to finds it still in the node's care, a waiting run being kept so: following's comment now says only the run's lock kept it in care, decided's that a run that waits is written no answer, and the new example now runs the watcher it is handed to, which ends it exited 0; the seventh and ninth still spoke in passing of a waiting run kept in care, which nothing keeps: a run that waits is written nothing, and its care is read from its run's lock alone (Node.care). The seventh's, that two watchers handed one run both start it: following's comment now says its run's lock takes one watcher, the other writing nothing, as the example of a second watcher leaving the first's lock as it is shows; not raised again. Wrong: the fourth's, fifth's, eighth's and ninth's, that a watcher killed after deciding its run waits, before its following, strands the run: the kernel lets go of a dead process's locks, so the following of the run it waited for, in each order given there after the death, reads the run free and hands it on; only a death after that following read it in care leaves it, which the node's deliberate check mends, as it does any watcher's death between its steps (decision 39; docs/protocol-v1-failures.md, case 3), with no sweep or timer (the causation precept), and an ensure, as the fourth proposed, does not run on KILL. The seventh's, as a defect: a run handed on twice is by design, as decision 108 had it. Demonstrates: spec/ocx/watcher_spec.cr, "hands on a run from a user holding R alone that waited by its own watcher when the run it waited for ended while that watcher held it": X, of builder, runs until the file go is in its workspace; Y's watcher, of coder, held by spec/support/held_watcher.cr once it decided Y waits, Y reads in the node's care; go is written and X's watcher returns, its next_runs empty, its following having read Y in care; Y's watcher goes on and returns next_runs [Y]; the watcher Y is handed to ends it exited 0. With following's test reverted to `run.said.artifact_hash != hash` the example fails, "Expected: [Y] got: []" (tried). "takes one run from a user holding R alone at a time..." passes as before through the helpers. src/ocx/watcher.cr holds the change; spec/guards/size_spec.cr holds src/ocx/watcher.cr at 400 lines and spec/ocx/watcher_spec.cr at 399; spec/guards/documents_spec.cr renders HISTORY.md and GLOSSARY.md with their links. crystal run ci.cr green: 507 examples, 0 failures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: 488aecd89f user: opus-ocx2 tags: agent-tools | |
| 10:55 |
An import pipes git's stream straight into Fossil, never a file, each step's largest file within a third of the space free; from the web page it goes on detached, answering at once, a TERM stopping it as a failure, its outcome logged where status shows it with the imports running and those that ended unreleased; two imports of one name never meet, and taking a directory never waits on a fossil command
Intent: the maintainer, 2026-10-21: "My `import` of https://github.com/beagleboard/beagleboard-org keeps failing. The post times out, so I don't know what happened." The tool's purpose, slice 39's: "comfort that i can import projects and reliably serve development back to git with ocx2". Reproduced on this host, the same code at the command line: the upstream, 3.0 GB packed with 527,641 commits, stopped after 10 minutes at import_branches, "git in the import's sandbox stopped by its files limit (SIGXFSZ)": the whole fast-export stream was written to a file, past the 8G files limit; and the page ran the whole import inside its request, so the browser gave up and the person never learned the outcome. An adversarial review of the change as first built (uncommitted on 22d4decadd) found seven defects, each fixed here: 1. a detached import that TERM or KILL ended logged no outcome, and status then showed nothing of it; 2. the 64 GB limit on each file alone could not stop a runaway before the disk filled; 3. the web page waited with no limit on the new repository's turn, which fossil git export held for two minutes in the proof; 4. a failed import left NAME.fossil-ocx.lock beside the served repository; 5. a detached import refused at check_import or read_served_setup left its directory, its job.json with any token in the upstream's URL; 6. Fossil's import took its turn from a checkout above its directory, failing at a .fslckout that did not read; 7. HISTORY.md and docs/interfaces.md gave the detached import's argument as its job, not its directory. Expression: src/ocx/commands/import.cr: ImportBranches runs git's fast-export and `fossil import --git --no-vacuum` side by side, each in a sandbox of its own, through an unnamed pipe, each end handed to its task, which closes it in this process as the task starts (src/ocx/launch.cr, src/ocx/tasks.cr), so either task's end ends the other's; fossil's failure is kept as a value, so git's is always received, and the import says both, git's first, leaving out git's SIGPIPE when fossil failed (Git::Failed keeps the signal, src/ocx/git.cr). Each task's limits (ImportCommand.limits): 48 hours of wall clock and as much CPU time, and a largest file of FILES, 24 GB, about twice the 10.6 GB repository the proof made, or a third of the space free where it works as it starts, when that is less, read by statvfs (Tasks.free, src/ocx/tasks.cr), so the new repository and its journal, or the clone, leave a third free (finding 2). TakeWork takes the directory first and answers whether it took it now; ImportCommand.run releases it only then, an import the web page started releasing it itself once its outcome is logged. From the web page (StartImport) the release's program starts detached, by setsid (src/ocx/session.cr, answering the process), as `ocx2 --import-detached WORK` (src/ocx/entry.cr), WORK's job.json, 0600, holding the served repository, the user and the input. src/ocx/imports.cr, new: Imported, with unmade! and discard (moved from ImportCommand.discard); the directory `.NAME.import` named `PID @TICKS`; Imports.take, Imports.release and Imports.standing hold the imports' lock, an flock on the served repository's directory itself (Imports.holding), exclusive to take or release, shared to read, never a fossil command, so no taking waits on one and no lock file is left (findings 3 and 4); release removes the directory only while it names the calling process; running reads a process as importing only while /proc shows it at that number, with that start, not ended; standing gives the imports running, `left`, each directory whose process ended without releasing it, as KILL leaves one (finding 1), and the log's last outcome. src/ocx/imports_detached.cr, new, split from imports.cr to keep both within 400 lines: the Job, Outcome and Detached elements, StartImport, Imports.start, and Imports.detached, which traps TERM for an Ending: Ending#ask stops the import's log (Log#stop, src/ocx/log.cr: each operation after is refused, "OP was not begun: SIGTERM asked the import to end") and sends TERM to each child not yet waited for (Sandbox.signal_children, src/ocx/sandbox.cr), so the step running fails, its sandbox with it, under GNU timeout too, and the import stops as at any failure, discarding what it made (finding 1); a failure no operation refused, as a File::Error opening a repository's lock, which Entry.identified, before the answer, does not take for a refusal, is logged as the outcome too, its backtrace on standard error; then, however it stopped, refused at its first checks too, it releases its directory and job (finding 5). src/ocx/command.cr: a tool's answer takes the log its caller holds. src/ocx/fossil/sync.cr: import_git names the new repository by `on:`, as clone does, so its turn is that file's, never a checkout's (finding 6); src/ocx/fossil.cr: a sandboxed fossil reads a pipe's end, and its failure says how it ended. src/ocx/commands/status.cr: ReadImports, for whoever may import, in a release root. src/ocx/fossil/direct.cr: the export's state seeded in one transaction that waits on a reader (33 minutes for 399,783 check-ins before, 9 s for 527,641 now). src/ocx/hook.cr: Hook.last reads the last line of a log of its form; src/ocx/care.cr: Node.stat_of public. HISTORY.md decision 120, the next free number; USAGE.md's import section and row; docs/interfaces.md's import row (finding 7); docs/slices-git.md; docs/linux.md; docs/backlog.md, two items: an old check-in of so long a history reads in minutes, and an upstream's URL shows on git clone's command line while the clone runs; docs/fossil.md, over 400 lines with this change's points, its "Git export and import" moved whole to the new docs/fossil-git.md, named in knowledge-map.json; docs/survey/functionality.json; docs/design/modules.json and the modules.md and knowledge-map.md generated. The specs' git helpers moved unchanged to spec/support/upstreams.cr, and the detached examples to spec/ocx/imports_detached_spec.cr. Every file within precept C1: src/ocx/commands/import.cr 391 lines, src/ocx/hook.cr 400, USAGE.md 400. Review: Gemma (gemma4:31b) read the change ten times (scratchpad gemma-import-large-land-1.txt to -10.txt, requests and replies in gemma-reviews/import-large-1 and import-large-land-2 to -10). Held: the third reading's, that "left" was said of imports KILL ended, or that logged no outcome, while it is any directory whose process ended without releasing it, its outcome logged or not: status's help, USAGE.md, HISTORY.md and the module docs now say so. The fourth's, that an exception no operation turned into a refusal escaped Imports.detached unlogged: as a File::Error opening the served repository's lock, raised in Entry.identified before the answer, whose capabilities rescue Fossil::Failed alone; it is now logged as the outcome, and a spec holds it. Misread, each a clarity finding, the code changed and asked again: the first's, that a failed start left the directory (take's comment now says a failing block leaves none, and only the named process releases it); that ImportBranches left git's result unreceived when fossil failed (the call now says fossil's failure is a value, git's always received); that release missed a zombie (its comment now says the importing process releases its own directory); that USAGE.md put the outcome in NAME.log (reworded). The third's and fourth's, that the started process writes `importer`, so a taking or status could look between: the line naming it now says this taking writes it before letting go of the lock that every taking and standing hold; not raised again. The fifth's, that a process dead at once, or one that took its number, reads as running: running's checks are now three lines, each named; not raised again. The sixth's, that `answer` is undefined after the rescue: Crystal makes it nil, as the spec of the jammed lock runs, and it is now declared nil first; not raised again. The seventh's, that the backtrace goes nowhere: the doc now says standard error is the same output file. Wrong: the second's, a directory KILL left lingering until the next import of its name: by design, status lists it as left, and OCX keeps no sweep or timer (decision 39; causation precept); its job.json, 0600 in a 0700 directory, holds no more than the clone's and the export's git configuration already keep. The third's, that a raise skips the TERM reset (ensure runs), and that KILL bypasses discard (no code runs on KILL; status lists the directory). The fourth's, that git's signal might not compare (Ended.signal is the name, "PIPE", as Signal::PIPE.to_s). The fifth's, a job.json corrupted by hand: the import then logs nothing and its directory stays, which status lists as left. The seventh's, that status should report a KILL'd import's outcome: `left` is that report. The eighth reading weighed several and concluded it found nothing. The ninth and tenth, after the specs' fixes below, the first's zombie again: that release, called by the importing process itself, may find it ended in /proc and leave its directory; a process calling release runs and has not ended, so running reads it whenever the directory names it, as a comment there now says, and the check is what keeps a late release from removing a directory taken since for another process, while take clears one whose process has ended; the tenth also had take refuse a left directory, which it clears. Demonstrates: spec/ocx/import_spec.cr, "imports a stream larger than its tasks' files limit, git's stream piped into Fossil and never written to a file": as before, now in a directory below one holding an empty .fslckout, the directory then holding its turn's made-ocx.lock; with import_git's `on:` taken out it fails ".fslckout could not be read: no such table: vvar" (tried); ImportCommand.limits gives 10 GiB of 30 GiB free and FILES of 300 GiB, and Tasks.free reads the space free and refuses a directory not there. "takes an import's directory for one process at a time, under the imports' lock alone, and anew once that one has ended, which status shows": a take while another holder keeps the new repository's turn, as a fossil command of the import does (the take as first built took that turn itself, so it waited as long as the holder held it: the review's run, 7.7 s for a holder of 8 s), release by a process not named leaving the directory, standing showing the running sleep, a process named with its start that has ended and is not yet waited for read as not running, then once it ended `left` [work], cleared by the next take, and no lock file left. "makes a served repository whose export keeps the upstream's commits..." and "leaves nothing of an import that fails..." pass as before, the latter through Imported#discard. spec/ocx/imports_detached_spec.cr, "starts an import from the web page detached, answering at once, refuses another of its name meanwhile, and logs its outcome, which status shows": as before, plus the stand-in program's directory shown as left once it ended unreleased; the failed import leaves no lost.db-ocx.lock and nothing left; a detached import refused at check_import, its repository made meanwhile, releases the directory taken for it; one whose served repository's lock is a directory, so that opening it raises a File::Error no operation refuses, logs "File::Error: ..." as its outcome, its backtrace on standard error, and releases its directory. "ends a detached import that TERM asks to end as at a failure: its outcome logged, its sandbox ended, its directory released": git's clone of an upstream that accepts and never answers, a TERM sent to this process once the upstream has its connection, which the import's trap hears: exit 1, the outcome "git in the import's sandbox ended by SIGTERM...", the directory gone; and one whose Ending was asked before its first operation logs "check_import was not begun: SIGTERM asked the import to end". spec/ocx/fossil_spec.cr: a sandboxed fossil's failure says it exited 1, and only a sandbox reads a pipe. spec/support/upstreams.cr: the helpers, moved. spec/guards/size_spec.cr, spec/guards/derivation_spec.cr, spec/guards/documents_spec.cr, spec/guards/delineation_spec.cr and spec/guards/survey_spec.cr hold the documents, docs/fossil-git.md among them. These hold src/ocx/imports.cr, src/ocx/imports_detached.cr, src/ocx/commands/import.cr, src/ocx/commands/status.cr, src/ocx/log.cr, src/ocx/command.cr, src/ocx/sandbox.cr, src/ocx/tasks.cr, src/ocx/launch.cr, src/ocx/session.cr, src/ocx/entry.cr, src/ocx/git.cr, src/ocx/fossil.cr, src/ocx/fossil/sync.cr, src/ocx/fossil/direct.cr, src/ocx/hook.cr and src/ocx/care.cr. The proof, on this host, of the change as first built, before these fixes: beagleboard-org posted as setup to a scratch served repository's web page, niced, answered in 48 ms; 14 h 13 min later the import log said ok and status showed it: 527,641 check-ins, main branch master, in the login group, a 10.6 GB repository, its export's refs the upstream's own commits, fossil git status up-to-date; the clone 7 minutes, git's fast-export 10 h 5 min and 11 minutes of CPU for a 50.6 GB stream, Fossil's import 14 h 4 min and 13 h 17 min of CPU. The fixes were not run on that upstream again. The gate's first run failed its coverage ratchet, src/ocx/imports.cr missing 1 statement and src/ocx/imports_detached.cr 3: running's check of an ended process, the TERM trap's block, and the rescue of a failure no operation refused, whose first spec, a served repository gone, reached a refusal instead, as Entry.identified rescues Fossil::Failed; the specs above now run each. crystal run ci.cr green: 506 examples, 0 failures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: 905756db67 user: opus-ocx2 tags: agent-tools | |