Repository navigation
Conversation
The old file was a ~1,500-line per-layer record written while the codebase was being re-added layer by layer. That rebuild is done, so the file now describes the code as it stands: commands, the review rules, and the architecture that spans modules. Also drop the remaining rebuild wording from the engine docstring and two test comments. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
ASTRA 0.1 moves universes into astra.yaml, defines where a result and its provenance record go, and says when a record still describes the analysis. astra-tools now answers all of that through `astra.api`, so lc stops deriving it and becomes the runner only. - plan.py asks `astra.api.plan` and carries each planned result across as a picklable Task keyed by its address (`fit#baseline`, `fit` for an output built once, `stage.fit#u1` driven, `stage/fit#v1` owned by a declared analysis). Paths are measured from the project root. Results of an analysis declared with a `commit` are refused. - assets.classify asks `astra.api.check` instead of hashing recipes and inputs; lc adds only `behind` (the record names an earlier environment) and the git-history foreign-write test. - The worker writes ASTRA records under `.astra/records/`, naming the environment `urn:lightcone:env:<env_version>`, with an `astra.environments` entry point for `astra check`. A recipe runs in its own analysis's folder. The manifest keeps only what the closed record cannot hold. - A task downstream of a possible remake re-asks the checker once its upstreams have landed, so a byte-identical rebuild still stops the cascade. - Scaffold, .gitattributes (nested `results/` are annexed), the RO-Crate renderer, `lc run` input discovery, the `lc view` server routes and the docs follow. ASTRA 0.1 is not on PyPI yet: astra-tools and astra-spec are pinned to git commits. The `lc view` page still needs the 0.1 SDK, and the eval workflow is not migrated. Tests are re-expressed as 0.1 specs; test_composition.py runs the specification's own shapes (pins, imports, derived_from, when, driving) end to end. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Signed-off-by: Francois Lanusse <fr.eiffel@gmail.com>
… result The manifest held what ASTRA's closed provenance record cannot: the rendered recipe, the decisions, the git remote, the uv version, the sandbox's hermeticity attestation and the image. None of it is kept any more, so `.<name>.manifest.json`, `assets.Manifest` and the helpers that existed only to fill it (`project.uv_version`, `Runtime.manifest_image`, `Runtime.arch`) are gone, with the `.gitattributes` lines that kept manifests out of the annex. - A run commits two files per place, the bytes and the record; the foreign-write check looks at those two. - The RO-Crate takes the repository's remote as an argument, describes each run with the task's command and decisions as the spec now stands, and no longer has a ContainerImage entity. - The warning about an output the spec dropped is now raised from its orphaned record. - `/lightcone/api/run` no longer answers `recipe`. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Signed-off-by: Francois Lanusse <fr.eiffel@gmail.com>
The engine and the test suite re-expressed as 0.1 specs. What follows rewrites every place that talks to astra-tools against its rescoped API. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
ASTRA 0.1 names three tools: a validator, a checker and a runner. astra-tools is the first two; this makes lc the third, on the rescoped `astra.api` (astra-project/astra-tools#138), in place of the earlier port's workarounds. - One question per verb. `plan.build` calls `astra.api.check` once and gets the planned results and how each record stands together, kept as `Graph.found`. The earlier port asked `api.plan` and `api.check` separately. - A task asks ASTRA nothing but a pure rule. The driver hands each task what the checker found; once its upstreams have landed, the task applies `Status.unchanged_given` to the bytes they produced. No check and no git inside a worker, and a byte-identical rebuild still stops the cascade. - One classification rule with one varying input: `classify(found, environment, read, foreign)`. A task gives what its upstreams made; the driver gives what their records say, or None while one may still be remade. - lc fills its own commands with `api.fill`, relative to the folder the recipe runs in. ASTRA owns the grammar, lc the paths. - No environment plug-in. lc minted the IRI, so `lc status --json` gives each result's recorded environment beside the project's. - The crate takes its records from the checker and the label and description from the resolved analysis; the probe binds offline; the scaffold is astra's public one again. - lc imports astra through `astra.api`, `astra.scaffold` and `astra.papers.cache` only. AGENTS.md records the split, the changed invariants and what was decided against. astra-tools is pinned by git to the head of #138 until it is released. The viewer's browser test fails: its page reads the spec with the released SDK, which does not read 0.1 yet. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This was referenced Nov 14, 2026
astra-tools now answers in one plain data model: api.check returns the resolved analysis, with every path from the project root and each command as it runs, and one status per result. The engine no longer converts paths between frames or fills a command. A task is ASTRA's own Result with what a run needs looked up once, and its key is ASTRA's id for the result, so a result that belongs to another analysis is stage:fit#v1. Whether a result that only reads a rebuilt one must be rebuilt too is lc's rule now, in classify: the bytes each result it reads has, against the bytes its record says were read. Records are written by api.write_records, one at each place, and lc hashes its own files. Each rule of the specification's runner layer is kept in one place, with a test named after it in tests/test_runner_rules.py. Two checks are new. A run is refused while a file the environment's identity reads is not tracked by git, as an ignored file leaves a tree clean (UNRECREATABLE_ENVIRONMENT). And a result that arrives after the checkout was edited or committed to is restored and reported failed, where the run used to commit it and warn that its record named a commit that no longer described the code (UNCOMMITTED_CHANGES). Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
ASTRA 0.1 changes what a spec is and who answers what. Universes live in
astra.yaml, and the specification fixes where a result and its provenance record go and what makes a result stale. It names three tools: a validator, a checker and a runner, and gives the runner a layer of rules of its own.This PR makes
lcthe runner and nothing else, on the astra-tools API of astra-project/astra-tools#138, whose data model is proposed in astra-project/astra-spec#117 (RFC 0009). It supersedes #268.The split
astra.api.check, per verbapi.checkreturns the resolved analysis and one status per result, as plain data. lc imports astra throughastra.apionly, plusastra.scaffold(the empty spec) andastra.papers.cache(the viewer).What the engine no longer does
ASTRA's model gives every path from the project root and each command already rendered, so the code that converted paths between frames and filled placeholders is gone.
plan.buildis lookups. ATaskis ASTRA's ownResultplus what a run needs resolved once from the model's references: the folder the recipe runs in, the file each entry reads, the options it is made with, what its recipe asks for.fit#baseline,stage.fit#u1, andstage:fit#v1for a result that belongs to another analysis (it wasstage/fit#v1).api.write_records, one at each place of a result, from the facts of the run. lc hashes its own files (assets.digest_file).The one rule lc adds to the checker's
The checker says what a result breaks in itself (
Status.why). Whether a result that only reads a rebuilt one must be rebuilt too is lc's rule, inassets.classify: compare the bytes each result it reads has now with the bytes its record says were read. A task passes what its upstreams actually produced; the driver passes what their records say, orNonewhile one may still be remade. A byte-identical rebuild still stops a cascade, with no second check and nothing asked of ASTRA from a worker.The specification's runner rules
Each rule of the runner layer is kept in one place, and
tests/test_runner_rules.pyhas a test named after each, on a real project. The suite reads the rules from the installed astra-spec, so a rule a later release adds fails there until it is answered.AGENTS.mdhas the table.UNRECORDED_RESULT,FALSE_RECORD,WRONG_WORKING_DIRECTORYworker.executeUNRECREATABLE_ENVIRONMENTUNCOMMITTED_CHANGESREBUILT_FROM_COMMITcommitis no task.NOT_AT_COMMIT,STALE_INPUTUNDECLARED_READCODE_OUTSIDE_ANALYSIS--check.A behavior change to decide on
An edit or a commit while a run is in flight now fails the results that arrive after it. Before, the run finished, committed them, and warned that "the records name the starting commit, which no longer describes this code". That warning described a record that is false, and the specification makes both rules a
MUST. Now such a result is restored and reportedfailed, with what was edited; results committed before the edit stand, and the edit itself is left untouched.The cost is real: touching a README during a long run discards the results that finish afterwards. If that is too strict in practice, the check is one call in
materialize._consumeand can go back to a warning.Dependencies
astra-toolsis pinned by git to the head of astra-project/astra-tools#138 until that is released.astra-spec>=0.1.0rc1is a direct dependency only so that a resolver accepts the release candidate.Known gaps
lc view's page needs@astra-spec/sdkand@astra-spec/uifor 0.1; the browser test fails in CI until then..github/workflows/eval.ymlandevals/are still 0.0.14.commitis refused wherever a result would be built from it. ASTRA's model has no command for such a result (the RFC's open question).lc rungrants a probe no declared input while the spec is invalid, as only a valid analysis resolves. Files inside the project are readable anyway.Tests
Locally, with
LC_SANDBOX_TESTS_REQUIRED=1 LC_CRATE_TESTS_REQUIRED=1: 1261 passed, 1 failed.ruff checkandmypy src/are clean.The failure is
tests/test_view_browser.py::test_open_dialog_follows_artifacts_and_late_provenance, the first known gap above: the page refuses a 0.1 analysis. It is left failing rather than marked expected, so the PR cannot merge with a viewer that does not work.New or re-expressed tests pin:
tests/test_runner_rules.py, 16 tests), including a result with two names being made once and recorded at each place, and the two mutation-checked boundary tests;classifyon the level of each diagnostic inwhy, withread=None, with the recorded digest and with another;check,resolveandvalidateall raise inside it), and a run askingapi.checkonce however far a remake cascades;🤖 Generated with Claude Code