从“造房子”到“定义拼接规则”


Proc-compose / Hearth:一次架构先行的 procedural composition 实验。用同一个组件协议组织地形、窗户、房间和聚落,让权限、验证与方块结构归属随生成自动记录。

2026-09-26 · gpt-6-astra / max · proc toolset · 单轮已完成并归档。报告正文为中文,保留原始英文代码及文档供核查。前次 proc-8 · 前次 proc-lodge · 下载原始库与测试

134交付测试,独立重跑通过
64 / 64冻结环境与建筑配对通过
18 / 24单体主结构签名
125,475默认聚落非空气方块

01 · 结论与证据边界

这次的实质进步是可执行的组合基础设施。高阶客户端描述房间图,内核负责实例身份、变换、写入权限、事务提交和结构查询;窗户、墙、房间、接触适配器与聚落共用 capability → negotiate → realize 协议。默认入口仅把聚落生成、验证和导出连起来,没有把库绑在命令行上。

已经交付

一个可导入的 Hearth 1.1.0 库;嵌套组件和独立扩展示例;冻结地形上的整栋候选适配;原始方块与 NBT 验证;玻璃到窗户/墙/房间/建筑的实际结构链;Litematica 与结构 JSON 成对保存、读回和一致性检查。

仍然受限

建筑以 9/11/13 格房间模数和有界山墙屋顶为主。聚落排列是对向街道、错落门面和 spine/loop 路径,尚不是任意城市布局。压力样本 9/32 通过,23 个输入被明确拒绝。没有证明全分布美观、万能屋顶连接或完整 Minecraft 物理模拟。

“验收通过”说明约定入口、样本复现与现有测试通过。它不能替代接口质量审查、美学判断,也不能把有限样本推广到所有随机参数组合。

本文区分三类证据:原始实验记录(模型提交的 corpus、测试与渲染),harness 独立执行(离线副本中的 5 个命令),以及报告复验(独立重跑测试和浏览器真实执行)。下方随机结构客户端、浏览器适配层、交互查看器由报告新增,不计为原实验的交付成果。

02 · Live proc-gen:运行 Python、调参、查结构

浏览器通过 Pyodide + Web Worker 执行原始 Python 库,不向模型发请求。先选一个客户端并点击载入,修改代码或变量,再生成。首次需要下载 Python、NumPy 和库文件;聚落比单体更慢,可随时停止。所有有效结果都会经过库的验证、MCIO 导出/读回和结构查询对比。

下载原始默认聚落

本次注入 Python 的变量(仅被代码使用的变量才生效)

“换 seed”保留当前代码和控件;“探索结构分布”会替换编辑器内容为可见的随机房间图客户端,改变房间数、翼部、楼层、模数和屋顶。它是有限的报告级采样策略,不声称均匀覆盖或穷尽整个库的表达空间,也不会隐藏失败后反复采样。

准备就绪。点击运行,开始真正的 Python 生成。

原始默认聚落预览

背景是原始实验渲染;运行后替换为当前 Python 结果。

剖切/隐藏只影响预览,不修改已验证的完整建筑或下载内容。单击可见方块查询,拖动则旋转。结构成员显示包含真实子结构与共享支撑。

选择一个方块,沿结构向上看

当前方块的真实结构记录
尚未生成
解析后的结构、策略和语义摘要
尚未生成
Python 输出与错误诊断
尚未运行

ZIP 保存 scene.litematic、scene.litematic.structure.json、可重放的 client.py 和生成元数据。结构记录不能丢:单独的 schematic 不包含这份语义关系图。库的源码哈希在运行前逐一校验;浏览器平台差异是否影响同 seed 的内容,见第 12 节实测。

03 · 任务、工具环境与 16 份参考

用户希望接口像积木:土地允许局部造池,树能通过草的授权替换完整植株,反向替换不成立;窗户依墙的接口装配;房间和聚落继续暴露同类接口。各层通过契约沟通,低层在不改变接口时改变样式,高层不需要翻阅其私有实现。

实验因此采用独立的 proc 工具集,没有预置 generate.py、Build 框架或渲染模板。提供 MCIO、状态等价 helper、渲染和切片教程。允许自由选择数据结构、场表达式、图、spline 等程序化生成方法;这不是必须逐个实现所有数据结构的清单。

输入是 exp8 的八份建筑与 lodge ref-1~8 的八份参考:仅用于美学结果,不要求复用实现、一比一复刻或穷尽八种固定环境。32 份输入文件(16 源码、16 原图)哈希已核对不变。原图不等于历史代码已验证复现的渲染。

mediterranean-villa 原始美学参考
exp8 / mediterranean-villa
merchant-manor 原始美学参考
exp8 / merchant-manor
red-roof-farmstead 原始美学参考
exp8 / red-roof-farmstead
root-house 原始美学参考
exp8 / root-house
sandstone-cottage 原始美学参考
exp8 / sandstone-cottage
stilt-water-cabin 原始美学参考
exp8 / stilt-water-cabin
stilted-manor 原始美学参考
exp8 / stilted-manor
stone-cottage 原始美学参考
exp8 / stone-cottage
ref-1 原始美学参考
lodge / ref-1
ref-2 原始美学参考
lodge / ref-2
ref-3 原始美学参考
lodge / ref-3
ref-4 原始美学参考
lodge / ref-4
ref-5 原始美学参考
lodge / ref-5
ref-6 原始美学参考
lodge / ref-6
ref-7 原始美学参考
lodge / ref-7
ref-8 原始美学参考
lodge / ref-8
完整实验 Prompt(原始发送内容)
# Task: Contract-Based Procedural Composition, Adaptation, and Structural Provenance Build an extensible Python generation and validation library for Minecraft Java 1.21.1. First build its executable architecture, then use its public interfaces to generate complete, attractive, logically sound content. A higher-level program must be able to discover what a lower-level component offers, decide whether and how to use it, and compose it without reading its private implementation. Components may vary their realization with seed and surroundings while fulfilling their negotiated contracts. A composition must itself be a reusable component. Deliver working generation from small objects through rooms and buildings to a coherent settlement of 3-6 buildings. The kernel must support further growth toward cities and other complex content without treating this demonstration scale as a fundamental architectural limit. Users write short, high-level programs and explicitly control the seed. Running `python generate.py` must produce the complete default settlement as one region in `output.litematic`. The requirements below fix semantics and observable behavior, not Python class names, signatures, storage encodings, or a particular solver. Choose those details deliberately and document them. Requirement identifiers are used for the evidence ledger requested under Deliverables. ## 1. Priorities and reference policy **R01 - Architecture first, with real implementations.** Establish clear module boundaries, public protocols, component lifecycles, transactions, provenance, and tests before expanding into extensive building geometry. Deliver an executable foundation, not empty interfaces or a framework proposal. Then complete the generated results. Do not optimize library line count, file count, or implementation length. Write as much well-factored shared code as the result requires. Keep clients lightweight without code-golf, opaque configuration dumps, or long hidden building-specific example helpers. **R02 - References are aesthetic outcomes only.** Two source snapshot sets and their original reference images are supplied under `references/exp8/`, `references/lodge/`, and task-root image files. `references/README.md` indexes all 16 examples and records their provenance and hashes. The supplied reference programs and images are aesthetic examples of building outcomes only. They are not architectural or implementation templates for your library. You are not required to study or reuse their code, follow their algorithms, reproduce them one-to-one, read every source file, or cover an enumerated list of building families. Design the framework independently. You may run or render a reference solely to inspect its resulting architecture. Keep the supplied snapshots unchanged. The images are original reference images, not a claim that each historical program reproduced them exactly or passed the new requirements. New styles are welcome. **R03 - Maximize meaningful, valid variety.** Broaden the space of possible component compositions and compatible parameter combinations. Prioritize component counts, connection topology, massing, footprints, wings, storeys, room functions and adjacency, roof systems, entrances, circulation, attachments, and site organization. Materials, planting, weathering, and decoration also contribute, but rank below structural variation. Randomness must affect a client's structure and composition, not only surface texture. The public API supports explicit decisions and bounded seeded choices. Do not introduce a whole-building family selector, reference-name dispatch, or a collection of fixed buildings disguised by a short API. New compositions must be expressible through existing public capabilities. Finite implementations of useful primitives and engineering strategies are appropriate when they can compose and be extended through contracts. Make parameter domains and dependencies explicit. Do not silently discard explicit intent. Arbitrarily unbounded dimensions, extra seeds, new names, file hashes, global rotations, or translations alone are not meaningful additional types. Retain believable scale, proportions, correctness, and aesthetics. Do not calculate, estimate, enumerate, or report the total number of possible combinations. Report observed finite-sample diversity only. ## 2. Kernel and recursive public contracts **R04 - Separate responsibilities.** Keep a general composition kernel, environment/geometry services, component and rule implementations, and high-level user programs distinct. The kernel must not import concrete building implementations. Components use public kernel protocols; ordinary clients use public composition APIs. Separate generation from CLI handling, rendering, filesystem export, and harness execution. Keep generation usable as an importable library and straightforward to adapt to a future browser runtime. A Houdini installation is not required. The kernel handles component instances, contract negotiation, spatial transforms, attachment, permissions, transactions, dependencies, random scopes, provenance, and validation orchestration. Environment/geometry services expose fields, spatial queries, geometry operations, block states, storage, and transport. Concrete components and rules contain architectural knowledge. High-level programs describe intent, select capabilities, arrange relationships, and package new components. **R05 - Executable component contracts.** A component must expose enough information for another component or planner to use it without inspecting private fields or switching on its implementation type. Its contract must describe, as applicable: | Concern | Required semantics | | --- | --- | | Inputs and assumptions | Accepted dimensions, orientations, support and environmental conditions, style constraints, variable parameters, and locked decisions | | Spatial claims | Actual occupied geometry, conservative possible extent, affected region, support regions, and space that must remain clear | | Connection interfaces | Points, surfaces, or regions with local frames, directions, dimensions, capacity, and alignment conditions | | Environmental access | Public fields, nearby geometry, and constraints the component can query | | Modification authority | What may be replaced or excavated, where, under which conditions, and with what limits | | Adaptation capabilities | Parts that may change and connection strategies that may fulfill the interface | | Guarantees and obligations | Connectivity, sealing, support, lighting, and requirements that an enclosing composition must satisfy | | Validation and diagnostics | Checks over actual results, with failing rule, component path, position, and conflicting conditions | An interface is not necessarily a single coordinate. A wall can expose an installation region with sill heights, framing exclusions, margins, and bay alignment. Terrain can expose an irregular plantable surface. Separate a component's feasible capability/domain description from the concrete or conservative instance contract negotiated for one realization. A larger canopy or wider footing requires renegotiation if it exceeds the accepted envelope; realization cannot silently exceed it. **R06 - Recursive composition and substitution.** Leaves and composites must implement the same usable protocol. A room may internally compose walls, windows, doors, furniture, and lights, while exposing purpose, entrances, envelope, and internal reachability. A building may expose footprint, height envelope, access ports, attachment opportunities, environmental assumptions, and guarantees. The framework retains internal composition and validation evidence for recursive inspection; parents work through public interfaces. Contract-compatible implementations must be substitutable without changing their parent program. Provide high-level operations sufficient to select, attach, arrange, repeat, scatter, constrain, and encapsulate components. A high-level program can generate different composition graphs, not merely resize an immutable graph. Shared rules can coordinate multiple children: a facade planner can establish bay alignment and sill levels while independent window implementations vary within those rules. A room planner allocates functions and circulation while furniture components realize them. Avoid absolute voxel loops, blockstate edits, NBT handling, and geometry repair in ordinary clients. Adding a component or validator must integrate through extension points, not core dispatch edits or duplicated validation code. ## 3. Spatial authority and atomic composition **R07 - Conditional replacement and preservation.** Check where an operation writes, who currently owns or shares the affected content, which permissions its binding grants, and whether other live components still satisfy their assumptions afterward. A universal numeric priority or last-write-wins rule is insufficient. Required examples: | Operation | Expected behavior | | --- | --- | | A pool replaces ground | Allowed within an authorized excavation region, producing a valid basin, boundary, and updated surface | | A tree is planted on ground | Uses a planting interface and depends on substrate support; an ordinary tree cannot excavate the terrain | | A tree replaces grass | Allowed when the grass exposes permission for that planting replacement | | Grass attempts to replace a tree | Reject that candidate; a scatter operation may try another legal location | | A pool excavates beneath an existing tree | Reject because it destroys an active support requirement, even if the soil itself is editable | | A window is installed in a wall | Permit the scoped replacement while preserving agreed support, sealing, margins, and alignment | | Decoration enters stair headroom | Reject because the clearance obligation remains protected | Permissions can refine or consume a host capability: terrain need not promise that every original soil cell survives an authorized pool excavation, but existing consumers of that soil must remain valid. Identical block states do not by themselves authorize shared occupancy. Shared supports, ownership, and write authority need explicit semantics. Replacement must maintain whole logical objects and their records; do not leave half a door, half a tall plant, dangling ports, or stale claims. **R08 - Functional boundaries and atomic transactions.** Components receive explicit inputs, read-only environmental access, and scoped randomness, and return plans or effect sets. Efficient mutable internals are acceptable, but components cannot bypass the kernel to mutate shared scene state. Every committed geometry write must have a kernel-bound component context. Negotiate a binding, generate a candidate, inspect its tentative resulting geometry and affected contracts, then commit all effects together. Failed attempts must leave geometry, ports, claims, ownership, dependencies, and other random branches unchanged. Initial implementations may recheck all relevant contracts rather than implementing a complex incremental validator. **R09 - Construction phases and obligations.** Distinguish invariants that must hold throughout composition from obligations that must be discharged when the current scope is finalized. A room can acquire walls before lights; a completed room must have lighting and an accessible exit. A building supplies internal reachability; a settlement connects its entrance to a public path. Unfinished scopes can continue local construction but cannot be returned or exported as completed valid components. Each room needs access and lighting; it does not need its own private staircase. Vertical circulation is required where the composed levels require it. ## 4. Automatic block-to-structure provenance **R10 - Record semantic structure in the kernel.** At instantiation, automatically assign stable component instance IDs and record type, resolved parameters, and random scope. At composition and attachment, automatically record semantic relationships. At geometry submission, automatically associate blocks with their current semantic component and generating operation. Component authors declare component types and interfaces normally; high-level clients must not supply per-block owner maps, handwritten ancestor chains, or a post-generation tagging pass. Semantic objects such as windows and walls must actually be generated as components. Querying a window's glass must recover relationships such as: ```text glass block -> window instance -> host wall -> house -> plot or settlement ``` This comes from real composition and binding, not source-code stack traces, material names, or post-hoc geometry classification. A window installed by a higher-level facade program must still identify its host wall through the attachment interface. Helper functions must not become fake semantic ancestors merely because they were called during generation. **R11 - Distinguish meaning, dependencies, and history.** Represent current structural membership and typed associations separately from data/constraint dependencies and generation/modification records. A window replacing wall infill owns its glass while remaining attached to the wall. A later property adjustment preserves that semantic membership even if another operation performs the write. Tree-over-grass replacement changes current ownership; displaced grass must not appear as a current owner. Preserve useful compact operation records for explanation and replay. Shared walls, bridges, and platforms joining multiple buildings can relate to multiple structures. Expose a useful primary structural chain plus typed related structures without forcing every relationship into a single-parent tree. Record containment, attachment, connection, and support according to their actual meaning. **R12 - Queryable, synchronized provenance.** Provide public APIs and a runnable headless example to inspect a block by coordinate and return its state, instance ID, structural chain, typed related structures, and generating information. Also query the actual current cells of a component, with optional descendants, for future highlighting. A bounding box alone is not an exact membership map. Document coordinate spaces and conversion through export offsets, translations, and supported rotations. This experiment requires the underlying query functionality, not a clickable viewer. Maintain coordinate and appropriate reverse indexes. Share the structure graph rather than storing a complete ancestor string on every voxel or scanning the whole scene on each query. Keep provenance transactionally consistent with replacement, deletion, rollback, and regeneration. Removing a block removes its current block ownership; clearance reservations remain separate. Recomputed branches must not leave stale cells, structure nodes, or associations. **R13 - Persist and verify structural identity.** Export sufficient companion data with the schematic to restore the same public queries, contracts, and validation context after reload. Include format version, coordinate transforms, and a semantic geometry identity/digest to check the pairing. A mismatched record must not be treated as trustworthy structure metadata. Equivalent blockstate property ordering must not create a mismatch. Handle unknown or missing structural data explicitly. Do not claim that arbitrary schematic geometry alone recovers the original semantic component graph. ## 5. General procedural environments **R14 - Compose environments from general operations.** Use Houdini-inspired data flow, attributes, fields, masks, scattering, connections, and encapsulated subnetworks in Python. Environments should come from composable parameterized operations such as field layering and transforms, mask blending, local shape operations, material distribution, water volumes, and constrained scattering. Operations can nest, repeat, and be packaged into new components. Use appropriate procedural-generation data structures throughout the library. You may combine splines/parametric curves and polylines, graphs and trees, polygons and meshes, point clouds with attributes, heightfields, scalar/vector fields, signed distance fields (SDFs), sparse voxel grids, and spatial indexes. For example, curves can guide paths, rivers, branches, or swept profiles; graphs can express circulation and structural relationships; fields can guide density and blending. These are optional tools, not a required checklist or a closed vocabulary. Choose representations that make each operation clear and extensible; intermediate design geometry need not be limited to boxes or Minecraft voxels. When converting representations into blocks, preserve component identity, coordinate transforms, and contract meaning, and validate the realized voxel geometry. Do not define a fixed list of environment classes or a `terrain_type` selector that dispatches to handwritten whole-scene cases. Flat terrain, gradients, shorelines, and other recognizable conditions must emerge as special cases of general parameters and compositions. For example, zero perturbation can yield flat ground, a field gradient can yield a slope, and an intersection of terrain with water can yield a shoreline. These are explanatory examples, not a required classification or a finite coverage checklist. One environment may contain many interacting conditions simultaneously. Adaptation must not inspect environment implementation types, source recipe names, reference names, or particular seeds to choose special-case behavior. Branching on measured geometry or contract facts is appropriate: support depth, water presence, available clearance, or local height difference can justify different engineering strategies. A finite set of useful primitive algorithms is fine; it must support new combinations and implementations through the public contracts. **R15 - Public environmental queries and control.** Expose relevant elevation, slope, materials, water levels, actual support, obstacle distance, occupancy, protected regions, access opportunities, and shared style information. Initial terrain generation may use heightfields, but the public environment interface must also support actual three-dimensional solid/support/clearance queries. A surface height alone does not prove that the material below can support a footing. Queries have explicit coordinate frames, valid domains, and input versions or dependency identities. Unknown space is not silently treated as flat terrain or empty air. Distinguish hard constraints (protected regions, locked placement, headroom, edit limits) from preference fields (planting density, buildability preference, access proximity, landscape preservation). Masks can control an operation's extent and strength; a high preference or mask value does not grant write authority. ## 6. Context-sensitive realization and connection adapters **R16 - Reusable adapters.** Treat connection adapters as ordinary components with contracts, provenance, and validators. Capabilities can include stepped foundations, retaining work, footings, posts to the actual bed beneath water, window reveals for varying wall thickness, entrance platforms and stairs, and sealed roof junctions. These are examples of reusable engineering, not an exhaustive adapter registry hardcoded into the kernel. New techniques must be addable through public interfaces. **R17 - Adapt at placement time.** For a workflow that generates terrain before placing a building: 1. Query the candidate location and neighborhood for support, elevation differences, water, obstacles, access, and protected regions. 2. Establish explicit user decisions and the remaining permitted variation. 3. Negotiate the binding and propose suitable contact geometry, adapters, and any permitted terrain edits. 4. Check the resulting combined scene, including affected existing components, in a tentative transaction. 5. Compare feasible candidates and atomically commit the chosen complete result. By default allow local excavation/fill, plinths, posts, retaining walls, and approach changes within explicit bounds. Preserve the terrain's major shape, the building's principal design, and locked requirements. Keep buildings sensibly aligned to gravity rather than tilting them wholesale with a slope. Explicitly bound and expose edit extent, excavation/fill volume, support height, and access detours. Do not make everything succeed by leveling the entire site, adding enormous solid pedestals, or extending arbitrarily tall posts. Regenerate contact geometry from the environment, rather than only translating a rigid finished building vertically. Adaptation should generalize across scales: a window can fit wall thickness within its contract, an approach can respond to height differences, and permitted branch/canopy variation can preserve nearby clearance. Shared facade grids, material roles, proportion rules, and layout constraints keep independently varying children coherent. **R18 - Quality-aware bounded planning.** First satisfy hard conditions: authority, support, reachability, sealing, spatial bounds, and explicit architectural intent. Then evaluate permissible alternatives for terrain disturbance, support proportions, boundary transitions, entrance/path quality, alignment, palette coherence, and landscape relationships. Use seeded selection among acceptable alternatives to retain diversity rather than always converging on one fixed form. Prefer constraint propagation and feasible-domain construction to blindly rejecting random complete builds. Bounded local search or backtracking is allowed; replan the smallest affected composition where practical. Distinguish proven/established incompatibility from search-budget exhaustion and validated success. Never claim a failed bounded search proves no solution exists. Do not silently drop required components, move locked placements, relax hard constraints, or recover to the same fixed building across most seeds. Optional omissions must respect declared minimum counts and be reported, not used to disguise failures. Return useful failed constraints and component locations. ## 7. Dependencies, deterministic regeneration, and bounds **R19 - Re-evaluate actual dependencies.** Composition structure defines encapsulation and responsibility. A separate data/constraint dependency graph identifies which changes require regeneration or revalidation. Terrain changes must invalidate affected foundations, approaches, and paths. Initial implementations may recompute whole affected nodes; sophisticated caching is not required. Recompute from inputs and recorded operations, replacing obsolete output rather than accumulating repeated cuts or fills. Keep current provenance and spatial indexes synchronized. Coupled building/terrain adjustments belong inside an explicit bounded solve that jointly produces the building and terrain edits. Do not create hidden, endlessly oscillating update loops. Record the environmental inputs on which a component's validity depends. An invalidated old result must not remain presented as a valid completed component. **R20 - Hierarchical deterministic randomness.** Derive stable child random scopes from the user's root seed and stable instance/operation keys. Separate planning, geometry, adaptation, and decoration. Users can override a subtree seed. Keys must not depend on traversal order or Python's process-random `hash()`. Sort unordered candidates with deterministic tie-breakers. Failed retries must not consume other branches' randomness. Scope attempted alternatives deterministically. With unchanged interfaces and no changed spatial/global constraint dependencies, adding a planter must not alter an unrelated building's layout. Changes that really affect dependencies can require replanning, and their cause must be inspectable. Independent operations can commute; dependent replacement and attachment operations obey their contracts. Do not falsely promise order independence for tree/grass replacement. Document the seed domain and retain inputs, resolved decisions, component structure, environmental versions, seeds, and implementation versions for replay. The same inputs and seed must reproduce semantic schematic content in the same environment: dimensions, coordinates, actual block states, entities, and block-entity data. Timestamps, compression, palette numbering and property ordering may differ; byte-identical files are not required. Use scoped streams for this task; all stochastic choices must still derive from explicit seeds, never ambient global randomness. **R21 - Resource and coordinate bounds.** Expose configurable limits for dimensions, recursion, search effort, and generation cost. Derive final export bounds from the realized composition, including terrain, roofs, adapters, vegetation, and external connections. Never silently clip. Library boundaries must not bake in the demonstration's building count or an environment category. ## 8. Architecture-first work sequence **R22 - Implement and verify in this order.** 1. Write `ARCHITECTURE.md` in your workspace before extensive scene geometry. Explain module dependencies, public protocols, lifecycle, contracts, effects/transactions, automatic provenance, environment queries, seeds, persistence, and extension mechanisms. Include short intended client compositions that make the proposed abstractions concrete. 2. Implement the working kernel. Pass tests for composition, binding, conditional replacement, rollback, automatic ownership, transforms, queries, and persistence before expanding the content. 3. Build a small end-to-end composition using terrain, grass, trees, walls, and windows. Exercise recursive composition, real attachment, provenance, and adaptation. Repair inadequate abstractions. 4. Build complete furnished buildings, roofs, circulation, lights, and connection adapters using the same public protocols. Demonstrate substitution and an independent extension. 5. Compose settlements, broaden high-level programs, run multi-seed validation, inspect renders, and fix generic defects exposed by the corpus. Proceed autonomously through these stages; do not stop for approval at each stage. Architecture can evolve when evidence calls for it, but rerun foundational tests after changing its semantics. Update the design rationale. Do not satisfy this sequence by writing placeholder interfaces and then routing all real work through a monolithic mutable compiler or a building-specific bypass. Large coherent implementation is acceptable; incomplete promises of future extensibility are not the deliverable. ## 9. Validation and finite evidence **R23 - Contract and extensibility tests.** Provide meaningful `test/test_*.py` tests for: - At least two visibly different implementations satisfying the same contract, substituted with no parent-program change; a composite remains usable at a higher level through the same protocol. - An independent extension package adding one low-level and one composite component without editing the kernel; ordinary clients need no geometry repairs or copied validators. - All conditional replacement examples above, including existing-consumer support preservation, whole-object consistency, rejected candidates, shared occupancy rules, and complete rollback. - Translation and horizontal rotations transforming states, interfaces, claims, and provenance together. - Determinism, stable independent branches, and failed attempts not perturbing sibling random streams. **R24 - Provenance tests.** Query window glass and recover its real window/wall/building relationships. Two windows using identical glass must have distinct instance identities. High-level examples must not contain per-voxel ownership tables or handwritten ancestry. Test replacement, deletion, property updates, rollback, shared walls/connections, exact current-cell queries, and branch regeneration. No obsolete node or voxel reference may survive as current structure. Test export/reload and coordinate changes, as well as detecting mismatched geometry and companion records. **R25 - General environmental adaptation tests.** Generate test environments with the same general operations, not a hand-authored list of terrain cases. Organize tests around independent environment and building seeds, parameter boundaries and degenerate values, rule interactions, previously unused operation compositions, local perturbations, and contract-compatible environment implementations. Derive special inputs such as flat ground from the general generator's parameters. Persist failures as generating expressions, parameters, and seeds; fix general rules, not seed-specific exceptions. Retain at least 64 reproducible environment/building pairings as a finite adaptation test budget. This count does not enumerate environment classes or define capability boundaries. Define the sampling recipe and supported parameter domains before evaluating results. Generate and freeze environmental inputs independently before placing buildings; do not secretly shape terrain to suit one house. Include untried combinations when assessing generalization, rather than only development examples. For explicitly satisfiable test specifications within documented domains, require valid results: contact geometry actually responds to surroundings, locked principal layout/functions remain intact, protected objects and terrain outside authorized modifications are unchanged, and there are no floating joins, buried doors, disconnected approaches, or invalid supports. Exercise multiple compatible adaptation strategies without reducing every case to a flat platform. Also run bounded stress sampling. Keep and report all successes, incompatibilities, retries, and budget-exhausted cases. Separate per-input success rate from per-candidate acceptance rate. Report edit costs and runtime, with denominators and sampling policy, rather than hiding hard inputs by resampling until only successes remain. A finite corpus is not a proof about every possible composition. **R26 - Whole-building and settlement corpus.** Supply at least three distinct lightweight building composition programs, each exercised at seeds 0-7. Exercise a settlement program at seeds 0-7 and test both 3-building and 6-building count boundaries. Programs use the same shared API and exhibit actual structural choices; they are not named reference dispatchers. Include new high-level compositions written after the abstractions exist, without changing the library for each new client. **R27 - Actual-geometry validators and negative tests.** Check generated and reloaded blocks, not only declared plans or claims. Validate Java 1.21.1 blockstates, bounds, support, multi-block consistency, doors/windows, room reachability, at least two blocks of player headroom on required routes including stairs, usable vertical connections, actual lights, appropriate furnishing, enclosed-space integrity, pool containment, exterior approaches, and settlement path connections. Late decoration must preserve earlier guarantees. Distinguish intended open spaces from enclosed spaces in the contracts. Deliberately remove supports, block stairs or exits, break paired door parts, remove room light sources, and exceed edit permissions. Validators must detect the resulting defects and identify the rule, component, and location. Support assumptions and the movement/lighting model must be explicit; a metadata declaration is not evidence of physical reachability or a placed light. Use the proc toolset's `blockstates_equivalent` semantics for round trips. Compare parsed block names and explicit property mappings, ignoring property order only. Changed names, values, missing properties, and extra properties still fail; do not infer defaults during equivalence checking. MCIO can reorder properties even after a single write. Repeated writes to a coordinate can be valid when the contract permits them and the final state is correct. Retain checks for relevant block-entity NBT and inventories. You may copy the independent comparison helper into your library or implement equivalent semantics; do not couple library validation to the CLI entry point. **R28 - Diversity and visual quality.** Measure observed differences in actual massing, component connections, room topology, roofs, and settlement organization, both within a client's seeds and between compositions. Exclude cosmetic noise, instance names, and global transforms from structural signatures. Report contact/foundation adaptation separately so it cannot substitute for diversity in principal architecture. Preserve harmonious material roles, useful proportions, complete hidden sides and interiors, meaningful furnished spaces, coherent roof joins, clear access, and composed landscapes. Keep all corpus results and failures. Render representative structural and adaptation variations from multiple exterior angles and with cutaways for circulation and furnishing. Inspect the images and fix visible problems. Do not present only favorable seeds while leaving known reproducible defects unreported. Rules and tests constrain quality; renders support aesthetic assessment. Neither formal contracts nor passing sampled tests constitute a proof of beauty or exhaustive validity. Keep tests bounded and rerunnable. Temporary test files belong in temporary directories under `test/` and must be cleaned up. Persistent samples, rendered previews, and corpus reports are explicit batch outputs, not unnoticed side effects of unit tests. ## 10. Harness contract and deliverables **R29 - Public generation, inspection, and export.** Work inside `/work/generator/workspace`. `python generate.py` is a thin public-API client and must generate, validate, and export the complete default 3-6 building settlement as one region in `output.litematic`. Support `python generate.py --seed INTEGER --output PATH` and document the default seed. Every example and batch command supports explicit seeds. Use the proc toolset and create your own entry point and library; no generator template is seeded. Preserve valid export and semantic reload checks while keeping substantial shared implementation in the library. The harness independently runs the default command, two seed-0 replays with different PYTHONHASHSEED values, seed 1, and your pytest suite in isolated offline workspace copies. Each command has a 1800-second limit. This checks the program interface and replay, not all R01-R30 requirements. The finished package must work without invoking reference programs, depending on the harness CLI, or downloading additional assets. Keep public generation and inspection callable without file export. Include an example that selects a coordinate from a generated artifact, prints the real structural chain and typed related structures, retrieves its component's cells, exports, reloads, and demonstrates the same query. A clickable viewer, node-editor UI, HTML report, or full city generator is outside this experiment; provide the foundation those later tools can use. **R30 - Complete artifacts and evidence ledger.** Deliver: - An importable shared library: kernel, environmental operations, components, adapters, validators, automatic structural provenance, public inspection, deterministic generation, and persistence. - `ARCHITECTURE.md`: the actual design, public protocol, dependencies, lifecycle, and rationale, updated as implementation evolves. - `GENERATOR.md`: quickstart, short client compositions, seed behavior, domains/dependencies, adaptation policy, resource limits, inspection and export/reload usage, extension instructions, diagnostics, batch/test/render commands, and known limitations. - `generate.py`, lightweight runnable examples, and an independent extension demonstration. - `output.litematic` with its verified structural/validation companion data. - `test/test_*.py`, representative samples with a replay manifest, labeled previews/cutaways, and rerunnable finite-corpus/assessment commands. - An evidence ledger in the documentation mapping **every R01-R30 requirement** to the responsible public API or module, tests/examples/render evidence, and any incomplete part. Use actual results; do not mark an unimplemented interface or an unrun test as complete. Preserve all requirements when refining the implementation. Document tradeoffs and limitations rather than silently shrinking the task. Spend effort on the reusable architecture and its verified generated results. State plainly in your final message what is complete and what remains unfinished. Environment details, available libraries, rendering tools, and repository conventions are in the workspace `AGENTS.md`.

参考路径与哈希 · 原始 prompt 文本 · 报告统计口径

04 · 运行时间、Token 与命令轨迹

99.4 min本轮生命周期,含验收与归档
102记录中的请求数
96结构化命令记录
10命令非零退出记录

时间为 attempt 的开始至结束(2026-09-26,UTC 18:48:16 → 20:27:38),不是纯模型计算时间。命令非零退出可能来自有意负例或开发排错,不能直接解释为最终任务失败。命令表保留全部 96 条记录,可排序/检索。

Token 字段计数解释
Input12,317,499包含缓存输入
Cached input11,879,424Input 的子集,不额外相加
Uncached input438,075Input − Cached input
Output178,964包含记录中的 reasoning output
Reasoning output82,445Output 的子集
Total12,496,463Input + Output;不据此估算费用
完整命令索引
#退出码记录用时命令 / 输出
100
pwd && rg --files -g 'AGENTS.md' -g 'README.md' -g '*.py' -g 'pyproject.toml' -g '!references/**' . /work /opt/tools 2>/dev/null | head -100
pwd && rg --files -g 'AGENTS.md' -g 'README.md' -g '*.py' -g 'pyproject.toml' -g '!references/**' . /work /opt/tools 2>/dev/null | head -100
/work/generator/workspace ./AGENTS.md /work/generator/workspace/AGENTS.md /opt/tools/README.md /opt/tools/blockstate_utils.py /opt/tools/cutaway.py
200
cat /work/AGENTS.md /opt/tools/README.md
cat /work/AGENTS.md /opt/tools/README.md
within your resource budget, or render appropriate sections. Exceeding it reports an error, not clipped geometry. Each render also writes a `.camera.json` file. The camera radius scales with the object's bounds. ## Multiple exterior views ```sh for view in 'front 210 20' 'rear 35 22' 'side 120 14' 'top 210 62'; do read -r name azimuth elevation <<< "$view" xvfb-run -a /work/generator/MCRender/node_modules/.bin/vite-node --script /opt/tools/render_schematic.mjs -- \ --input output.litematic --output "previews/${name}.png" \ --azimuth "$azimuth" --elevation "$elevation" done ``` Run this shell example in bash. Adjust views for the content; these directions do not define its facade. Inspect images and repair visible defects. Image brightness is not a Minecraft lighting simulation. ## Interior cutaways ```sh python /opt/tools/cutaway.py --input output.litematic --output floor.litematic --max-y 12 python /opt/tools/cutaway.py --input output.litematic --output section.litematic --axis x --max 20 xvfb-run -a /work/generator/MCRender/node_modules/.bin/vite-node --script /opt/tools/render_schematic.mjs -- \ --input section.litematic --output previews/section.png ``` The cutoff is inclusive; `--keep-above` selects the other side. Keep the source intact. Slices are geometry previews, may shift coordinates, and do not carry your provenance or full entity/NBT data. Query and validate the original artifact with its companion records, never the preview slice. ## Tests and extra packages Use `test/` or `tests/`, and run `python -m pytest -q test` (or `tests`). Include actual geometry checks, negative cases, seed replay, persistence and the task's requested evidence. Temporary test files belong in temporary directories under the test directory and must be cleaned up. Install extra packages with `uv pip install --target "$MCGEN_PYTHON_PACKAGES" package_name` during development. Record exact dependencies; generation and verification must work offline afterward.
300
cat AGENTS.md references/README.md
cat AGENTS.md references/README.md
workspace/generate.py` | `d1d8c312871a59f2f11afa94f5370f025b745e248f55726b45294783fc5c6533` | | `reference_lodge_ref-4.png` | `prompts/proc-lodge/task/reference_ref-4.png` | `prompts/ref-4/task/reference.png` | `f29b25707d7563197e3d5440e78f3d13cef38101be752b5174187812a3e067b0` | | `references/lodge/ref-5/generate.py` | `prompts/proc-lodge/task/references/ref-5/generate.py` | `runs/standard/ref-5/20260923T214601/work/generator/workspace/generate.py` | `161193d9b58feeac4d59b646d39d0606d5be53210bf88c9d6edfb2d34822048e` | | `reference_lodge_ref-5.png` | `prompts/proc-lodge/task/reference_ref-5.png` | `prompts/ref-5/task/reference.png` | `6a978df56439a5136b565687199a112d80cfc982a00df4b4f06f54250278d998` | | `references/lodge/ref-6/generate.py` | `prompts/proc-lodge/task/references/ref-6/generate.py` | `runs/standard/ref-6/20260923T214606/work/generator/workspace/generate.py` | `bace3e591f8dfdb61d09968d13e9176a30432da4715c2eae3f382651ebec1010` | | `reference_lodge_ref-6.png` | `prompts/proc-lodge/task/reference_ref-6.png` | `prompts/ref-6/task/reference.png` | `3a22f1581bc8b72fddd5594345b6573156ef7ccdf74936c31cdb86613ec4442d` | | `references/lodge/ref-7/generate.py` | `prompts/proc-lodge/task/references/ref-7/generate.py` | `runs/standard/ref-7/20260923T214612/work/generator/workspace/generate.py` | `71838ba26c2801f92fd01fab70847c20a7fef585fa56f3cbc921d34364e3bad4` | | `reference_lodge_ref-7.png` | `prompts/proc-lodge/task/reference_ref-7.png` | `prompts/ref-7/task/reference.png` | `4a6d6ab0ff861a8ffcd38d728a4e47c2af31bcdc15fa1676f7d5b4e12384aad5` | | `references/lodge/ref-8/generate.py` | `prompts/proc-lodge/task/references/ref-8/generate.py` | `runs/standard/ref-8/20260923T214616/work/generator/workspace/generate.py` | `2bd08d3038d4eedde2d9811a1e264fb8eff35d0f6f21b52b8e14772f3d59dcd3` | | `reference_lodge_ref-8.png` | `prompts/proc-lodge/task/reference_ref-8.png` | `prompts/ref-8/task/reference.png` | `ea93850446545fcdccc6400a4060fd462caaa6d15a448d77525c780e87edf52f` |
400
rg --files /work/generator/MCIO | head -60 && rg -n 'class LitematicCanvas|def to_litematica|class.*Region|TileEntities|block_entities|def save' /work
rg --files /work/generator/MCIO | head -60 && rg -n 'class LitematicCanvas|def to_litematica|class.*Region|TileEntities|block_entities|def save' /work/generator/MCIO/mcio | head -100
MCIO/mcio/__pycache__/__init__.cpython-311.pyc /work/generator/MCIO/mcio/__pycache__/__init__.cpython-313.pyc /work/generator/MCIO/mcio/__pycache__/lru_cache.cpython-311.pyc /work/generator/MCIO/mcio/__pycache__/unpack.cpython-311.pyc /work/generator/MCIO/mcio/__pycache__/constants.cpython-311.pyc /work/generator/MCIO/mcio/__pycache__/litematica.cpython-311.pyc /work/generator/MCIO/mcio/__pycache__/litematica.cpython-313.pyc /work/generator/MCIO/mcio/__pycache__/sketch.cpython-311.pyc /work/generator/MCIO/mcio/__pycache__/constants.cpython-312.pyc /work/generator/MCIO/mcio/__pycache__/sketch.cpython-312.pyc /work/generator/MCIO/mcio/__pycache__/constants.cpython-313.pyc /work/generator/MCIO/mcio/__pycache__/world.cpython-311.pyc /work/generator/MCIO/mcio/__pycache__/litematica.cpython-314.pyc /work/generator/MCIO/mcio/__pycache__/__init__.cpython-314.pyc /work/generator/MCIO/mcio/__pycache__/schematic.cpython-311.pyc /work/generator/MCIO/mcio/__pycache__/__init__.cpython-312.pyc /work/generator/MCIO/mcio/__pycache__/litematica.cpython-312.pyc /work/generator/MCIO/mcio/__pycache__/schematic.cpython-312.pyc /work/generator/MCIO/mcio/__pycache__/unpack.cpython-312.pyc /work/generator/MCIO/mcio/sketch.py:66:class LitematicCanvas: /work/generator/MCIO/mcio/sketch.py:106: def to_litematica( /work/generator/MCIO/mcio/sketch.py:153: def save( /work/generator/MCIO/mcio/schematic.py:39:class MultiRegionSchematicError(InvalidSchematicError): /work/generator/MCIO/mcio/nbt/nbt.py:288: def save(self, filename=None, *, gzipped=None, byteorder=None): /work/generator/MCIO/mcio/litematica.py:85: def save(self, path: pathlib.Path): /work/generator/MCIO/mcio/litematica.py:129: def to_litematica_schematic(self, minecraft_data_version: int, author: str, description: str) -> 'LitematicaSchematic': /work/generator/MCIO/mcio/litematica.py:834: tag["TileEntities"] = NBTList([]) /work/generator/MCIO/mcio/litematica.py:1319: def save(self, path: pathlib.Path) -> None:
500
python - <<'PY' import json,importlib.util p='/work/generator/MCRender/resources/1.21.1-blocks.json' d=json.load(open(p)); print(type(d)); print(str(d
python - <<'PY' import json,importlib.util p='/work/generator/MCRender/resources/1.21.1-blocks.json' d=json.load(open(p)); print(type(d)); print(str(d)[:2200]) for x in ['nbtlib','mcio','numpy','pytest']: print(x,importlib.util.find_spec(x)) PY
e_gate': [{'facing': ['north', 'south', 'west', 'east'], 'in_wall': ['true', 'false'], 'open': ['true', 'false'], 'powered': ['true', 'false']}, {'facing': 'north', 'in_wall': 'false', 'open': 'false', 'powered': 'false'}], 'acacia_hanging_sign': [{'attached': ['true', 'false'], 'rotation': ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15'], 'waterlogged': ['true', 'false']}, {'attached': 'false', 'rotation': '0', 'waterlogged': 'false'}], 'acacia_leaves': [{'distance': ['1', '2', '3', '4', '5', '6', '7'], 'persistent': ['true', 'false'], 'waterlogged': ['true', 'false']}, {'distance': '7', 'persistent': 'false', 'waterlogged': 'false'}], 'acacia_log': [{'axis': ['x', 'y', 'z']}, {'axis': 'y'}], 'acacia_planks': [{}, {}], 'acacia_pressure_plate': [{'powered': ['true', 'false']}, {'powered': 'false'}], 'acacia_sapling': [{'stage': ['0', '1']}, {'stage': '0'}], 'acacia_sign': [{'rotation': ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15'], 'waterlogged': ['true', 'false']}, {'rotation': '0', 'waterlogged': 'false'}], 'acacia_slab': [{'type': ['top', 'bottom', 'double'], 'waterlogged': ['true', 'false']}, {'type': 'bottom', 'waterlogged': 'false'}], 'acacia_stairs': [{'facing': ['north', 'south', 'west', 'east'], 'half': ['top', 'bottom'], 'shape': ['straight', 'inner_left', 'inner_right', 'outer_left', 'outer_right'], 'waterlogged': ['true', 'false']}, {'facing': 'north', nbtlib None mcio None numpy ModuleSpec(name='numpy', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7d9165372480>, origin='/opt/venv/lib/python3.12/site-packages/numpy/__init__.py', submodule_search_locations=['/opt/venv/lib/python3.12/site-packages/numpy']) pytest ModuleSpec(name='pytest', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7d91653723c0>, origin='/opt/venv/lib/python3.12/site-packages/pytest/__init__.py', submodule_search_locations=['/opt/venv/lib/python3.12/site-packages/pytest'])
600
mkdir -p hearth/kernel hearth/environment hearth/components hearth/adapters hearth/data examples extension_demo test samples previews reports && cat >
mkdir -p hearth/kernel hearth/environment hearth/components hearth/adapters hearth/data examples extension_demo test samples previews reports && cat > ARCHITECTURE.md <<'EOF' # Hearth: contract composition for block architecture Initial design recorded before implementation and scene geometry, 2026-09-26. Hearth separates an immutable-input component protocol, a transactional composition kernel, spatial/environment services, architectural components/adapters, and ordinary client programs. The kernel never imports building components. No reference generator is used. ## Dependencies and public protocol `hearth.space`, `hearth.blocks`, and `hearth.randomness` are value/geometry services. `hearth.kernel` owns capability discovery, instances, negotiations, bindings, effect application, transactions, structure/dependency graphs, queries and validation scheduling. `hearth.environment` supplies expression fields, terrain and read-only spatial observations. `hearth.components` and `hearth.adapters` implement the same protocol as independently packaged extensions. `hearth.programs` and `examples/` express compositions. `hearth.persistence` transports validated geometry and structural records, independently of the command line and renderer. A component provides a **capability** (parameter domains, offered interfaces, assumptions, adaptations and guarantees), **negotiate(context, parameters)** returning an instance contract, and **realize(context, contract)** returning a plan. A plan contains explicit geometry effects and child instantiations. Leaves and composites use this identical protocol. Child placement, attachment, repetition and encapsulation create real semantic instances, not call-stack ancestors. A registry selects by public capability tags. Validators register by rule identifier. Instance contracts carry a local possible envelope, affected/edit regions, installation ports, clearance/support rules, permissions, invariants, completion obligations and resolved decisions. Actual occupied cells are indexed from committed effects, separately from possible envelopes. A negotiation cannot exceed a capability domain or silently alter a locked parameter. Realization outside its accepted envelope fails. Ports carry local frames, regions, capacity, alignment and semantic intent. Host bindings grant narrowly typed modifications to particular regions/owners. ## Lifecycle, atomicity and authority A top-level placement forks a tentative scene. Negotiation reads its explicit environmental view and stable random scope. Geometry writes are applied with the executing instance as owner and an operation record. Children use the same tentative transaction. Existing support/clearance and logical-object invariants are checked before commit. Completion additionally checks lighting, room access, enclosure and enclosing-scope path obligations. Any failure discards the entire candidate, including nodes, relationships, reservations, dependencies and operation records. Unfinished scopes may be built locally but cannot be exported as valid complete content. Writes require empty space or ownership, a host's scoped grant, or explicitly declared shared occupancy. Identical material alone confers no rights. Replacement can retire a whole replaceable leaf but cannot leave half an object. Removing geometry updates reverse ownership. Structural membership, typed associations, input dependencies and operation history are separate records. Foreign property updates retain ownership. Grass can grant replacement to planting; terrain grants bounded edits but existing tree support remains invariant. Protected route clearance survives all later decoration. A preference field never grants authority. ## Environments, adaptation and bounds Composable constant, gradient, wave, radial, blend and transformed fields are frozen into a terrain component before siting. Views expose known domain, actual 3D occupancy/support, elevation, water, slope, protection and clearance; unknown positions raise diagnostics. Site adapters inspect these public measurements, choose among bounded contact/approach strategies and record costs and input regions. Buildings remain aligned with gravity. Local edits never authorize global leveling. Principal rooms, storeys and functions remain locked while contact geometry is recomputed. Configurable limits cover coordinate dimensions, block cost, recursion and search effort. Bounds are computed from all realized content; no fixed canvas clips roofs, plants or external paths. Dependencies identify which completed branches become stale after environmental changes. Explicit regeneration removes obsolete outputs and replays from recorded inputs. Coupled solutions are bounded transactions, with incompatible and budget-exhausted outcomes distinguished. ## Identity, randomness and persistence Coordinates are integer `(x,y,z)`, Y up, north -Z. Frames support translation and quarter-turns about Y, transforming block properties, interfaces, claims and queries together. World coordinates are preserved in companion data; export-local coordinates subtract the recorded minimum corner. Stable IDs derive from explicit parent/key paths. Seed scopes use a cryptographic digest of root seed and stable keys, never Python hash or traversal order. Planning, realization, adaptation and decoration have separate scopes. Optional subtree seeds reset a scope intentionally. Failed attempts use named alternatives and do not advance siblings. Seeds are signed arbitrary-precision integers. Each voxel stores current owner and operation identity once. Nodes store the shared structure graph. A reverse index provides exact current cells without whole-scene scans. Attachment hosts participate in the primary chain; shared/connected/support relations remain typed graph edges, not false parents. Queries return state, owner, structural chain, related nodes and operation history. Export uses one Java 1.21.1 Litematica region and a versioned JSON companion containing contracts, frames, nodes, edges, dependencies, rules, random scopes, reverse-index source records and replay inputs. A canonical semantic geometry digest ignores palette numbering and property order only. Reload checks the digest, then reruns validators on actual blocks; missing or mismatched metadata is explicitly untrusted. Geometry alone is never claimed to reconstruct semantic structure. ## Intended clients and extension points ```python scene = Scene(seed=17) site = scene.place('land', Terrain(field=Gradient(...) + Wave(...), ...)) house = encapsulate('dwelling', [Room(...), Room(...)], connections=[...]) scene.place('home', house, at=Frame(...), bindings=[site.offer('construction')]) scene.finalize() export(scene, Path('home.litematic')) ``` The implemented API may refine these illustrative signatures. A new component implements the protocol and registers public tags; a new validator registers a rule handler. Neither requires a kernel dispatch change. A new high-level client arranges capabilities rather than writing voxels. ## Verification sequence 1. Kernel and contracts, authority, rollback, frames, ownership and persistence tests. 2. Terrain/grass/tree/wall/window recursive prototype and real host attachment. 3. Furnished rooms, roofs, stairs, lights and independently packaged substitution. 4. Settlement compositions, finite adaptation/building corpora, renders and cutaways. The final evidence ledger will report actual outcomes and limitations, including the deliberately bounded movement, lighting and structural models. Sampled success is not a proof of all inputs. EOF
700
sed -n '66,165p' /work/generator/MCIO/mcio/sketch.py && sed -n '780,850p' /work/generator/MCIO/mcio/litematica.py && sed -n '1240,1335p' /work/generat
sed -n '66,165p' /work/generator/MCIO/mcio/sketch.py && sed -n '780,850p' /work/generator/MCIO/mcio/litematica.py && sed -n '1240,1335p' /work/generator/MCIO/mcio/litematica.py && sed -n '1,100p' /work/generator/MCIO/mcio/nbt/tag.py
| +===================+=========================================================+ | ``int`` | :class:`Byte` :class:`Short` :class:`Int` :class:`Long` | +-------------------+---------------------------------------------------------+ | ``float`` | :class:`Float` :class:`Double` | +-------------------+---------------------------------------------------------+ | ``str`` | :class:`String` | +-------------------+---------------------------------------------------------+ | ``numpy.ndarray`` | :class:`ByteArray` :class:`IntArray` :class:`LongArray` | +-------------------+---------------------------------------------------------+ | ``list`` | :class:`List` | +-------------------+---------------------------------------------------------+ | ``dict`` | :class:`Compound` | +-------------------+---------------------------------------------------------+ Operator overloading works as expected with all tag types. Note that values are returned unwrapped. .. doctest:: >>> data = Compound({"foo": Int(123)}) >>> data["foo"] = Int(-1 * data["foo"]) >>> data["bar"] = String("hello") >>> data Compound({'foo': Int(-123), 'bar': String('hello')}) """ __all__ = [ "Base", "Numeric", "NumericInteger", "Byte", "Short", "Int", "Long", "Float", "Double", "String", "List", "Compound", "End", "Array", "ByteArray", "IntArray", "LongArray", "EndInstantiation", "OutOfRange", "IncompatibleItemType", "CastError", ] from struct import Struct, error as StructError import numpy as np from mcio.nbt.serializer import serialize_tag from typing import BinaryIO, Literal, Dict from enum import Enum class ByteOrder(Enum): """Enum representing the byte order of nbt data.""" BIG = "big" LITTLE = "little"
800
cat > hearth/space.py <<'EOF' # Integer geometry and explicit local-to-world transforms. from dataclasses import dataclass from itertools import produ
cat > hearth/space.py <<'EOF' # Integer geometry and explicit local-to-world transforms. from dataclasses import dataclass from itertools import product from typing import Iterable Pos = tuple[int, int, int] @dataclass(frozen=True) class Box: lo: Pos hi: Pos def __post_init__(self): if any(a > b for a, b in zip(self.lo, self.hi)): raise ValueError('Inverted box') def contains(self, p: Pos) -> bool: return all(a <= v <= b for a, v, b in zip(self.lo, p, self.hi)) def cells(self) -> Iterable[Pos]: return product(*(range(a, b + 1) for a, b in zip(self.lo, self.hi))) def corners(self): return product(*zip(self.lo, self.hi)) def expand(self, n: int): return Box(tuple(v - n for v in self.lo), tuple(v + n for v in self.hi)) @property def size(self): return tuple(b - a + 1 for a, b in zip(self.lo, self.hi)) @property def volume(self): x, y, z = self.size return x * y * z @classmethod def enclosing(cls, points): points = list(points) if not points: raise ValueError('No realized geometry') return cls(tuple(min(p[i] for p in points) for i in range(3)), tuple(max(p[i] for p in points) for i in range(3))) @dataclass(frozen=True) class Frame: origin: Pos = (0, 0, 0) turn: int = 0 def vector(self, p: Pos) -> Pos: x, y, z = p for _ in range(self.turn % 4): x, z = -z, x return x, y, z def point(self, p: Pos) -> Pos: return tuple(a + b for a, b in zip(self.origin, self.vector(p))) def inverse(self, p: Pos) -> Pos: return Frame(turn=-self.turn).vector(tuple(a - b for a, b in zip(p, self.origin))) def box(self, box: Box) -> Box: return Box.enclosing(self.point(p) for p in box.corners()) def compose(self, other): return Frame(self.point(other.origin), (self.turn + other.turn) % 4) def state(self, state: str) -> str: from .blocks import parse, state_of name, props = parse(state) dirs = ['north', 'east', 'south', 'west'] rotated = {} for key, value in props.items(): if key in dirs: key = dirs[(dirs.index(key) + self.turn) % 4] if key == 'facing' and value in dirs: value = dirs[(dirs.index(value) + self.turn) % 4] if key == 'axis' and value in ('x', 'z') and self.turn % 2: value = 'z' if value == 'x' else 'x' if key == 'rotation': value = str((int(value) + 4 * self.turn) % 16) rotated[key] = value return state_of(name, **rotated) EOF cat > hearth/blocks.py <<'EOF' # Canonical blockstates and a deliberately conservative physical model. import json import re from functools import lru_cache from pathlib import Path SCHEMA = json.loads((Path(__file__).parent / 'data' / 'blockstates-1.21.1.json').read_text()) AIR = 'minecraft:air' LIGHTS = {'lantern': 15, 'torch': 14, 'wall_torch': 14, 'glowstone': 15, 'sea_lantern': 15, 'shroomlight': 15, 'ochre_froglight': 15, 'pearlescent_froglight': 15, 'verdant_froglight': 15} SOFT = {'air', 'cave_air', 'water', 'short_grass', 'fern', 'dead_bush', 'dandelion', 'poppy', 'cornflower', 'allium', 'azure_bluet', 'oxeye_daisy', 'lily_of_the_valley', 'blue_orchid', 'torch', 'wall_torch', 'vine', 'snow', 'lily_pad', 'tall_grass', 'large_fern', 'sunflower', 'rose_bush', 'peony', 'lilac', 'wheat', 'carrots', 'potatoes'} @lru_cache(maxsize=4096) def parse(state: str): match = re.fullmatch(r'(minecraft:[a-z0-9_]+)(?:\[([^\]]+)\])?', state) if not match: raise ValueError(f'Invalid blockstate syntax: {state}') props = {} if match[2]: for part in match[2].split(','): key, value = part.split('=') if key in props: raise ValueError('Duplicate block property') props[key] = value return match[1], props def state_of(name: str, **properties) -> str: if not name.startswith('minecraft:'): name = 'minecraft:' + name return name + ('[' + ','.join(f'{k}={str(v).lower()}' for k, v in sorted(properties.items())) + ']' if properties else '') def canonical(state: str) -> str: name, props = parse(state) return state_of(name, **props) def blockstates_equivalent(left: str, right: str) -> bool: return parse(left) == parse(right) @lru_cache(maxsize=4096) def validate_state(state: str): name, props = parse(state) short = name.removeprefix('minecraft:') if short not in SCHEMA: raise ValueError(f'Unknown Java 1.21.1 block: {name}') domain = SCHEMA[short][0] for key, value in props.items(): if key not in domain or value not in domain[key]: raise ValueError(f'Invalid property {key}={value} for {name}') @lru_cache(maxsize=4096) def name_of(state: str) -> str: return parse(state)[0].removeprefix('minecraft:') def solid(state: str) -> bool: name = name_of(state) return name not in SOFT and not any(s in name for s in ('leaves', 'fence', 'pane', 'door', 'lantern', 'chain', 'flower_pot', 'potted_', 'carpet', 'bed', 'button')) def passable(state: str) -> bool: name = name_of(state) return name in SOFT - {'water'} or name.endswith('_door') or name.endswith('_carpet') def stairs(material='stone_brick', facing='north', half='bottom'): return state_of(material + '_stairs', facing=facing, half=half, shape='straight', waterlogged='false') def slab(material='stone_brick', half='bottom'): return state_of(material + '_slab', type=half, waterlogged='false') def log(material='spruce', axis='y'): return state_of(material + '_log', axis=axis) def leaves(material='spruce'): return state_of(material + '_leaves', distance='1', persistent='true', waterlogged='false') EOF python - <<'PY' from pathlib import Path import json p=Path('/work/generator/MCRender/resources/1.21.1-blocks.json') Path('hearth/data/blockstates-1.21.1.json').write_text(json.dumps(json.loads(p.read_text()),sort_keys=True,separators=(',',':'))) PY cat > hearth/randomness.py <<'EOF' # Stateless hierarchical scopes, with explicitly local random streams. import hashlib import json import random from dataclasses import dataclass @dataclass(frozen=True) class Scope: seed: int key: tuple[str, ...] = () def child(self, key: str, override: int | None = None): return Scope(self.seed, self.key + (key,)) if override is None else Scope(override, (key,)) def stream(self, purpose: str = 'plan') -> random.Random: payload = json.dumps([self.seed, self.key, purpose], separators=(',', ':')).encode() return random.Random(int.from_bytes(hashlib.sha256(payload).digest(), 'big')) def choose(self, values, purpose='plan'): return self.stream(purpose).choice(tuple(values)) EOF cat > hearth/kernel/contracts.py <<'EOF' # Serializable contracts, binding requests and pure candidate plans. from dataclasses import dataclass, field from typing import Any, Protocol from hearth.space import Box, Frame, Pos @dataclass(frozen=True) class Domain: minimum: float | None = None maximum: float | None = None choices: tuple = () def accepts(self, value): return (not self.choices or value in self.choices) and (self.minimum is None or value >= self.minimum) and (self.maximum is None or value <= self.maximum) @dataclass(frozen=True) class Capability: name: str tags: tuple[str, ...] parameters: dict[str, Domain] = field(default_factory=dict) offers: tuple[str, ...] = () assumptions: tuple[str, ...] = () adaptations: tuple[str, ...] = () guarantees: tuple[str, ...] = () version: str = '1' @dataclass(frozen=True) class Rule: kind: str cells: tuple[Pos, ...] = () box: Box | None = None data: dict = field(default_factory=dict) phase: str = 'invariant' def transformed(self, frame): return Rule(self.kind, tuple(frame.point(p) for p in self.cells), frame.box(self.box) if self.box else None, self.data, self.phase) @dataclass(frozen=True) class Grant: key: str box: Box verbs: tuple[str, ...] tags: tuple[str, ...] = () limit: int = 100000 whole: bool = False @dataclass(frozen=True) class Port: key: str kind: str frame: Frame region: Box capacity: int = 1 grant: str | None = None alignment: int = 1 facts: dict = field(default_factory=dict) @dataclass(frozen=True) class Contract: envelope: Box ports: tuple[Port, ...] = () grants: tuple[Grant, ...] = () rules: tuple[Rule, ...] = () decisions: dict = field(default_factory=dict) reads: tuple[Box, ...] = () atomic_object: bool = False def transformed(self, frame): return Contract(frame.box(self.envelope), tuple(Port(p.key, p.kind, frame.compose(p.frame), frame.box(p.region), p.capacity, p.grant, p.alignment, p.facts) for p in self.ports), tuple(Grant(g.key, frame.box(g.box), g.verbs, g.tags, g.limit, g.whole) for g in self.grants), tuple(r.transformed(frame) for r in self.rules), self.decisions, tuple(frame.box(b) for b in self.reads), self.atomic_object) @dataclass(frozen=True) class Binding: host: str port: str verb: str = 'install' region: Box | None = None @dataclass(frozen=True) class Write: point: Pos state: str operation: str = 'realize' preserve_owner: bool = False nbt: dict | None = None @dataclass(frozen=True) class Child: key: str component: Any params: dict = field(default_factory=dict) frame: Frame = Frame() bindings: tuple[Binding, ...] = () seed: int | None = None @dataclass class Plan: writes: list[Write] = field(default_factory=list) children: list[Child] = field(default_factory=list) relations: list[tuple[str, str, str]] = field(default_factory=list) def block(self, point, state, operation='realize', **kwargs): self.writes.append(Write(tuple(point), state, operation, **kwargs)) def fill(self, box, state, operation='fill'): self.writes.extend(Write(p, state, operation) for p in box.cells()) class Component(Protocol): def capability(self) -> Capability: ... def negotiate(self, context, parameters: dict) -> Contract: ... def realize(self, context, contract: Contract) -> Plan: ... class Registry: def __init__(self): self.entries = {} def register(self, component): self.entries[component.capability().name] = component return component def select(self, *tags): return tuple(self.entries[k] for k in sorted(self.entries) if set(tags) <= set(self.entries[k].capability().tags)) EOF cat > hearth/kernel/errors.py <<'EOF' # Structured, stable diagnostics for failed contracts and searches. from dataclasses import dataclass @dataclass(frozen=True) class Diagnostic: rule: str component: str position: tuple | None conditions: str def __str__(self): return f'{self.rule}: {self.component} at {self.position}: {self.conditions}' class ContractError(ValueError): def __init__(self, rule, component='/', position=None, conditions=''): self.diagnostic = Diagnostic(rule, component, position, conditions) super().__init__(str(self.diagnostic)) class ValidationError(ContractError): def __init__(self, diagnostics): self.diagnostics = diagnostics self.diagnostic = diagnostics[0] ValueError.__init__(self, '\n'.join(map(str, diagnostics[:12]))) class SearchExhausted(ContractError): pass EOF cat > hearth/kernel/view.py <<'EOF' # Read-only, domain-aware environmental observations. from dataclasses import dataclass from hearth.blocks import AIR, solid, name_of, passable from hearth.kernel.errors import ContractError from hearth.space import Box @dataclass(frozen=True) class Observation: version: int region: Box elevation: int water: int | None material: str slope: int support_depth: int class View: def __init__(self, scene): self.__scene = scene @property def version(self): return self.__scene.version @property def domain(self): return self.__scene.domain def state(self, p): p = tuple(p) if self.domain and not self.domain.contains(p): raise ContractError('unknown-space', position=p, conditions='Outside explicit environment domain') record = self.__scene.blocks.get(p) return record.state if record else AIR def owner(self, p): record = self.__scene.blocks.get(tuple(p)) return record.owner if record else None def supports(self, p): return solid(self.state(p)) def clear(self, box): return all(passable(self.state(p)) for p in box.cells()) def elevation(self, x, z): if self.domain is None: raise ContractError('unknown-space', position=(x, 0, z), conditions='No environmental domain') for y in range(self.domain.hi[1], self.domain.lo[1] - 1, -1): if self.supports((x, y, z)): return y raise ContractError('missing-substrate', position=(x, self.domain.lo[1], z), conditions='No actual solid substrate') def water(self, x, z): if self.domain is None: raise ContractError('unknown-space', position=(x, 0, z)) for y in range(self.domain.hi[1], self.domain.lo[1] - 1, -1): if name_of(self.state((x, y, z))) == 'water': return y return None def sample(self, x, z): y = self.elevation(x, z) heights = [self.elevation(x + dx, z + dz) for dx, dz in ((1, 0), (-1, 0), (0, 1), (0, -1)) if self.domain.contains((x + dx, y, z + dz))] depth = 0 for yy in range(y, self.domain.lo[1] - 1, -1): if not self.supports((x, yy, z)): break depth += 1 return Observation(self.version, Box((x, self.domain.lo[1], z), (x, self.domain.hi[1], z)), y, self.water(x, z), self.state((x, y, z)), max([abs(h - y) for h in heights] or [0]), depth) def port(self, host, key): node = self.__scene.nodes[host] for p in node.contract.ports: if p.key == key: return p raise ContractError('missing-port', host, conditions=key) def contract(self, path): return self.__scene.nodes[path].contract def protected(self, box): return any(r.kind == 'clear' and any(box.contains(p) for p in r.cells) for n in self.__scene.nodes.values() for r in n.contract.rules) def obstacle_distance(self, p, radius=8): best = radius + 1 for q in Box(tuple(v - radius for v in p), tuple(v + radius for v in p)).cells(): if q in self.__scene.blocks and not passable(self.__scene.blocks[q].state): best = min(best, max(abs(a - b) for a, b in zip(p, q))) return best EOF
900
cat > hearth/kernel/validation.py <<'EOF' # Extensible actual-geometry validators and bounded player movement. from collections import deque from hear
cat > hearth/kernel/validation.py <<'EOF' # Extensible actual-geometry validators and bounded player movement. from collections import deque from hearth.blocks import AIR, LIGHTS, name_of, parse, passable, solid, validate_state from hearth.kernel.errors import Diagnostic from hearth.space import Box VALIDATORS = {} def validator(name): def register(fn): VALIDATORS[name] = fn return fn return register def state(scene, p): record = scene.blocks.get(tuple(p)) return record.state if record else AIR def fail(kind, node, point, message): return Diagnostic(kind, node.path, point, message) @validator('support') def support(scene, node, rule): for p in rule.cells: if not solid(state(scene, p)): yield fail('support', node, p, 'Required actual load-bearing cell is missing') @validator('clear') def clear(scene, node, rule): for p in rule.cells: if not passable(state(scene, p)): yield fail('clearance', node, p, 'Protected player headroom is obstructed') @validator('sealed') def sealed(scene, node, rule): for p in rule.cells: if name_of(state(scene, p)) in ('air', 'water'): yield fail('enclosure', node, p, 'Enclosed boundary has a gap') @validator('expected') def expected(scene, node, rule): allowed = set(rule.data['names']) for p in rule.cells: if name_of(state(scene, p)) not in allowed: yield fail('expected-geometry', node, p, f'Expected one of {sorted(allowed)}') @validator('pool') def pool(scene, node, rule): for x, y, z in rule.cells: if name_of(state(scene, (x, y, z))) != 'water': yield fail('pool-water', node, (x, y, z), 'Pool water missing') for q in ((x, y - 1, z), (x - 1, y, z), (x + 1, y, z), (x, y, z - 1), (x, y, z + 1)): if not solid(state(scene, q)) and name_of(state(scene, q)) != 'water': yield fail('pool-containment', node, q, 'Basin leaks') def standable(scene, p): x, y, z = p return passable(state(scene, p)) and passable(state(scene, (x, y + 1, z))) and solid(state(scene, (x, y - 1, z))) def reachable(scene, start, box): if not standable(scene, start): return set() reached = {start} queue = deque([start]) while queue: x, y, z = queue.popleft() for dx, dz in ((1, 0), (-1, 0), (0, 1), (0, -1)): for dy in (0, 1, -1): q = (x + dx, y + dy, z + dz) if q not in reached and box.contains(q) and standable(scene, q): # Ascending requires clearance above the lower step as well. high = (x, y + 2, z) if dy == 1 else (q[0], q[1] + 2, q[2]) if dy and not passable(state(scene, high)): continue reached.add(q) queue.append(q) return reached @validator('route') def route(scene, node, rule): if not rule.cells or rule.box is None: yield fail('route-contract', node, None, 'Route needs start, targets and bounded search region') return reached = reachable(scene, rule.cells[0], rule.box) for p in rule.cells: if p not in reached: yield fail('reachability', node, p, 'No walkable route with two blocks of headroom from entrance') @validator('light') def light(scene, node, rule): sources = [p for p in rule.box.cells() if name_of(state(scene, p)) in LIGHTS] if not sources: yield fail('lighting', node, rule.box.lo, 'Completed room has no actual light source') return # Bounded Manhattan attenuation model, with an unobstructed axis-order ray. for p in rule.cells: if not any(sum(abs(a-b) for a,b in zip(p, q)) <= LIGHTS[name_of(state(scene, q))] - rule.data.get('minimum', 1) for q in sources): yield fail('lighting', node, p, 'Required location outside conservative light radius') @validator('furnishing') def furnishing(scene, node, rule): names = {name_of(state(scene, p)) for p in rule.box.cells()} for group in rule.data['groups']: if not names.intersection(group): yield fail('furnishing', node, rule.box.lo, f'Missing functional furnishing: {group}') def validate(scene, final=False): diagnostics = [] for p, record in scene.blocks.items(): try: validate_state(record.state) except ValueError as exc: diagnostics.append(Diagnostic('blockstate', record.owner, p, str(exc))) if record.owner not in scene.nodes: diagnostics.append(Diagnostic('ownership', record.owner, p, 'Owner missing')) name, props = parse(record.state) if name.endswith('_door') and not name.endswith('_trapdoor'): dy = 1 if props.get('half') == 'lower' else -1 q = (p[0], p[1] + dy, p[2]) other, op = parse(state(scene, q)) if other != name or op.get('half') == props.get('half') or any(op.get(k) != props.get(k) for k in ('facing', 'hinge', 'open', 'powered')): diagnostics.append(Diagnostic('door-pair', record.owner, p, 'Door halves absent or inconsistent')) if name.endswith('_bed'): direction = {'north': (0,-1), 'south': (0,1), 'east': (1,0), 'west': (-1,0)}[props['facing']] sign = 1 if props['part'] == 'foot' else -1 q = (p[0] + direction[0]*sign,p[1],p[2] + direction[1]*sign) other, op = parse(state(scene, q)) if name != other or op.get('part') == props['part'] or op.get('facing') != props['facing']: diagnostics.append(Diagnostic('bed-pair', record.owner, p, 'Bed halves inconsistent')) if name_of(record.state) in ('sunflower', 'rose_bush', 'peony', 'lilac', 'tall_grass', 'large_fern'): dy = 1 if props.get('half') == 'lower' else -1 q = (p[0], p[1] + dy, p[2]) other, op = parse(state(scene, q)) if other != name or op.get('half') == props.get('half'): diagnostics.append(Diagnostic('plant-pair', record.owner, p, 'Tall plant halves inconsistent')) for node in scene.nodes.values(): if final and (not node.complete or node.stale): diagnostics.append(Diagnostic('unfinished', node.path, None, 'Scope unfinished or dependent inputs stale')) for rule in node.contract.rules: if rule.phase == 'complete' and not final: continue if rule.kind not in VALIDATORS: diagnostics.append(Diagnostic('unknown-validator', node.path, None, rule.kind)) else: diagnostics.extend(VALIDATORS[rule.kind](scene, node, rule)) return diagnostics EOF cat > hearth/kernel/scene.py <<'EOF' # Transaction kernel, automatic ownership and separate semantic/dependency graphs. import copy from dataclasses import dataclass, field, replace from hearth.blocks import AIR, canonical from hearth.space import Box, Frame from hearth.randomness import Scope from .contracts import Binding, Capability, Child, Contract, Plan from .errors import ContractError, ValidationError, SearchExhausted from .view import View from .validation import validate @dataclass(frozen=True) class Limits: dimension: int = 512 blocks: int = 1000000 depth: int = 40 search: int = 24 @dataclass(frozen=True) class Cell: state: str owner: str operation: str nbt: dict | None = None shared: tuple[str, ...] = () @dataclass class Node: path: str type: str version: str parameters: dict frame: Frame scope: Scope contract: Contract parent: str | None primary: str | None = None complete: bool = True stale: bool = False @dataclass(frozen=True) class Context: path: str frame: Frame scope: Scope view: View bindings: tuple[Binding, ...] limits: Limits def rng(self, purpose='plan'): return self.scope.stream(purpose) def world(self, p): return self.frame.point(p) def local(self, p): return self.frame.inverse(p) class Scene: def __init__(self, seed=0, limits=None, domain=None): if not isinstance(seed, int): raise TypeError('Seed must be an integer') self.seed = seed self.limits = limits or Limits() self.domain = domain self.blocks = {} self.nodes = {} self.reverse = {} self.relations = set() self.dependencies = [] self.operations = {} self.port_uses = {} self.version = 0 self.completed = False self._recipes = {} self.events = [] @property def view(self): return View(self) def _fork(self): other = copy.copy(self) other.blocks = self.blocks.copy() other.nodes = {p: copy.copy(n) for p, n in self.nodes.items()} other.reverse = {k: set(v) for k, v in self.reverse.items()} other.relations = set(self.relations) other.dependencies = list(self.dependencies) other.operations = copy.deepcopy(self.operations) other.port_uses = dict(self.port_uses) other._recipes = self._recipes.copy() other.events = list(self.events) return other def _commit(self, candidate): candidate.version += 1 candidate.completed = False self.__dict__.update(candidate.__dict__) def place(self, key, component, params=None, frame=Frame(), bindings=(), seed=None, complete=True): candidate = self._fork() path = '/' + key.strip('/') candidate._instantiate(path, component, params or {}, frame, tuple(bindings), None, Scope(self.seed).child(key, seed), complete) candidate._check(False) self._commit(candidate) return path def choose(self, key, candidates, score=lambda scene, path: 0): accepted, failed = [], [] for index, child in enumerate(candidates): if index >= self.limits.search: break trial = self._fork() try: path = trial.place(key, child.component, child.params, child.frame, child.bindings, child.seed) accepted.append((score(trial, path), index, trial, path)) except ContractError as exc: failed.append(str(exc)) if not accepted: raise SearchExhausted('search-budget', '/' + key, conditions=f'No validated candidate within budget {self.limits.search}; failures={failed}') accepted.sort(key=lambda item: (item[0], item[1])) best_score = accepted[0][0] best = [c for c in accepted if c[0] <= best_score + 0.1] chosen = Scope(self.seed).child(key).choose(best, 'alternatives') self._commit(chosen[2]) self.events.append({'kind': 'search', 'key': key, 'accepted': len(accepted), 'rejected': len(failed), 'failures': failed}) return chosen[3] def _instantiate(self, path, component, params, frame, bindings, parent, scope, complete=True): if path in self.nodes: raise ContractError('duplicate-instance', path) if len(path.split('/')) > self.limits.depth: raise ContractError('recursion-budget', path) cap = component.capability() for key, value in params.items(): if key not in cap.parameters or not cap.parameters[key].accepts(value): raise ContractError('parameter-domain', path, conditions=f'{key}={value!r}') ctx = Context(path, frame, scope, self.view, bindings, self.limits) local = component.negotiate(ctx, dict(params)) contract = local.transformed(frame) if max(contract.envelope.size) > self.limits.dimension: raise ContractError('dimension-budget', path) if parent and not all(self.nodes[parent].contract.envelope.contains(p) for p in contract.envelope.corners()): raise ContractError('child-envelope', path, contract.envelope.lo, f'Exceeds accepted parent {parent}') self.nodes[path] = Node(path, cap.name, cap.version, dict(params), frame, scope, contract, parent, complete=complete) self.reverse[path] = set() self._recipes[path] = (component, params, frame, bindings, parent, scope, complete) if parent: self.relations.add((path, 'contained_by', parent)) grants = [] for binding in bindings: if binding.host not in self.nodes: raise ContractError('missing-host', path, conditions=binding.host) host = self.nodes[binding.host] port = self.view.port(binding.host, binding.port) use_key = (binding.host, binding.port) if self.port_uses.get(use_key, 0) >= port.capacity: raise ContractError('port-capacity', path, port.frame.origin, binding.port) self.port_uses[use_key] = self.port_uses.get(use_key, 0) + 1 if binding.verb == 'install': if not port.region.contains(frame.origin): raise ContractError('port-alignment', path, frame.origin, 'Origin outside installation region') if (frame.origin[0] - port.frame.origin[0]) % port.alignment: raise ContractError('port-alignment', path, frame.origin, 'Outside facade bay grid') grant = next((g for g in host.contract.grants if g.key == port.grant), None) if grant: if binding.verb not in grant.verbs or (grant.tags and not set(cap.tags).intersection(grant.tags)): raise ContractError('permission-kind', path, frame.origin, f'{cap.tags} cannot {binding.verb} {binding.host}') grants.append((binding, grant)) elif binding.verb != 'connect': raise ContractError('no-write-grant', path) kind = 'attached_to' if binding.verb == 'install' else ('connected_to' if binding.verb == 'connect' else 'supported_by') self.relations.add((path, kind, binding.host)) if kind == 'attached_to' and self.nodes[path].primary is None: self.nodes[path].primary = binding.host self.dependencies.append({'consumer': path, 'source': binding.host, 'version': self.version, 'region': binding.region or port.region, 'reason': binding.verb}) for region in contract.reads: self.dependencies.append({'consumer': path, 'source': 'environment', 'version': self.version, 'region': region, 'reason': 'spatial-query'}) plan = component.realize(ctx, local) if not isinstance(plan, Plan): raise TypeError('Components return Plan effect sets') final_writes = {} for write in plan.writes: p = frame.point(write.point) final_writes[p] = write retired = set() counts = {} for p, write in final_writes.items(): if not contract.envelope.contains(p): raise ContractError('envelope', path, p, 'Realization exceeds negotiated bounds') old = self.blocks.get(p) if old and old.owner != path: authorization = next(((b, g) for b, g in grants if b.host == old.owner and g.box.contains(p) and (b.region is None or b.region.contains(p))), None) if authorization is None: raise ContractError('write-authority', path, p, f'Owned by {old.owner}; no scoped grant') binding, grant = authorization count_key = (binding.host, grant.key) counts[count_key] = counts.get(count_key, 0) + 1 if counts[count_key] > grant.limit: raise ContractError('edit-limit', path, p, f'Limit {grant.limit}') if self.nodes[old.owner].contract.atomic_object and not write.preserve_owner: if not grant.whole or not self.reverse[old.owner].issubset(final_writes): raise ContractError('whole-object', path, p, f'Partial replacement of {old.owner}') retired.add(old.owner) if old: self.reverse[old.owner].discard(p) world_state = frame.state(write.state) opid = path + '#' + write.operation operation = self.operations.setdefault(opid, {'component': path, 'name': write.operation, 'writes': 0, 'replaced': set()}) operation['writes'] += 1 if old: operation['replaced'].add(old.owner) if world_state == AIR: self.blocks.pop(p, None) else: owner = old.owner if old and write.preserve_owner else path self.blocks[p] = Cell(canonical(world_state), owner, opid, write.nbt) self.reverse[owner].add(p) for old in retired: self._retire(old) for child in plan.children: self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) self.relations.update(plan.relations) if len(self.blocks) > self.limits.blocks: raise ContractError('block-budget', path) def _retire(self, path): if self.reverse.get(path): raise ContractError('whole-object', path, conditions='Cannot retire occupied instance') self.nodes.pop(path, None) self.reverse.pop(path, None) self._recipes.pop(path, None) self.relations = {r for r in self.relations if r[0] != path and r[2] != path} self.dependencies = [d for d in self.dependencies if d['consumer'] != path and d['source'] != path] self.port_uses = {k: v for k, v in self.port_uses.items() if k[0] != path} def _check(self, final): errors = validate(self, final) if errors: raise ValidationError(errors) def finalize(self): self._check(True) self.completed = True return self def finish_scope(self, path): trial = self._fork() trial.nodes[path].complete = True trial._check(True) self._commit(trial) def cells(self, path, descendants=False): paths = [path] if descendants: paths = [k for k in self.nodes if k == path or k.startswith(path + '/')] return frozenset(p for k in paths for p in self.reverse.get(k, ())) def inspect(self, point): point = tuple(point) record = self.blocks.get(point) if not record: return {'position': point, 'state': AIR, 'instance': None, 'chain': [], 'related': [], 'operation': None} chain, seen = [], set() path = record.owner while path and path not in seen: seen.add(path) node = self.nodes[path] chain.append({'id': path, 'type': node.type}) path = node.primary or node.parent related = sorted(r for r in self.relations if r[0] in seen or r[2] in seen) return {'position': point, 'state': record.state, 'instance': record.owner, 'chain': chain, 'related': related, 'operation': self.operations.get(record.operation), 'shared': record.shared, 'nbt': record.nbt} def share(self, point, participant, host, port): trial = self._fork() p = tuple(point) record = trial.blocks[p] offered = trial.view.port(host, port) if record.owner != host or offered.kind != 'shared-support' or not offered.region.contains(p) or participant not in trial.nodes: raise ContractError('shared-authority', participant, p) trial.blocks[p] = replace(record, shared=tuple(sorted(set(record.shared + (participant,))))) trial.relations.add((participant, 'shares_support', host)) trial._check(False) self._commit(trial) def remove(self, path): trial = self._fork() trial._remove_branch(path) trial._check(False) self._commit(trial) def _remove_branch(self, path): paths = {k for k in self.nodes if k == path or k.startswith(path + '/')} affected = set() for k in paths: for p in self.reverse[k]: affected.add(p) self.blocks.pop(p, None) for d in self.dependencies: if d['consumer'] not in paths and (d['source'] in paths or any(d['region'].contains(p) for p in affected)): self.nodes[d['consumer']].stale = True for k in sorted(paths, reverse=True): self.reverse[k].clear() self._retire(k) self.relations = {r for r in self.relations if r[0] in self.nodes and r[2] in self.nodes} for p, record in list(self.blocks.items()): if set(record.shared).intersection(paths): self.blocks[p] = replace(record, shared=tuple(s for s in record.shared if s not in paths)) def regenerate(self, path, component=None, params=None, dependents=()): trial = self._fork() targets = [path] + list(dependents) recipes = {p: trial._recipes[p] for p in targets} for p in targets: trial._remove_branch(p) for p in targets: comp, oldparams, frame, bindings, parent, scope, complete = recipes[p] trial._instantiate(p, component if p == path and component is not None else comp, params if p == path and params is not None else oldparams, frame, bindings, parent, scope, complete) trial._check(True) self._commit(trial) self.events.append({'kind': 'regenerated', 'targets': targets}) EOF cat > hearth/kernel/__init__.py <<'EOF' # Public composition kernel, independent of architectural implementations. from .contracts import Binding, Capability, Child, Component, Contract, Domain, Grant, Plan, Port, Registry, Rule, Write from .errors import ContractError, Diagnostic, SearchExhausted, ValidationError from .scene import Context, Limits, Scene from .validation import validate, validator EOF cat > hearth/__init__.py <<'EOF' # Hearth public library entry points. from .kernel import Binding, Child, ContractError, Limits, Scene from .space import Box, Frame __version__ = '1.0.0' EOF
1000
cat > hearth/persistence.py <<'EOF' # One-region Litematica transport paired with verified structural records. import hashlib import json import sys f
cat > hearth/persistence.py <<'EOF' # One-region Litematica transport paired with verified structural records. import hashlib import json import sys from dataclasses import fields, is_dataclass from pathlib import Path from . import __version__ from .blocks import canonical, AIR from .space import Box, Frame from .randomness import Scope from .kernel import contracts from .kernel.scene import Scene, Node, Cell, Limits from .kernel.errors import ContractError FORMAT_VERSION = 1 TYPES = {c.__name__: c for c in (Box, Frame, Scope, Node, Cell, Limits, contracts.Contract, contracts.Rule, contracts.Port, contracts.Grant, contracts.Binding)} def encode(value): if is_dataclass(value): return {'$type': type(value).__name__, **{f.name: encode(getattr(value, f.name)) for f in fields(value)}} if isinstance(value, tuple): return {'$tuple': [encode(v) for v in value]} if isinstance(value, set): return {'$set': [encode(v) for v in sorted(value)]} if isinstance(value, dict): return {k: encode(v) for k, v in value.items()} if isinstance(value, list): return [encode(v) for v in value] return value def decode(value): if isinstance(value, list): return [decode(v) for v in value] if isinstance(value, dict): if '$tuple' in value: return tuple(decode(v) for v in value['$tuple']) if '$set' in value: return set(decode(v) for v in value['$set']) if '$type' in value: return TYPES[value['$type']](**{k: decode(v) for k, v in value.items() if k != '$type'}) return {k: decode(v) for k, v in value.items()} return value def semantic_digest(scene): digest = hashlib.sha256() for p, c in sorted(scene.blocks.items()): digest.update(json.dumps([p, canonical(c.state), c.nbt], sort_keys=True, separators=(',', ':')).encode()) return digest.hexdigest() def companion_path(path: Path): return path.with_suffix(path.suffix + '.structure.json') def _mcio(): try: import mcio except ImportError: sys.path.insert(0, '/work/generator/MCIO') from mcio.sketch import LitematicCanvas from mcio.schematic import load_schematic from mcio.nbt import tag from mcio.nbt.nbt import File return LitematicCanvas, load_schematic, tag, File def _to_nbt(value, tag, key=''): if isinstance(value, dict): return tag.Compound({k: _to_nbt(v, tag, k) for k, v in value.items()}) if isinstance(value, list): if not value: return tag.List[tag.Compound]([]) items = [_to_nbt(v, tag) for v in value] return tag.List[type(items[0])](items) if isinstance(value, str): return tag.String(value) if isinstance(value, int): return tag.Byte(value) if key == 'Slot' else tag.Int(value) raise TypeError(type(value)) def _plain(value): if isinstance(value, dict): return {str(k): _plain(v) for k, v in value.items()} if isinstance(value, (list, tuple)): return [_plain(v) for v in value] if isinstance(value, str): return str(value) return int(value) def export_scene(scene, path: Path, verify=True): path = Path(path) scene.finalize() bounds = Box.enclosing(scene.blocks) if max(bounds.size) > scene.limits.dimension: raise ContractError('export-bounds', conditions=str(bounds)) canvas_type, _, tag, nbtfile = _mcio() sx, sy, sz = bounds.size canvas = canvas_type((sy, sz, sx)) offset = bounds.lo block_entities = [] for p, cell in sorted(scene.blocks.items()): x, y, z = tuple(v - o for v, o in zip(p, offset)) canvas.block((y, z, x), cell.state) if cell.nbt is not None: block_entities.append(_to_nbt({**cell.nbt, 'x': x, 'y': y, 'z': z}, tag)) schematic = canvas.to_litematica(name='Hearth', author='Hearth procedural library', description='Contract-composed settlement; structural identity in companion JSON', minecraft_data_version=3955) nbt = schematic.write_to_nbt() nbt['Regions']['Hearth']['TileEntities'] = tag.List[tag.Compound](block_entities) nbt['Regions']['Hearth']['Entities'] = tag.List[tag.Compound]([]) path.parent.mkdir(parents=True, exist_ok=True) temporary = path.with_suffix(path.suffix + '.tmp') nbtfile(nbt).save(temporary) owners = sorted(scene.nodes) operations = sorted(scene.operations) owner_id, op_id = {v:i for i,v in enumerate(owners)}, {v:i for i,v in enumerate(operations)} data = {'format': 'hearth.structure', 'version': FORMAT_VERSION, 'implementation': __version__, 'minecraft_data_version': 3955, 'digest': semantic_digest(scene), 'offset': offset, 'size': bounds.size, 'seed': scene.seed, 'domain': encode(scene.domain), 'limits': encode(scene.limits), 'scene_version': scene.version, 'nodes': encode(scene.nodes), 'relations': encode(scene.relations), 'dependencies': encode(scene.dependencies), 'operations': encode(scene.operations), 'events': encode(scene.events), 'port_uses': [[*k, v] for k, v in sorted(scene.port_uses.items())], 'owners': owners, 'operation_ids': operations, 'cells': [[*p, owner_id[c.owner], op_id[c.operation], list(c.shared)] for p,c in sorted(scene.blocks.items())]} target = companion_path(path) temporary_meta = target.with_suffix('.json.tmp') temporary_meta.write_text(json.dumps(data, sort_keys=True, separators=(',', ':'))) temporary.replace(path) temporary_meta.replace(target) if verify: restored = load_scene(path) if semantic_digest(restored) != semantic_digest(scene): raise ContractError('roundtrip', conditions='Semantic geometry differs') return path def load_scene(path: Path): path = Path(path) meta = companion_path(path) if not meta.exists(): raise ContractError('untrusted-structure', conditions='Missing companion; geometry cannot reconstruct semantic identity') data = json.loads(meta.read_text()) if data.get('format') != 'hearth.structure' or data.get('version') != FORMAT_VERSION: raise ContractError('untrusted-structure', conditions='Unknown companion format/version') _, load, _, nbtfile = _mcio() loaded = load(path) nbt = nbtfile.load_regardless_of_gzipped(filename=path) regions = nbt['Regions'] if len(regions) != 1 or int(nbt['MinecraftDataVersion']) != 3955: raise ContractError('transport', conditions='Require one Java 1.21.1 region') region = next(iter(regions.values())) if list(loaded.size_yzx) != [data['size'][1], data['size'][2], data['size'][0]]: raise ContractError('geometry-mismatch', conditions='Export dimensions changed') if region['Entities']: raise ContractError('geometry-mismatch', conditions='Unexpected entities') inventories = {} for entry in region['TileEntities']: item = _plain(entry) p = tuple(item.pop(k) + data['offset'][i] for i, k in enumerate(('x', 'y', 'z'))) inventories[p] = item scene = Scene(data['seed'], decode(data['limits']), decode(data['domain'])) scene.nodes = decode(data['nodes']) scene.relations = decode(data['relations']) scene.dependencies = decode(data['dependencies']) scene.operations = decode(data['operations']) scene.events = decode(data['events']) scene.version = data['scene_version'] scene.port_uses = {(a, b): n for a, b, n in data['port_uses']} ownership = {tuple(row[:3]): row[3:] for row in data['cells']} scene.reverse = {k:set() for k in scene.nodes} ids = loaded.read_flat(0, loaded.volume).reshape(loaded.size_yzx) import numpy as np for y, z, x in np.argwhere(ids != 0): block = canonical(loaded.palette[int(ids[y,z,x])]) if block == AIR: continue p = tuple(int(v)+o for v,o in zip((x,y,z), data['offset'])) if p not in ownership: raise ContractError('geometry-mismatch', position=p, conditions='Unrecorded block') owner, op, shared = ownership[p] owner = data['owners'][owner] scene.blocks[p] = Cell(block, owner, data['operation_ids'][op], inventories.get(p), tuple(shared)) scene.reverse[owner].add(p) if set(ownership) != set(scene.blocks) or set(inventories) - set(scene.blocks) or semantic_digest(scene) != data['digest']: raise ContractError('geometry-mismatch', conditions='Schematic and structural companion are not a matching semantic pair') scene.finalize() return scene EOF python - <<'PY' import sys sys.path.insert(0,'/work/generator/MCIO') import mcio.nbt.nbt as n print([k for k in dir(n) if k in ['File','NBTFile']]) PY
['File']
1100
cat > hearth/environment/fields.py <<'EOF' # Serializable scalar-field expressions; recognizable terrain emerges from parameters. from dataclasses imp
cat > hearth/environment/fields.py <<'EOF' # Serializable scalar-field expressions; recognizable terrain emerges from parameters. from dataclasses import dataclass import math @dataclass(frozen=True) class Field: op: str args: tuple def __call__(self, x, z): a = self.args if self.op == 'constant': return a[0] if self.op == 'gradient': return a[0] * x + a[1] * z + a[2] if self.op == 'wave': return a[0] * math.sin(x * a[1] + a[3]) * math.cos(z * a[2] + a[3]) if self.op == 'radial': return a[3] * max(0, 1 - math.hypot(x-a[0], z-a[1]) / a[2]) if self.op == 'add': return a[0](x,z) + a[1](x,z) if self.op == 'multiply': return a[0](x,z) * a[1](x,z) if self.op == 'blend': mask = min(1, max(0, a[2](x,z))) return (1-mask)*a[0](x,z) + mask*a[1](x,z) if self.op == 'transform': return a[0]((x-a[1])/a[3], (z-a[2])/a[3]) if self.op == 'clamp': return max(a[1], min(a[2], a[0](x,z))) raise ValueError(self.op) def __add__(self, other): return Field('add', (self, as_field(other))) def __mul__(self, other): return Field('multiply', (self, as_field(other))) def blend(self, other, mask): return Field('blend', (self, as_field(other), as_field(mask))) def transformed(self, dx=0, dz=0, scale=1): if scale <= 0: raise ValueError('Scale must be positive') return Field('transform', (self, dx, dz, scale)) def clamp(self, low, high): return Field('clamp', (self, low, high)) def expression(self): return {'op': self.op, 'args': [a.expression() if isinstance(a, Field) else a for a in self.args]} def as_field(value): return value if isinstance(value, Field) else constant(value) def constant(value=0): return Field('constant', (value,)) def gradient(x=0, z=0, base=0): return Field('gradient', (x,z,base)) def wave(amplitude=1, frequency_x=0.1, frequency_z=0.1, phase=0): return Field('wave', (amplitude, frequency_x, frequency_z, phase)) def radial(x, z, radius, amplitude): if radius <= 0: raise ValueError('Radius must be positive') return Field('radial', (x,z,radius,amplitude)) EOF cat > hearth/environment/terrain.py <<'EOF' # Frozen field sampling, strata and water under scoped edit interfaces. import math from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of from hearth.kernel import Capability, Contract, Grant, Port, Plan, Rule from .fields import Field @dataclass(frozen=True) class Terrain: area: Box field: Field water_level: int | None = None edit_limit: int = 2500 def capability(self): return Capability('terrain.field', ('environment', 'ground'), offers=('construction', 'planting'), guarantees=('frozen field inputs', 'actual 3D substrate')) def negotiate(self, ctx, parameters): ports = tuple(Port(k, k, Frame(self.area.lo), self.area, capacity=100000, grant=k) for k in ('construction','planting')) grants = (Grant('construction', self.area, ('excavate','fill','surface'), ('siteworks','path','pool'), self.edit_limit), Grant('planting', self.area, ('plant',), ('plant',), 0)) return Contract(self.area, ports, grants, decisions={'expression': self.field.expression(), 'water': self.water_level, 'edit_limit': self.edit_limit}) def realize(self, ctx, contract): plan = Plan() x0, bottom, z0 = self.area.lo x1, top, z1 = self.area.hi for x in range(x0,x1+1): for z in range(z0,z1+1): height = math.floor(self.field(x,z)) if not bottom <= height < top: raise ValueError(f'Terrain field exceeds negotiated vertical domain at {(x,z)}') for y in range(bottom,height+1): material = 'stone' if y < height-2 else ('dirt' if y < height else 'grass_block') if self.water_level is not None and height < self.water_level: material = 'gravel' if y == height else material plan.block((x,y,z), state_of(material), 'strata') if self.water_level is not None: for y in range(height+1,self.water_level+1): plan.block((x,y,z),state_of('water',level='0'),'water-volume') return plan EOF cat > hearth/environment/__init__.py <<'EOF' # Public environment operations. from .fields import Field, constant, gradient, radial, wave from .terrain import Terrain EOF cat > hearth/components/primitives.py <<'EOF' # Small architectural components with executable contracts. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import AIR, state_of, log, leaves, name_of from hearth.kernel import Capability, Contract, Domain, Grant, Port, Rule, Plan, Child, Binding, ContractError @dataclass(frozen=True) class Volume: box: Box material: str role: str = 'masonry' def capability(self): return Capability('volume.' + self.role, (self.role,)) def negotiate(self, ctx, parameters): return Contract(self.box) def realize(self, ctx, contract): plan = Plan() plan.fill(self.box,self.material) return plan @dataclass(frozen=True) class Grass: tall: bool = False def capability(self): return Capability('plant.grass', ('plant',), offers=('replacement',), assumptions=('substrate',)) def negotiate(self, ctx, parameters): box = Box((0,0,0),(0,int(self.tall),0)) return Contract(box,(Port('replacement','planting',Frame(),box,grant='replace'),),(Grant('replace',box,('plant',),('tree',),2,True),),(Rule('support',((0,-1,0),)),),atomic_object=True) def realize(self,ctx,contract): plan=Plan() if self.tall: for y,half in enumerate(('lower','upper')): plan.block((0,y,0),state_of('tall_grass',half=half)) else: plan.block((0,0,0),state_of('short_grass')) return plan @dataclass(frozen=True) class Tree: height: int = 10 radius: int = 3 def capability(self): return Capability('plant.conifer', ('plant','tree'), {'height': Domain(5,18), 'radius':Domain(1,4)}, assumptions=('substrate',), adaptations=('prune canopy against obstacles within accepted radius',)) def negotiate(self,ctx,parameters): h,r=parameters.get('height',self.height),parameters.get('radius',self.radius) if not 5<=h<=18 or not 1<=r<=4: raise ContractError('tree-domain',ctx.path) return Contract(Box((-r,0,-r),(r,h,r)),rules=(Rule('support',((0,-1,0),)),Rule('expected',((0,0,0),),data={'names':['spruce_log']})),decisions={'height':h,'radius':r},reads=(Box((-r,-1,-r),(r,h,r)),)) def realize(self,ctx,contract): p=Plan(); h=contract.decisions['height']; radius=contract.decisions['radius'] for y in range(h): p.block((0,y,0),log()) for y in range(3,h+1): r=min(radius, max(0,(h-y+1)//2)) if y%3==0: r=max(0,r-1) for x in range(-r,r+1): for z in range(-r,r+1): if abs(x)+abs(z)>r+1 or (x==0 and z==0 and y<h): continue q=ctx.world((x,y,z)) if ctx.view.domain and not ctx.view.domain.contains(q): continue if name_of(ctx.view.state(q))=='air': p.block((x,y,z),leaves()) return p @dataclass(frozen=True) class Wall: width: int = 9 height: int = 5 thickness: int = 1 infill: str = 'minecraft:smooth_sandstone' timber: str = 'spruce' def capability(self): return Capability('wall.framed',('wall','enclosure'), offers=('window','door'), assumptions=('floor below',), guarantees=('frame preserved','sealed infill')) def negotiate(self,ctx,parameters): w,h,t=self.width,self.height,self.thickness if w<5 or h<4 or not 1<=t<=3: raise ContractError('wall-domain',ctx.path) box=Box((0,0,0),(w-1,h-1,t-1)); install=Box((1,0,0),(w-2,h-2,t-1)) ports=(Port('infill','wall-installation',Frame((1,0,0)),install,20,'install',1,{'thickness':t,'sill':1,'margin':1}),) grants=(Grant('install',install,('install',),('window','door'),w*h*t),) boundary=tuple(box.cells()) frame=tuple((x,y,z) for x in (0,w-1) for y in range(h) for z in range(t)) return Contract(box,ports,grants,(Rule('support',frame),Rule('sealed',boundary,phase='complete')),decisions={'width':w,'height':h,'thickness':t}) def realize(self,ctx,contract): p=Plan(); p.fill(contract.envelope,self.infill) for x in (0,self.width-1): p.fill(Box((x,0,0),(x,self.height-1,self.thickness-1)),log(self.timber)) p.fill(Box((0,self.height-1,0),(self.width-1,self.height-1,self.thickness-1)),log(self.timber,'x')) return p @dataclass(frozen=True) class Window: width: int = 2 height: int = 2 shutters: bool = True glass: str = 'minecraft:glass' def capability(self): return Capability('window.shuttered' if self.shutters else 'window.lattice',('window','sealed-opening'), offers=('daylight',), adaptations=('depth reveal',), guarantees=('sealed opening','frame margins')) def negotiate(self,ctx,parameters): if not ctx.bindings: raise ContractError('window-host',ctx.path) port=ctx.view.port(ctx.bindings[0].host,ctx.bindings[0].port) depth=port.facts['thickness'] box=Box((0,0,-1),(self.width-1,self.height-1,depth-1)) inner=Box((0,0,0),(self.width-1,self.height-1,depth-1)) if not all(port.region.contains(ctx.world(q)) for q in inner.corners()): raise ContractError('window-margins',ctx.path,ctx.frame.origin,'Opening crosses excluded framing') return Contract(box,rules=(Rule('sealed',tuple(inner.cells())),),decisions={'depth':depth}) def realize(self,ctx,contract): p=Plan(); d=contract.decisions['depth'] for z in range(d): p.fill(Box((0,0,z),(self.width-1,self.height-1,z)),self.glass,'glazing') if self.shutters: for x in (0,self.width-1): p.block((x,0,-1),state_of('spruce_trapdoor',facing='north',half='bottom',open='true',powered='false',waterlogged='false'),'shutters') else: for x in range(self.width): p.block((x,self.height-1,-1),state_of('spruce_trapdoor',facing='north',half='top',open='false',powered='false',waterlogged='false'),'hood') return p @dataclass(frozen=True) class Pool: width: int=7 depth: int=6 def capability(self): return Capability('water.basin',('pool','siteworks'),adaptations=('bounded excavation',),guarantees=('contained water',)) def negotiate(self,ctx,parameters): box=Box((0,-2,0),(self.width-1,0,self.depth-1)) water=tuple(Box((1,-1,1),(self.width-2,0,self.depth-2)).cells()) return Contract(box,rules=(Rule('pool',water),),decisions={'excavation_limit':box.volume}) def realize(self,ctx,contract): p=Plan();p.fill(contract.envelope,state_of('smooth_sandstone'),'basin') p.fill(Box((1,-1,1),(self.width-2,0,self.depth-2)),state_of('water',level='0'),'water') return p @dataclass(frozen=True) class Assembly: name: str envelope: Box children: tuple[Child,...] rules: tuple[Rule,...]=() ports: tuple[Port,...]=() def capability(self): return Capability(self.name,('composite',)) def negotiate(self,ctx,parameters): return Contract(self.envelope,ports=self.ports,rules=self.rules) def realize(self,ctx,contract): return Plan(children=list(self.children)) EOF cat > test/conftest.py <<'EOF' # Tests keep transient artifacts under test/ and remove them after each test. import sys import tempfile from pathlib import Path import pytest sys.path.insert(0,str(Path(__file__).parents[1])) @pytest.fixture def work(): with tempfile.TemporaryDirectory(dir=Path(__file__).parent,prefix='tmp-') as name: yield Path(name) EOF cat > test/test_kernel.py <<'EOF' # Foundation tests run before extending architectural content. from dataclasses import dataclass import pytest from hearth import Scene, Box, Frame, Binding, ContractError from hearth.kernel import Capability, Contract, Plan, Child, Rule from hearth.components.primitives import Assembly, Volume, Wall, Window, Grass, Tree, Pool from hearth.environment import Terrain, constant from hearth.blocks import state_of, blockstates_equivalent from hearth.persistence import export_scene, load_scene, semantic_digest def land(): s=Scene(12,domain=Box((-10,-3,-10),(20,25,20))) s.place('terrain',Terrain(s.domain,constant(0))) return s def test_composite_attachment_automatic_chain(): s=Scene(4) children=(Child('wall',Wall(),frame=Frame((0,1,0))),Child('window',Window(),frame=Frame((2,2,0)),bindings=(Binding('/house/wall','infill'),))) s.place('house',Assembly('house',Box((-1,0,-2),(10,8,3)),children)) q=s.inspect((2,2,0)) assert [n['type'] for n in q['chain']]==['window.shuttered','wall.framed','house'] assert len(s.cells('/house/window'))==6 assert s.cells('/house/window') <= s.cells('/house',True) def test_substitution_same_parent(): def parent(window): return Assembly('room',Box((-1,0,-2),(10,8,3)),(Child('wall',Wall()),Child('window',window,frame=Frame((2,1,0)),bindings=(Binding('/room/wall','infill'),)))) a,b=Scene(),Scene() a.place('room',parent(Window())) b.place('room',parent(Window(shutters=False))) assert semantic_digest(a)!=semantic_digest(b) assert a.nodes['/room/window'].contract.envelope==b.nodes['/room/window'].contract.envelope def test_tree_grass_and_pool_preserve_support(): s=land() s.place('grass',Grass(),frame=Frame((0,1,0)),bindings=(Binding('/terrain','planting','plant'),)) s.place('tree',Tree(),frame=Frame((0,1,0)),bindings=(Binding('/terrain','planting','plant'),Binding('/grass','replacement','plant'))) assert '/grass' not in s.nodes assert s.inspect((0,1,0))['instance']=='/tree' before=semantic_digest(s); nodes=set(s.nodes); ops=set(s.operations) with pytest.raises(ContractError): s.place('pool',Pool(),frame=Frame((-2,0,-2)),bindings=(Binding('/terrain','construction','excavate'),)) assert semantic_digest(s)==before and set(s.nodes)==nodes and set(s.operations)==ops with pytest.raises(ContractError): s.place('grass2',Grass(),frame=Frame((0,1,0))) s.place('pool-ok',Pool(),frame=Frame((6,0,6)),bindings=(Binding('/terrain','construction','excavate'),)) s.finalize() def test_tall_grass_whole_object_and_no_tree_excavation(): s=land();s.place('grass',Grass(True),frame=Frame((0,1,0))) with pytest.raises(ContractError): s.place('ordinary-tree',Tree(),frame=Frame((0,0,0)),bindings=(Binding('/terrain','construction','excavate'),)) s.place('tree',Tree(),frame=Frame((0,1,0)),bindings=(Binding('/grass','replacement','plant'),)) assert '/grass' not in s.nodes def test_transforms_and_persistence(work): frame=Frame((14,3,-7),1) s=Scene(-42) s.place('beam',Volume(Box((0,0,0),(2,0,0)),state_of('oak_log',axis='x')),frame=frame) assert s.inspect((14,3,-5))['state']==state_of('oak_log',axis='z') path=work/'space name.litematic' export_scene(s,path) restored=load_scene(path) assert restored.inspect((14,3,-5))==s.inspect((14,3,-5)) assert blockstates_equivalent('minecraft:oak_stairs[facing=north,half=bottom]','minecraft:oak_stairs[half=bottom,facing=north]') assert not blockstates_equivalent('minecraft:oak_log','minecraft:oak_log[axis=y]') import json meta=path.with_suffix('.litematic.structure.json');data=json.loads(meta.read_text());data['digest']='bad';meta.write_text(json.dumps(data)) with pytest.raises(ContractError,match='geometry-mismatch'): load_scene(path) def test_clearance_rollback_and_bounds(): s=Scene() s.place('stairs',Assembly('circulation',Box((0,0,0),(3,5,3)),(),(Rule('clear',((1,2,1),(1,3,1))),))) with pytest.raises(ContractError,match='clearance'): s.place('decoration',Volume(Box((1,3,1),(1,3,1)),state_of('stone'))) assert set(s.nodes)=={'/stairs'} and not s.blocks @dataclass class Escaper: def capability(self): return Capability('bad',()) def negotiate(self,c,p): return Contract(Box((0,0,0),(0,0,0))) def realize(self,c,b): p=Plan();p.block((1,0,0),state_of('stone'));return p with pytest.raises(ContractError,match='envelope'): s.place('bad',Escaper()) def test_seed_stability_and_regeneration(): from hearth.randomness import Scope a=Scope(123).child('house') before=a.stream('layout').getrandbits(64) Scope(123).child('failed').stream().random() assert before==a.stream('layout').getrandbits(64) s=Scene();s.place('beam',Volume(Box((0,0,0),(2,0,0)),state_of('stone'))) s.regenerate('/beam',Volume(Box((0,0,0),(1,0,0)),state_of('oak_planks'))) assert s.inspect((2,0,0))['instance'] is None assert len(s.cells('/beam'))==2 EOF python -m pytest -q test/test_kernel.py
....... [100%] 7 passed in 0.30s
1200
cat > hearth/composition.py <<'EOF' # High-level selection, arrangement, repetition, scattering and encapsulation. from dataclasses import dataclass f
cat > hearth/composition.py <<'EOF' # High-level selection, arrangement, repetition, scattering and encapsulation. from dataclasses import dataclass from hearth.kernel import Capability, Contract, Plan, Child, ContractError, Rule from hearth.space import Box, Frame @dataclass(frozen=True) class Network: name: str envelope: Box recipe: object tags: tuple = ('composite',) rules: tuple[Rule, ...] = () def capability(self): return Capability(self.name,self.tags) def negotiate(self,ctx,parameters): return Contract(self.envelope,rules=self.rules) def realize(self,ctx,contract): return self.recipe(ctx) def encapsulate(name, envelope, recipe, tags=('composite',), rules=()): return Network(name,envelope,recipe,tags,rules) def attach(key, component, host, port, frame, verb='install', region=None): from hearth.kernel import Binding return Child(key,component,frame=frame,bindings=(Binding(host,port,verb,region),)) def arrange(components, origins, prefix='item'): components,origins=tuple(components),tuple(origins) if len(components)!=len(origins): raise ValueError('One placement per component is required') return tuple(Child(f'{prefix}-{i}',c,frame=Frame(tuple(p))) for i,(c,p) in enumerate(zip(components,origins))) def repeat(component, origins, prefix='repeat'): return arrange([component for _ in origins],origins,prefix) def scatter(ctx, candidates, predicate, minimum, maximum, purpose='scatter'): candidates=sorted(set(candidates)) ctx.rng(purpose).shuffle(candidates) accepted=[] for p in candidates: if predicate(p,accepted): accepted.append(p) if len(accepted)>=maximum: break if len(accepted)<minimum: raise ContractError('scatter-minimum',ctx.path,conditions=f'Accepted {len(accepted)}, required {minimum}; finite candidate set exhausted') return tuple(accepted) def constrain(condition, rule, context, position=None, reason=''): if not condition: raise ContractError(rule,context.path,position,reason) EOF cat > hearth/adapters/site.py <<'EOF' # Measured, bounded support and access strategies independent of terrain recipes. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of, log, stairs, name_of, solid from hearth.kernel import Capability, Contract, Port, Grant, Rule, Plan, ContractError @dataclass(frozen=True) class SiteLimits: relief: int = 5 support_height: int = 8 approach_length: int = 12 fill_volume: int = 1600 excavation_volume: int = 300 def survey(ctx, footprint, limits=SiteLimits()): samples={} for x,z in sorted(footprint): wx,_,wz=ctx.world((x,0,z)) obs=ctx.view.sample(wx,wz) samples[(x,z)]=(obs.elevation-ctx.frame.origin[1],None if obs.water is None else obs.water-ctx.frame.origin[1],obs.support_depth) heights=[v[0] for v in samples.values()] relief=max(heights)-min(heights) if relief>limits.relief: raise ContractError('site-relief',ctx.path,ctx.frame.origin,f'Measured {relief}, permitted {limits.relief}') surface=max(max(v[0],v[1] if v[1] is not None else v[0]) for v in samples.values()) floor=surface+1 if floor-min(heights)>limits.support_height: raise ContractError('support-height',ctx.path,ctx.frame.origin,'Bounded support depth exceeded') wet=any(v[1] is not None and v[1]>=v[0] for v in samples.values()) strategies=['piers'] if wet or relief>=3 else ['stepped','piers'] strategy=ctx.scope.choose(strategies,'adaptation') return {'floor':floor,'relief':relief,'wet':wet,'strategy':strategy,'samples':samples} @dataclass(frozen=True) class Foundation: footprint: tuple[tuple[int,int],...] floor: int strategy: str limits: SiteLimits=SiteLimits() def capability(self): return Capability('adapter.foundation',('siteworks','support'),offers=('support',),assumptions=('actual bed within bounded depth',),adaptations=('stepped perimeter','piers to bed'),guarantees=('grounded support grid',)) def negotiate(self,ctx,parameters): positions=set(self.footprint) supports=[];columns=[] for x,z in sorted(positions): boundary=any((x+dx,z+dz) not in positions for dx,dz in ((1,0),(-1,0),(0,1),(0,-1))) grid=(x%4==0 and z%4==0) # Piers include perimeter every third cell and all corners. edge_pier=boundary and (x%3==0 or z%3==0 or sum((x+dx,z+dz) not in positions for dx,dz in ((1,0),(-1,0),(0,1),(0,-1)))>=2) if not (grid or (boundary if self.strategy=='stepped' else edge_pier)): continue wx,_,wz=ctx.world((x,0,z));bed=ctx.view.elevation(wx,wz)-ctx.frame.origin[1] if self.floor-bed>self.limits.support_height: raise ContractError('support-height',ctx.path,ctx.world((x,bed,z))) supports.append((x,bed,z));columns.append((x,bed,z,self.floor-1)) count=sum(max(0,top-bed) for x,bed,z,top in columns) if count>self.limits.fill_volume: raise ContractError('fill-volume',ctx.path,conditions=f'{count} > {self.limits.fill_volume}') for x,bed,z,top in columns: supports.extend((x,y,z) for y in range(bed+1,top+1)) box=Box.enclosing([(x,bed,z) for x,bed,z,top in columns]+[(x,self.floor-1,z) for x,bed,z,top in columns]) return Contract(box,rules=(Rule('support',tuple(supports)),),decisions={'columns':columns,'strategy':self.strategy,'fill':count,'excavation':0},reads=(box,)) def realize(self,ctx,contract): p=Plan() for x,bed,z,top in contract.decisions['columns']: for y in range(bed+1,top+1): material=log('spruce') if self.strategy=='piers' and y>bed+1 else state_of('stone_bricks') p.block((x,y,z),material,'contact') return p @dataclass(frozen=True) class Approach: center: int floor: int porch: int=0 limits: SiteLimits=SiteLimits() def capability(self): return Capability('adapter.approach',('siteworks','access'),offers=('street','surface'),adaptations=('stairs','landing','bounded fill'),guarantees=('two-block headroom','entrance connection')) def negotiate(self,ctx,parameters): rows=[] for step in range(1,self.limits.approach_length+1): z=-self.porch-step wx,_,wz=ctx.world((self.center,0,z)) ground=ctx.view.elevation(wx,wz)-ctx.frame.origin[1] y=max(ground,self.floor-step+1) rows.append((z,y)) if y==ground: break else: raise ContractError('approach-detour',ctx.path,ctx.frame.origin,'Cannot meet terrain within length bound') cells=[];support=[] for z,y in rows: cells.extend((x,y+k,z) for x in range(self.center-1,self.center+2) for k in (1,2)) support.extend((x,y,z) for x in range(self.center-1,self.center+2)) low=min(ctx.view.elevation(*((lambda p:(p[0],p[2]))(ctx.world((x,0,z))))) - ctx.frame.origin[1] for z,y in rows for x in range(self.center-1,self.center+2)) box=Box((self.center-1,low,rows[-1][0]),(self.center+1,self.floor+2,-self.porch-1)) end=(self.center,rows[-1][1]+1,rows[-1][0]) region=Box((self.center-1,rows[-1][1],rows[-1][0]),(self.center+1,rows[-1][1]+2,rows[-1][0])) port=Port('street','access',Frame(end),region,10,'surface') grant=Grant('surface',region,('surface',),('path',),9) route=tuple((self.center,y+1,z) for z,y in rows) return Contract(box,(port,),(grant,),(Rule('clear',tuple(cells)),Rule('support',tuple(support)),Rule('route',route,box.expand(1),phase='complete')),decisions={'rows':rows,'end':end},reads=(box,)) def realize(self,ctx,contract): p=Plan() rows=contract.decisions['rows'] for index,(z,y) in enumerate(rows): for x in range(self.center-1,self.center+2): wx,_,wz=ctx.world((x,0,z));bed=ctx.view.elevation(wx,wz)-ctx.frame.origin[1] for yy in range(bed+1,y): p.block((x,yy,z),state_of('cobblestone'),'step-footing') p.block((x,y,z),stairs('stone_brick','south') if index and rows[index-1][1]>y else state_of('stone_bricks'),'treads') return p EOF cat > hearth/components/interior.py <<'EOF' # Usable doors, lights and furnished rooms assembled as semantic children. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of, stairs, slab, log from hearth.kernel import Capability, Contract, Grant, Port, Rule, Plan, Child, Binding, ContractError from .primitives import Volume, Wall, Window @dataclass(frozen=True) class Door: material: str='spruce' def capability(self): return Capability('opening.door',('door','access'),guarantees=('paired halves','support','operable exit')) def negotiate(self,ctx,parameters): return Contract(Box((0,0,0),(0,1,0)),rules=(Rule('support',((0,-1,0),)),),atomic_object=True) def realize(self,ctx,contract): p=Plan() for y,half in enumerate(('lower','upper')): p.block((0,y,0),state_of(self.material+'_door',facing='north',half=half,hinge='left',open='false',powered='false')) return p @dataclass(frozen=True) class Light: hanging: bool=True def capability(self): return Capability('light.lantern',('light','room-light'),guarantees=('actual light source',)) def negotiate(self,ctx,parameters): return Contract(Box((0,0,0),(0,1,0)),rules=(Rule('expected',((0,0,0),),data={'names':['lantern']}),)) def realize(self,ctx,contract): p=Plan();p.block((0,0,0),state_of('lantern',hanging=str(self.hanging).lower(),waterlogged='false')) if self.hanging: p.block((0,1,0),state_of('chain',axis='y',waterlogged='false')) return p @dataclass(frozen=True) class Furniture: purpose: str='living' width: int=11 depth: int=11 def capability(self): return Capability('furniture.'+self.purpose,('furniture',self.purpose),guarantees=('usable function',)) def negotiate(self,ctx,parameters): if self.purpose not in ('living','bedroom','workshop','library','kitchen','storage'): raise ContractError('room-function',ctx.path,conditions=self.purpose) return Contract(Box((1,0,1),(self.width-2,2,self.depth-2))) def realize(self,ctx,contract): p=Plan();w,d=self.width,self.depth inventory={'id':'minecraft:barrel','Items':[{'Slot':0,'id':'minecraft:bread','count':6},{'Slot':1,'id':'minecraft:torch','count':12}]} p.block((w-3,0,2),state_of('barrel',facing='north',open='false'),'supplies',nbt=inventory) if self.purpose=='bedroom': for z,part in ((2,'foot'),(3,'head')): p.block((2,0,z),state_of('red_bed',facing='south',part=part,occupied='false'),'bed') p.block((2,0,d-3),state_of('bookshelf')) elif self.purpose=='library': for x in (2,3,w-3): for y in range(2): p.block((x,y,d-2),state_of('bookshelf')) p.block((2,0,2),state_of('lectern',facing='south',has_book='false',powered='false')) elif self.purpose=='workshop': p.block((2,0,2),state_of('crafting_table')) p.block((3,0,2),state_of('smithing_table')) p.block((2,0,d-3),state_of('anvil',facing='north')) elif self.purpose=='kitchen': p.block((2,0,2),state_of('smoker',facing='south',lit='false')) p.block((3,0,2),state_of('furnace',facing='south',lit='false')) p.block((2,0,d-3),state_of('crafting_table')) else: for z in (2,3): p.block((2,0,z),stairs('spruce','east'),'bench') p.block((w-3,0,d-1-z),stairs('spruce','west'),'bench') p.block((3,0,2),state_of('spruce_fence',north='false',south='false',east='false',west='false',waterlogged='false')) p.block((3,1,2),state_of('spruce_pressure_plate',powered='false'),'table') # Rugs avoid the central circulation cross and door landings. for x in (3,4): for z in (d-4,d-3): p.block((x,0,z),state_of('red_carpet'),'rug') return p @dataclass(frozen=True) class Stair: rise: int=6 width: int=2 def capability(self): return Capability('circulation.stair',('stairs','vertical-access'),guarantees=('walkable flight','two-block headroom')) def negotiate(self,ctx,parameters): points=tuple((x,i+1,i) for i in range(self.rise) for x in range(self.width)) clear=tuple((x,i+k,i) for i in range(self.rise) for x in range(self.width) for k in (1,2,3)) support=tuple((x,i,i) for i in range(self.rise) for x in range(self.width)) box=Box((0,0,-1),(self.width-1,self.rise+2,self.rise)) return Contract(box,rules=(Rule('support',support),Rule('clear',clear),Rule('route',points,box,phase='complete'))) def realize(self,ctx,contract): p=Plan() for i in range(self.rise): for x in range(self.width): for y in range(i): p.block((x,y,i),state_of('spruce_planks'),'stringer') p.block((x,i,i),stairs('spruce','south'),'tread') return p @dataclass(frozen=True) class Room: purpose: str width: int=11 depth: int=11 doors: tuple[str,...]=('north',) windows: tuple[str,...]=('north','east','south','west') upper_open: bool=False stair_up: bool=False stair_down: bool=False window_component: object=None light_component: object=None def capability(self): return Capability('room.'+self.purpose,('room','habitable','composite'),offers=('access',),guarantees=('lit','furnished','reachable','enclosed'),adaptations=('facade grid','substitutable windows and lights')) def negotiate(self,ctx,parameters): w,d=self.width,self.depth if w<9 or d<9: raise ContractError('room-domain',ctx.path) doors={'north':(w//2,1,0),'south':(w//2,1,d-1),'west':(0,1,d//2),'east':(w-1,1,d//2)} points=[doors[k] for k in self.doors]+[(w//2,1,d//2)] if not self.doors: points=[(w//2,1,d//2)] interior=Box((1,1,1),(w-2,5,d-2)) boundary=[] for x in range(w): for z in range(d): # Upper landing leaves only the required stair slot open. if not (self.stair_down and x in (w-4,w-3) and 2<=z<=7): boundary.append((x,0,z)) if not (self.stair_up and x in (w-4,w-3) and 2<=z<=7): boundary.append((x,6,z)) function={'bedroom':[['red_bed'],['barrel']],'workshop':[['crafting_table'],['smithing_table']],'library':[['bookshelf'],['lectern']],'kitchen':[['smoker'],['furnace']],'living':[['spruce_stairs'],['barrel']],'storage':[['barrel']]} rules=(Rule('route',tuple(points),Box((0,1,0),(w-1,8,d-1)),phase='complete'),Rule('light',tuple(points),Box((0,1,0),(w-1,5,d-1)),{'minimum':1},'complete'),Rule('furnishing',box=interior,data={'groups':function[self.purpose]},phase='complete'),Rule('sealed',tuple(boundary),phase='complete')) ports=tuple(Port(side,'access',Frame(p),Box(p,(p[0],p[1]+1,p[2])),10) for side,p in doors.items() if side in self.doors) return Contract(Box((-1,0,-1),(w,9,d)),ports=ports,rules=rules,decisions={'purpose':self.purpose,'doors':self.doors,'windows':self.windows,'stair_up':self.stair_up,'stair_down':self.stair_down}) def realize(self,ctx,contract): w,d=self.width,self.depth;p=Plan() floor=Plan() for x in range(w): for z in range(d): if not (self.stair_down and x in (w-4,w-3) and 2<=z<=7): floor.block((x,0,z),state_of('spruce_planks')) p.children.append(Child('floor',Pattern('floor',Box((0,0,0),(w-1,0,d-1)),tuple(floor.writes)))) if not self.upper_open: p.children.append(Child('ceiling',Volume(Box((0,6,0),(w-1,6,d-1)),state_of('spruce_planks'),'ceiling'))) walls={'north':(Frame((0,1,0)),w),'south':(Frame((w-1,1,d-1),2),w),'east':(Frame((w-1,1,1),1),d-2),'west':(Frame((0,1,d-2),3),d-2)} for side,(frame,length) in walls.items(): wallpath=ctx.path+'/wall-'+side p.children.append(Child('wall-'+side,Wall(length,5),frame=frame)) if side in self.doors: at=frame.compose(Frame((length//2,0,0))) p.children.append(Child('door-'+side,Door(),frame=at,bindings=(Binding(wallpath,'infill'),))) if side in self.windows: bays=(2,length-4) if length>=11 else (1,length-3) for i,bay in enumerate(bays): if side in self.doors and abs(bay-length//2)<2: continue at=frame.compose(Frame((bay,2,0))) p.children.append(Child(f'window-{side}-{i}',self.window_component or Window(),frame=at,bindings=(Binding(wallpath,'infill'),))) # Furnish the opposite half to the flight; clipping stays inside the furnishing component's declared domain. furniture=Furniture(self.purpose,w,d) if self.stair_up or self.stair_down: furniture=Furniture(self.purpose,w-3,d) p.children.append(Child('furniture',furniture,frame=Frame((0,1,0)))) for i,(x,z) in enumerate(((2,d-3),(w-3,2))): if self.stair_up and i==1: x=w//2 p.children.append(Child(f'light-{i}',self.light_component or Light(),frame=Frame((x,4,z)))) if self.stair_up: p.children.append(Child('stairs',Stair(),frame=Frame((w-4,1,2)))) return p @dataclass(frozen=True) class Pattern: role: str envelope: Box writes: tuple def capability(self): return Capability('surface.'+self.role,(self.role,)) def negotiate(self,ctx,parameters): return Contract(self.envelope) def realize(self,ctx,contract): return Plan(writes=list(self.writes)) EOF
1300
cat > hearth/components/roofs.py <<'EOF' # Pitched roof surfaces and open porch attachments with explicit overlap policy. from dataclasses import data
cat > hearth/components/roofs.py <<'EOF' # Pitched roof surfaces and open porch attachments with explicit overlap policy. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of, stairs, slab, log, name_of from hearth.kernel import Capability, Contract, Grant, Port, Rule, Plan, Child from .interior import Light @dataclass(frozen=True) class Roof: width: int depth: int axis: str='z' material: str='deepslate_tile' steep: bool=True def capability(self): return Capability('roof.gable',('roof','enclosure'),offers=('junction',),adaptations=('abut taller wall','merge shared eaves'),guarantees=('pitched weather skin',)) def negotiate(self,ctx,parameters): span=self.width if self.axis=='z' else self.depth height=(span+2)//2+2 box=Box((-1,0,-1),(self.width,height,self.depth)) return Contract(box,(Port('junction','roof-seam',Frame(),box,100,'junction'),),(Grant('junction',box,('join',),('roof',),box.volume),),decisions={'axis':self.axis,'span':span,'steep':self.steep,'material':self.material}) def realize(self,ctx,contract): p=Plan();w,d=self.width,self.depth span=w if self.axis=='z' else d length=d if self.axis=='z' else w for cross in range(-1,span+1): step=min(cross+1,span-cross) y=step if self.steep else (step+1)//2 face=('east' if cross<span/2 else 'west') if self.axis=='z' else ('south' if cross<span/2 else 'north') for along in range(-1,length+1): x,z=(cross,along) if self.axis=='z' else (along,cross) q=ctx.world((x,y,z)) existing=name_of(ctx.view.state(q)) if existing!='air': # Negotiated abutment is only to actual masonry/roof boundaries. continue trim=along in (-1,length) material='dark_oak' if trim else self.material p.block((x,y,z),stairs(material,face),'roof-course') if y and along in (0,length-1) and 0<=cross<span: for yy in range(y): q=ctx.world((x,yy,z)) if name_of(ctx.view.state(q))=='air': p.block((x,yy,z),log('spruce') if cross in (span//2,0,span-1) else state_of('smooth_sandstone'),'gable') mid=span//2;peak=min(mid+1,span-mid) if self.steep else (min(mid+1,span-mid)+1)//2 for along in range(-1,length+1): x,z=(mid,along) if self.axis=='z' else (along,mid) if name_of(ctx.view.state(ctx.world((x,peak+1,z))))=='air': p.block((x,peak+1,z),slab('dark_oak'),'ridge') for along in (-1,length): x,z=(mid,along) if self.axis=='z' else (along,mid) if name_of(ctx.view.state(ctx.world((x,peak+2,z))))=='air': p.block((x,peak+2,z),state_of('dark_oak_fence',north='false',south='false',east='false',west='false',waterlogged='false'),'finial') return p @dataclass(frozen=True) class Porch: width: int depth: int=3 def capability(self): return Capability('attachment.porch',('attachment','access','composite'),guarantees=('open sheltered access',)) def negotiate(self,ctx,parameters): center=self.width//2 clear=tuple((x,y,z) for x in range(center-1,center+2) for y in (1,2,3) for z in range(-self.depth,0)) return Contract(Box((0,0,-self.depth),(self.width-1,6,-1)),rules=(Rule('clear',clear),)) def realize(self,ctx,contract): p=Plan();w=self.width;d=self.depth p.fill(Box((0,0,-d),(w-1,0,-1)),state_of('spruce_planks'),'deck') for x in (0,w-1): p.fill(Box((x,1,-d),(x,4,-d)),log(),'post') for z in range(-d,0): y=4+(z+d)//2 for x in range(w): p.block((x,y,z),slab('dark_oak') if z%2 else stairs('dark_oak','south'),'canopy') for x in range(w): if abs(x-w//2)>1: p.block((x,1,-d),state_of('spruce_fence',north='false',south='false',east=str(x<w-1).lower(),west=str(x>0).lower(),waterlogged='false'),'balustrade') p.children.append(Child('lantern',Light(),frame=Frame((1,2,-2)))) return p EOF cat > hearth/components/building.py <<'EOF' # Room-graph building composition and shared facade/roof planning. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.kernel import Capability, Contract, Port, Plan, Child, Binding, Rule, ContractError from hearth.adapters.site import survey, Foundation, Approach, SiteLimits from .interior import Room from .roofs import Roof, Porch @dataclass(frozen=True) class RoomSpec: x: int z: int level: int purpose: str @dataclass(frozen=True) class Blueprint: rooms: tuple[RoomSpec,...] bay: int=11 porch: bool=True roof_axis: str='auto' roof_material: str='deepslate_tile' steep: bool=True window_component: object=None light_component: object=None def normalized(self): return tuple(sorted(self.rooms,key=lambda r:(r.level,r.z,r.x,r.purpose))) @property def footprint(self): return tuple(sorted((r.x*self.bay+x,r.z*self.bay+z) for r in self.rooms if r.level==0 for x in range(self.bay) for z in range(self.bay))) def validate(self): cells={(r.x,r.z,r.level) for r in self.rooms} if len(cells)!=len(self.rooms) or (0,0,0) not in cells or min(min(r.x,r.z,r.level) for r in self.rooms)<0: raise ValueError('Unique nonnegative rooms and entrance room (0,0,0) required') if self.bay not in (9,11,13): raise ValueError('Supported room bays: 9, 11, 13') for x,z,level in cells: if level and (x,z,level-1) not in cells: raise ValueError('Upper rooms require a supporting lower room') reached={(0,0,0)} while True: more={p for p in cells if any(sum(abs(a-b) for a,b in zip(p,q))==1 for q in reached)} if more<=reached: break reached|=more if reached!=cells: raise ValueError('Room adjacency graph disconnected') @dataclass(frozen=True) class Building: design: Blueprint terrain: str site_limits: SiteLimits=SiteLimits() def capability(self): return Capability('building.rooms',('building','habitable','composite'),offers=('entrance','street','attachment'),assumptions=('known ground','bounded relief'),adaptations=('foundation','approach','roof junction'),guarantees=('locked room graph','internal reachability','furnishing','lighting')) def negotiate(self,ctx,parameters): self.design.validate() b=self.design.bay;rooms=self.design.normalized() measured=survey(ctx,self.design.footprint,self.site_limits) floor=measured['floor'];height=max(r.level for r in rooms)*6 width=(max(r.x for r in rooms)+1)*b;depth=(max(r.z for r in rooms)+1)*b minimum=min(v[0] for v in measured['samples'].values()) front=self.site_limits.approach_length+(3 if self.design.porch else 0) box=Box((-1,min(minimum,0),-front),(width,floor+height+b+12,depth)) points=tuple((r.x*b+b//2,floor+r.level*6+1,r.z*b+b//2) for r in rooms) entrance=(b//2,floor+1,0) route=Rule('route',(entrance,)+points,box,phase='complete') port=Port('entrance','access',Frame(entrance),Box(entrance,(entrance[0],entrance[1]+1,entrance[2])),10) decisions={'floor':floor,'relief':measured['relief'],'wet':measured['wet'],'foundation':measured['strategy'],'rooms':[(r.x,r.z,r.level,r.purpose) for r in rooms],'bay':b,'roof_axis':self.design.roof_axis,'porch':self.design.porch,'roof_material':self.design.roof_material,'steep':self.design.steep} return Contract(box,ports=(port,),rules=(route,),decisions=decisions,reads=(Box((0,minimum,0),(width-1,floor,depth-1)),)) def realize(self,ctx,contract): p=Plan();b=self.design.bay;floor=contract.decisions['floor'];rooms=self.design.normalized() cells={(r.x,r.z,r.level) for r in rooms} p.children.append(Child('foundation',Foundation(self.design.footprint,floor,contract.decisions['foundation'],self.site_limits),bindings=(Binding(self.terrain,'construction','fill',ctx.frame.box(contract.envelope)),))) # A spanning tree of vertical access: one flight per upper horizontal component. stair_columns=set() for level in sorted({r.level for r in rooms if r.level}): remaining={(x,z) for x,z,l in cells if l==level} while remaining: seed=min(remaining);connected={seed} while True: expanded={v for v in remaining if any(abs(v[0]-q[0])+abs(v[1]-q[1])==1 for q in connected)} if expanded<=connected:break connected|=expanded root=min(connected) stair_columns.add((root[0],root[1],level-1)) remaining-=connected for r in rooms: adjacent={'north':(r.x,r.z-1,r.level),'south':(r.x,r.z+1,r.level),'west':(r.x-1,r.z,r.level),'east':(r.x+1,r.z,r.level)} doors=tuple(side for side,q in adjacent.items() if q in cells or (side=='north' and (r.x,r.z,r.level)==(0,0,0))) windows=tuple(side for side,q in adjacent.items() if q not in cells) key=f'room-{r.x}-{r.z}-{r.level}' room=Room(r.purpose,b,b,doors,windows,(r.x,r.z,r.level+1) in cells,(r.x,r.z,r.level) in stair_columns,(r.x,r.z,r.level-1) in stair_columns,self.design.window_component,self.design.light_component) p.children.append(Child(key,room,frame=Frame((r.x*b,floor+r.level*6,r.z*b)))) if self.design.porch: p.children.append(Child('porch',Porch(b),frame=Frame((0,floor,0)))) p.children.append(Child('approach',Approach(b//2,floor,3 if self.design.porch else 0,self.site_limits),bindings=(Binding(self.terrain,'construction','surface',ctx.frame.box(contract.envelope)),))) # Rectangular roof runs are derived from exposed top rooms, not a building family. top={(r.x,r.z,r.level) for r in rooms if (r.x,r.z,r.level+1) not in cells} groups=[] while top: x,z,l=min(top,key=lambda v:(v[2],v[1],v[0]));axis=self.design.roof_axis if axis=='auto': axis='x' if (x+1,z,l) in top else 'z' run=[(x,z,l)] while ((run[-1][0]+(axis=='x'),run[-1][1]+(axis=='z'),l)) in top: run.append((run[-1][0]+(axis=='x'),run[-1][1]+(axis=='z'),l)) top-=set(run);groups.append((x,z,l,axis,len(run))) for i,(x,z,l,axis,length) in enumerate(groups): w=b*(length if axis=='x' else 1);d=b*(length if axis=='z' else 1) p.children.append(Child(f'roof-{i}',Roof(w,d,axis,self.design.roof_material,self.design.steep),frame=Frame((x*b,floor+l*6+7,z*b)))) return p EOF cat > hearth/adapters/__init__.py <<'EOF' # Reusable environmental contact and circulation adapters. from .site import Foundation, Approach, SiteLimits, survey EOF python -m compileall -q hearth python - <<'PY' from hearth import * from hearth.environment import * from hearth.components.building import * s=Scene(0,domain=Box((-20,-3,-25),(40,55,40))) s.place('land',Terrain(s.domain,constant(3))) b=Building(Blueprint((RoomSpec(0,0,0,'living'),RoomSpec(0,0,1,'bedroom'))),'/land') s.place('home',b) s.finalize() print(len(s.blocks),len(s.nodes)) PY
29373 44
1401
python - <<'PY' p='hearth/components/roofs.py' s=open(p).read().replace('from .interior import Light','from .interior import Light\nfrom .primitives i
python - <<'PY' p='hearth/components/roofs.py' s=open(p).read().replace('from .interior import Light','from .interior import Light\nfrom .primitives import Window') s=s.replace('Box((-1,0,-1),(self.width,height,self.depth))','Box((-1,-1,-1),(self.width,height,self.depth))') start=s.index(' if y and along in (0,length-1)') end=s.index(' mid=span//2',start) s=s[:start]+''' for end in (0,length-1): frame=Frame((0,0,end)) if self.axis=='z' else Frame((end,0,span-1),3) p.children.append(Child(f'gable-{end}',Gable(span,self.steep),frame=frame)) for cross in (-1,span): for along in range(length): x,z=(cross,along) if self.axis=='z' else (along,cross) if name_of(ctx.view.state(ctx.world((x,-1,z))))=='air': p.block((x,-1,z),slab('spruce','top'),'eave') ''' + s[end:] # Gables must adapt to taller adjoining rooms too. s += '''\n\n@dataclass(frozen=True) class Gable: span: int steep: bool=True def capability(self): return Capability('wall.gable',('wall','enclosure'),offers=('window',),adaptations=('abut existing upper wall',)) def negotiate(self,ctx,parameters): height=(self.span+1)//2 region=Box((1,0,0),(self.span-2,height-2,0)) box=Box((0,0,-1),(self.span-1,height-1,0)) return Contract(box,(Port('infill','wall-installation',Frame((1,0,0)),region,4,'install',facts={'thickness':1}),),(Grant('install',region,('install',),('window',),30),)) def realize(self,ctx,contract): p=Plan() for x in range(self.span): step=min(x+1,self.span-x) y=step if self.steep else (step+1)//2 for yy in range(y): if name_of(ctx.view.state(ctx.world((x,yy,0))))=='air': p.block((x,yy,0),log('spruce') if x in (0,self.span//2,self.span-1) else state_of('smooth_sandstone'),'gable-infill') available={w.point for w in p.writes} at=(self.span//2-1,0,0) if self.steep and all((at[0]+x,y,0) in available for x in range(2) for y in (0,1)): from hearth.kernel import Binding p.children.append(Child('window',Window(2,2,False),frame=Frame(at),bindings=(Binding(ctx.path,'infill'),))) return p ''' open(p,'w').write(s) PY cat > examples/prototype.py <<'EOF' # Run the small terrain, planting and attached-window composition before full buildings. import argparse from pathlib import Path from hearth import Scene, Box, Frame, Binding from hearth.environment import Terrain, gradient, wave from hearth.components.primitives import Wall, Window, Grass, Tree from hearth.composition import encapsulate from hearth.kernel import Plan, Child from hearth.persistence import export_scene def build(seed=0): scene=Scene(seed,domain=Box((-8,-3,-8),(20,24,20))) scene.place('land',Terrain(scene.domain,gradient(base=2)+wave(0.6,0.2,0.2))) def facade(ctx): return Plan(children=[Child('wall',Wall(thickness=2)),Child('window',Window(),frame=Frame((3,1,0)),bindings=(Binding(ctx.path+'/wall','infill'),))]) scene.place('facade',encapsulate('facade',Box((-1,0,-2),(10,6,3)),facade),frame=Frame((0,4,0))) y=scene.view.elevation(13,9)+1 scene.place('grass',Grass(True),frame=Frame((13,y,9)),bindings=(Binding('/land','planting','plant'),)) scene.place('tree',Tree(),frame=Frame((13,y,9)),bindings=(Binding('/land','planting','plant'),Binding('/grass','replacement','plant'))) return scene.finalize() if __name__=='__main__': parser=argparse.ArgumentParser();parser.add_argument('--seed',type=int,default=0);parser.add_argument('--output',type=Path,default=Path('samples/prototype.litematic'));args=parser.parse_args() export_scene(build(args.seed),args.output) EOF python -m pytest -q test/test_kernel.py PYTHONPATH=. python examples/prototype.py --seed 0 python - <<'PY' from hearth import * from hearth.environment import * from hearth.components.building import * from hearth.persistence import export_scene s=Scene(0,domain=Box((-8,-3,-15),(28,50,27))) s.place('land',Terrain(s.domain,gradient(base=3)+wave(1,.1,.15))) s.place('home',Building(Blueprint((RoomSpec(0,0,0,'living'),RoomSpec(0,0,1,'bedroom'),RoomSpec(1,0,0,'workshop'))),'/land')) s.finalize();export_scene(s,__import__('pathlib').Path('samples/development-house.litematic')) print(len(s.blocks),len(s.nodes)) PY
....... [100%] 7 passed in 0.37s 12292 69
1510
cat > hearth/components/landscape.py <<'EOF' # Public paths, planted borders, lamps and constrained landscape compositions. from dataclasses import da
cat > hearth/components/landscape.py <<'EOF' # Public paths, planted borders, lamps and constrained landscape compositions. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of, stairs, slab, log, leaves, name_of from hearth.kernel import Capability, Contract, Port, Grant, Rule, Plan, Child, Binding, ContractError from hearth.composition import scatter from .primitives import Tree, Grass from .interior import Light @dataclass(frozen=True) class PathNetwork: waypoints: tuple[tuple[int,int],...] links: tuple[tuple[int,int],...] width: int=3 def capability(self): return Capability('landscape.paths',('path','connection'),offers=('public-access',),adaptations=('terrain treads','bounded retaining edges'),guarantees=('connected public routes',)) def _points(self): points=set() for a,b in self.links: x,z=self.waypoints[a];xx,zz=self.waypoints[b] dx=1 if xx>=x else -1;dz=1 if zz>=z else -1 line=[(v,z) for v in range(x,xx+dx,dx)]+[(xx,v) for v in range(z,zz+dz,dz)] for px,pz in line: for ox in range(-(self.width//2),self.width//2+1): for oz in range(-(self.width//2),self.width//2+1): points.add((px+ox,pz+oz)) return sorted(points) def negotiate(self,ctx,parameters): points=[] for x,z in self._points(): wx,_,wz=ctx.world((x,0,z));h=ctx.view.elevation(wx,wz)-ctx.frame.origin[1] points.append((x,h,z)) if not points: raise ContractError('empty-path',ctx.path) box=Box.enclosing(points).expand(2) targets=[] for x,z in self.waypoints: wx,_,wz=ctx.world((x,0,z));targets.append((x,ctx.view.elevation(wx,wz)+1-ctx.frame.origin[1],z)) clears=tuple((x,y+k,z) for x,y,z in points for k in (1,2)) return Contract(box,ports=(Port('public','public-access',Frame(targets[0]),box,10000),),rules=(Rule('support',tuple(points)),Rule('clear',clears),Rule('route',tuple(targets),box,phase='complete')),decisions={'surface':points,'waypoints':self.waypoints,'links':self.links},reads=(box,)) def realize(self,ctx,contract): p=Plan();rng=ctx.rng('materials');heights={(x,z):y for x,y,z in contract.decisions['surface']} for x,y,z in contract.decisions['surface']: uphill=[] for dx,dz,face in ((1,0,'east'),(-1,0,'west'),(0,1,'south'),(0,-1,'north')): if heights.get((x+dx,z+dz),y)>y: uphill.append(face) material=stairs('stone_brick',uphill[0]) if uphill else state_of(rng.choice(('stone_bricks','stone_bricks','andesite','cobblestone','mossy_stone_bricks'))) p.block((x,y,z),material,'paving') return p @dataclass(frozen=True) class Planter: width: int=3 flowers: tuple[str,...]=('cornflower','azure_bluet','allium') def capability(self): return Capability('garden.planter',('decoration','plant'),guarantees=('grounded bed',)) def negotiate(self,ctx,parameters): return Contract(Box((0,0,0),(self.width-1,1,1)),rules=(Rule('support',tuple((x,-1,z) for x in range(self.width) for z in range(2))),)) def realize(self,ctx,contract): p=Plan();rng=ctx.rng('flowers') for x in range(self.width): p.block((x,0,0),state_of('dirt'),'soil') p.block((x,1,0),state_of(rng.choice(self.flowers)),'flower') p.block((x,0,1),state_of('spruce_trapdoor',facing='south',half='bottom',open='true',powered='false',waterlogged='false'),'edging') return p @dataclass(frozen=True) class LampPost: def capability(self): return Capability('landscape.lamppost',('light','outdoor-light','composite')) def negotiate(self,ctx,parameters): return Contract(Box((0,0,0),(1,4,0)),rules=(Rule('support',((0,-1,0),)),)) def realize(self,ctx,contract): p=Plan();p.block((0,0,0),state_of('stone_bricks')) for y in range(1,4): p.block((0,y,0),state_of('spruce_fence',north='false',south='false',east='false',west='false',waterlogged='false')) p.block((0,4,0),slab('spruce'));p.block((1,4,0),slab('spruce')) p.children.append(Child('lantern',Light(),frame=Frame((1,2,0)))) return p @dataclass(frozen=True) class Landscape: area: Box terrain: str tree_minimum: int=6 tree_maximum: int=14 density: float=0.08 def capability(self): return Capability('landscape.scatter',('landscape','composite'),adaptations=('clearance-aware scattering',),guarantees=('minimum tree count','preserved routes')) def negotiate(self,ctx,parameters): return Contract(self.area,decisions={'minimum_trees':self.tree_minimum,'maximum_trees':self.tree_maximum,'density':self.density}) def realize(self,ctx,contract): p=Plan();x0,_,z0=self.area.lo;x1,_,z1=self.area.hi candidates=[(x,z) for x in range(x0+4,x1-3,4) for z in range(z0+4,z1-3,4)] def legal(q,accepted): x,z=q if any(abs(x-a)+abs(z-b)<10 for a,b in accepted):return False h=ctx.view.elevation(x,z) if name_of(ctx.view.state((x,h,z)))!='grass_block':return False box=Box((x-3,h+1,z-3),(x+3,h+16,z+3)) return all(ctx.view.domain.contains(c) for c in box.corners()) and ctx.view.clear(box) and not ctx.view.protected(Box((x-3,h,z-3),(x+3,h+2,z+3))) chosen=scatter(ctx,candidates,legal,self.tree_minimum,self.tree_maximum,'trees') for i,(x,z) in enumerate(chosen): y=ctx.view.elevation(x,z)+1 h=ctx.scope.child(f'tree-{i}').choose((9,11,13,15),'height') p.children.append(Child(f'tree-{i}',Tree(h),frame=Frame((x,y,z)),bindings=(Binding(self.terrain,'planting','plant'),))) rng=ctx.rng('groundcover') for x in range(x0+1,x1): for z in range(z0+1,z1): if rng.random()>self.density or any(abs(x-a)<=3 and abs(z-b)<=3 for a,b in chosen):continue h=ctx.view.elevation(x,z) if name_of(ctx.view.state((x,h,z)))!='grass_block':continue if name_of(ctx.view.state((x,h+1,z)))!='air':continue if ctx.view.protected(Box((x,h+1,z),(x,h+2,z))):continue p.children.append(Child(f'grass-{x}-{z}',Grass(),frame=Frame((x,h+1,z)),bindings=(Binding(self.terrain,'planting','plant'),))) return p EOF cat > hearth/programs.py <<'EOF' # Lightweight high-level room-graph programs and settlement intent. from hearth import Scene, Box, Frame from hearth.randomness import Scope from hearth.kernel import Capability, Contract, Plan, Child, Binding, Rule from hearth.environment import Terrain, gradient, wave, radial from hearth.components.building import Blueprint, Building, RoomSpec from hearth.components.landscape import PathNetwork, Landscape, LampPost from hearth.components.primitives import Window from hearth.composition import encapsulate def dwelling(seed): rng=Scope(seed).child('dwelling').stream('layout') rooms=[RoomSpec(0,0,0,'living'),RoomSpec(0,0,1,'bedroom')] if rng.choice((True,False)): rooms.append(RoomSpec(0,1,0,'kitchen')) if rng.choice((True,False)): rooms.append(RoomSpec(1,0,0,'library')) return Blueprint(tuple(rooms),bay=rng.choice((9,11)),porch=True,roof_axis='auto',steep=True) def atelier(seed): rng=Scope(seed).child('atelier').stream('layout') rooms=[RoomSpec(0,0,0,'workshop'),RoomSpec(1,0,0,'storage')] if rng.choice((True,False)): rooms.append(RoomSpec(1,0,1,'bedroom')) if rng.choice((True,False)): rooms.append(RoomSpec(0,1,0,'kitchen')) return Blueprint(tuple(rooms),bay=rng.choice((9,11)),porch=rng.choice((True,False)),roof_axis='x',roof_material='brick',steep=rng.choice((True,False)),window_component=Window(shutters=False)) def commons(seed): rng=Scope(seed).child('commons').stream('layout') rooms=[RoomSpec(0,0,0,'library'),RoomSpec(0,1,0,'living'),RoomSpec(1,1,0,'kitchen')] for level in range(1,rng.choice((2,3))): rooms.append(RoomSpec(0,1,level,'bedroom' if level==1 else 'library')) if rng.choice((True,False)): rooms.append(RoomSpec(1,0,0,'storage')) return Blueprint(tuple(rooms),bay=rng.choice((9,11)),porch=True,roof_axis='z') PROGRAMS={'dwelling':dwelling,'atelier':atelier,'commons':commons} def building_scene(design,seed=0,field=None,water=None): design.validate();b=design.bay width=(max(r.x for r in design.rooms)+1)*b;depth=(max(r.z for r in design.rooms)+1)*b domain=Box((-8,-4,-18),(width+8,64,depth+8)) scene=Scene(seed,domain=domain) expression=field if field is not None else gradient(base=4)+wave(.8,.1,.11,Scope(seed).stream('environment').random()*6) scene.place('land',Terrain(domain,expression,water)) scene.place('building',Building(design,'/land')) return scene.finalize() class Settlement: def __init__(self,designs,domain,terrain): self.designs=tuple(designs);self.domain=domain;self.terrain=terrain def capability(self): return Capability('settlement.village',('settlement','composite'),offers=('public-access',),guarantees=('building entrances connected',)) def negotiate(self,ctx,parameters): return Contract(self.domain,decisions={'buildings':len(self.designs),'arrangement':'opposed street with staggered frontage'}) def realize(self,ctx,contract): p=Plan() for i,design in enumerate(self.designs): row=i//2;left=i%2==0 z=row*38+ctx.scope.child(f'plot-{i}').choose((-2,0,2),'frontage') origin=(-16,0,z-design.bay//2) if left else (16,0,z+design.bay//2) p.children.append(Child(f'plot-{i}',Building(design,self.terrain),frame=Frame(origin,1 if left else 3))) p.children.append(Child('connections',SettlementConnections(len(self.designs),self.domain,self.terrain))) p.children.append(Child('landscape',Landscape(self.domain,self.terrain,8,12,0.045))) return p class SettlementConnections: def __init__(self,count,domain,terrain): self.count=count;self.domain=domain;self.terrain=terrain def capability(self): return Capability('settlement.connections',('connection','composite')) def negotiate(self,ctx,parameters): parent=ctx.path.rsplit('/',1)[0] targets=tuple(ctx.view.port(f'{parent}/plot-{i}/approach','street').frame.origin for i in range(self.count)) return Contract(self.domain,rules=(Rule('route',targets,self.domain,phase='complete'),)) def realize(self,ctx,contract): parent=ctx.path.rsplit('/',1)[0];points=[];links=[];bindings=[Binding(self.terrain,'construction','surface')] for i in range(self.count): host=f'{parent}/plot-{i}/approach';port=ctx.view.port(host,'street');x,y,z=port.frame.origin points.extend(((x,z),(0,z)));links.append((2*i,2*i+1));bindings.append(Binding(host,'street','surface')) if i:links.append((2*i-1,2*i+1)) p=Plan(children=[Child('paths',PathNetwork(tuple(points),tuple(links)),bindings=tuple(bindings))]) for i in range(self.count): p.relations.append((ctx.path+'/paths','connects',f'{parent}/plot-{i}')) for i,z in enumerate(sorted({z for x,z in points})): x=5 if i%2 else -5;y=ctx.view.elevation(x,z)+1 p.children.append(Child(f'lamp-{i}',LampPost(),frame=Frame((x,y,z+4)))) return p def settlement_scene(seed=0,count=None): scope=Scope(seed);rng=scope.stream('settlement-layout') if count is None:count=rng.choice((3,4,5)) if count<1:raise ValueError('A settlement needs at least one building') recipes=(dwelling,atelier,commons) designs=[recipes[i%len(recipes)](scope.child(f'building-{i}').stream('seed').getrandbits(64)) for i in range(count)] rows=(count+1)//2 domain=Box((-49,-4,-23),(49,64,(rows-1)*38+28)) field=gradient(.012,-.009,4.8)+wave(.7,.075,.09,rng.random()*6)+radial(-36,rows*12,26,1.1) scene=Scene(seed,domain=domain) scene.place('land',Terrain(domain,field,edit_limit=20000)) scene.place('village',Settlement(designs,domain,'/land')) return scene.finalize() EOF cat > generate.py <<'EOF' # Generate, validate and export the default complete Hearth settlement. import argparse from pathlib import Path from hearth.programs import settlement_scene from hearth.persistence import export_scene, semantic_digest def main(): parser=argparse.ArgumentParser(description='Generate a contract-composed Minecraft Java 1.21.1 settlement.') parser.add_argument('--seed',type=int,default=0,help='Explicit integer seed, default 0') parser.add_argument('--output',type=Path,default=Path('output.litematic')) parser.add_argument('--count',type=int,choices=range(3,7),help='Optional explicit building count, 3 through 6') args=parser.parse_args() scene=settlement_scene(args.seed,args.count) export_scene(scene,args.output) print(f'Validated {sum(n.type=="building.rooms" for n in scene.nodes.values())} buildings, {len(scene.blocks)} blocks, {len(scene.nodes)} components.') print(f'{args.output} | semantic SHA256 {semantic_digest(scene)}') if __name__=='__main__': main() EOF python generate.py
Traceback (most recent call last): File "/work/generator/workspace/generate.py", line 21, in <module> main() File "/work/generator/workspace/generate.py", line 14, in main scene=settlement_scene(args.seed,args.count) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/work/generator/workspace/hearth/programs.py", line 116, in settlement_scene scene.place('village',Settlement(designs,domain,'/land')) File "/work/generator/workspace/hearth/kernel/scene.py", line 108, in place candidate._instantiate(path, component, params or {}, frame, tuple(bindings), None, Scope(self.seed).child(key, seed), complete) File "/work/generator/workspace/hearth/kernel/scene.py", line 227, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 227, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 227, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) [Previous line repeated 1 more time] File "/work/generator/workspace/hearth/kernel/scene.py", line 200, in _instantiate raise ContractError('write-authority', path, p, f'Owned by {old.owner}; no scoped grant') hearth.kernel.errors.ContractError: write-authority: /village/plot-0/roof-1/gable-0/window at (-24, 13, -1): Owned by /village/plot-0/room-0-0-1/wall-south; no scoped grant
1602
xvfb-run -a /work/generator/MCRender/node_modules/.bin/vite-node --script /opt/tools/render_schematic.mjs -- --input samples/development-house.litemat
xvfb-run -a /work/generator/MCRender/node_modules/.bin/vite-node --script /opt/tools/render_schematic.mjs -- --input samples/development-house.litematic --output previews/development-house.png --size 1000 --azimuth 215 --elevation 26 --radius 3.0 --fov 30 --ambient 0.75
parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! Using WebGL2 context for WebGL requests instead of WebGL Loaded structure from /work/generator/workspace/samples/development-house.litematic in 18 ms Set structure in renderer in 246 ms Rendering development-house at azimuth 0 (1/1)... Rendered image in 71 ms (azimuth: 3.752457891787808, elevation: 0.4537856055185257) wrote /work/generator/workspace/previews/development-house.png (1000x1000, azimuth 215, elevation 26)
1711
python - <<'PY' p='hearth/components/roofs.py';s=open(p).read();s=s.replace("if self.steep and all((at[0]+x,y,0) in available for x in range(2) for y
python - <<'PY' p='hearth/components/roofs.py';s=open(p).read();s=s.replace("if self.steep and all((at[0]+x,y,0) in available for x in range(2) for y in (0,1)):","if self.steep and all((at[0]+x,y,0) in available for x in range(2) for y in (0,1)) and all(name_of(ctx.view.state(ctx.world((at[0]+x,1,-1))))=='air' for x in range(2)):") open(p,'w').write(s) PY python generate.py
Traceback (most recent call last): File "/work/generator/workspace/generate.py", line 21, in <module> main() File "/work/generator/workspace/generate.py", line 14, in main scene=settlement_scene(args.seed,args.count) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/work/generator/workspace/hearth/programs.py", line 116, in settlement_scene scene.place('village',Settlement(designs,domain,'/land')) File "/work/generator/workspace/hearth/kernel/scene.py", line 108, in place candidate._instantiate(path, component, params or {}, frame, tuple(bindings), None, Scope(self.seed).child(key, seed), complete) File "/work/generator/workspace/hearth/kernel/scene.py", line 227, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 227, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 200, in _instantiate raise ContractError('write-authority', path, p, f'Owned by {old.owner}; no scoped grant') hearth.kernel.errors.ContractError: write-authority: /village/connections/paths at (-14, 4, 75): Owned by /village/plot-4/approach; no scoped grant
1811
python - <<'PY' p='hearth/adapters/site.py';s=open(p).read();s=s.replace("region=Box((self.center-1,rows[-1][1],rows[-1][0]),(self.center+1,rows[-1][1
python - <<'PY' p='hearth/adapters/site.py';s=open(p).read();s=s.replace("region=Box((self.center-1,rows[-1][1],rows[-1][0]),(self.center+1,rows[-1][1]+2,rows[-1][0]))","region=Box((self.center-1,rows[-1][1],rows[-1][0]),(self.center+1,self.floor+2,min(-self.porch-1,rows[-1][0]+1)))").replace("('path',),9)","('path',),18)") open(p,'w').write(s) PY python generate.py
Traceback (most recent call last): File "/work/generator/workspace/generate.py", line 21, in <module> main() File "/work/generator/workspace/generate.py", line 14, in main scene=settlement_scene(args.seed,args.count) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/work/generator/workspace/hearth/programs.py", line 116, in settlement_scene scene.place('village',Settlement(designs,domain,'/land')) File "/work/generator/workspace/hearth/kernel/scene.py", line 108, in place candidate._instantiate(path, component, params or {}, frame, tuple(bindings), None, Scope(self.seed).child(key, seed), complete) File "/work/generator/workspace/hearth/kernel/scene.py", line 227, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 227, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 200, in _instantiate raise ContractError('write-authority', path, p, f'Owned by {old.owner}; no scoped grant') hearth.kernel.errors.ContractError: write-authority: /village/connections/paths at (15, 13, -3): Owned by /village/plot-1/roof-0; no scoped grant
1911
python - <<'PY' p='hearth/kernel/view.py';s=open(p).read().replace('def elevation(self, x, z):','def elevation(self, x, z, maximum=None):').replace('f
python - <<'PY' p='hearth/kernel/view.py';s=open(p).read().replace('def elevation(self, x, z):','def elevation(self, x, z, maximum=None):').replace('for y in range(self.domain.hi[1], self.domain.lo[1] - 1, -1):\n if self.supports','for y in range(self.domain.hi[1] if maximum is None else min(maximum,self.domain.hi[1]), self.domain.lo[1] - 1, -1):\n if self.supports',1);open(p,'w').write(s) p='hearth/components/landscape.py';s=open(p).read().replace('x,z=self.waypoints[a];xx,zz=self.waypoints[b]','x,z=self.waypoints[a][0],self.waypoints[a][-1];xx,zz=self.waypoints[b][0],self.waypoints[b][-1]') s=s.replace("wx,_,wz=ctx.world((x,0,z));h=ctx.view.elevation(wx,wz)-ctx.frame.origin[1]","hint=min(self.waypoints,key=lambda q:abs(q[0]-x)+abs(q[-1]-z))\n maximum=hint[1] if len(hint)==3 else None\n wx,_,wz=ctx.world((x,0,z));h=ctx.view.elevation(wx,wz,maximum=maximum)-ctx.frame.origin[1]",1) s=s.replace("for x,z in self.waypoints:\n wx,_,wz=ctx.world((x,0,z));targets.append((x,ctx.view.elevation(wx,wz)+1-ctx.frame.origin[1],z))","surface={(x,z):y for x,y,z in points}\n for q in self.waypoints:\n x,z=q[0],q[-1];targets.append((x,surface[(x,z)]+1,z))") open(p,'w').write(s) p='hearth/programs.py';s=open(p).read().replace("points.extend(((x,z),(0,z)))","points.extend(((x,y,z),(0,ctx.view.elevation(0,z)+1,z)))").replace("sorted({z for x,z in points})","sorted({q[-1] for q in points})") open(p,'w').write(s) PY python generate.py
Traceback (most recent call last): File "/work/generator/workspace/generate.py", line 21, in <module> main() File "/work/generator/workspace/generate.py", line 14, in main scene=settlement_scene(args.seed,args.count) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/work/generator/workspace/hearth/programs.py", line 116, in settlement_scene scene.place('village',Settlement(designs,domain,'/land')) File "/work/generator/workspace/hearth/kernel/scene.py", line 109, in place candidate._check(False) File "/work/generator/workspace/hearth/kernel/scene.py", line 245, in _check raise ValidationError(errors) hearth.kernel.errors.ValidationError: support: /village/connections/lamp-0 at (-5, 5, 2): Required actual load-bearing cell is missing support: /village/connections/lamp-1 at (5, 5, 4): Required actual load-bearing cell is missing support: /village/connections/lamp-4 at (-5, 4, 80): Required actual load-bearing cell is missing
2004
python - <<'PY' from hearth.programs import PROGRAMS,building_scene for name,recipe in PROGRAMS.items(): for seed in range(8): try: s=building_s
python - <<'PY' from hearth.programs import PROGRAMS,building_scene for name,recipe in PROGRAMS.items(): for seed in range(8): try: s=building_scene(recipe(seed),seed);print(name,seed,'ok',len(s.blocks),flush=True) except Exception as e:print(name,seed,type(e).__name__,str(e),flush=True) PY
room-0-1-0/stairs at (5, 13, 15): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (6, 12, 15): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (6, 13, 15): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (5, 12, 16): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (5, 13, 16): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (5, 14, 16): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (6, 12, 16): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (6, 13, 16): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (6, 14, 16): Protected player headroom is obstructed commons 7 ValidationError clearance: /building/room-0-1-0/stairs at (7, 12, 16): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (8, 12, 16): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (7, 12, 17): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (7, 13, 17): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (8, 12, 17): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (8, 13, 17): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (7, 12, 18): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (7, 13, 18): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (7, 14, 18): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (8, 12, 18): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (8, 13, 18): Protected player headroom is obstructed clearance: /building/room-0-1-0/stairs at (8, 14, 18): Protected player headroom is obstructed
2105
python - <<'PY' p='hearth/components/interior.py';s=open(p).read().replace("p.block((w-3,0,2),state_of('barrel'","p.block((1,0,d-2),state_of('barrel'"
python - <<'PY' p='hearth/components/interior.py';s=open(p).read().replace("p.block((w-3,0,2),state_of('barrel'","p.block((1,0,d-2),state_of('barrel'");open(p,'w').write(s) p='hearth/programs.py';s=open(p).read().replace("y=ctx.view.elevation(x,z)+1\n p.children.append(Child(f'lamp-","y=ctx.view.elevation(x,z+4)+1\n p.children.append(Child(f'lamp-");open(p,'w').write(s) p='hearth/adapters/site.py';s=open(p).read();s=s.replace("ground=ctx.view.elevation(wx,wz)-ctx.frame.origin[1]\n y=max(ground,self.floor-step+1)","ground=max(ctx.view.elevation(ctx.world((x,0,z))[0],ctx.world((x,0,z))[2])-ctx.frame.origin[1] for x in range(self.center-1,self.center+2))\n y=max(ground,self.floor-step+1)") s=s.replace("(self.center+1,self.floor+2,-self.porch-1))","(self.center+1,max(y for z,y in rows)+3,-self.porch-1))") open(p,'w').write(s) PY python generate.py
Validated 5 buildings, 126240 blocks, 842 components. output.litematic | semantic SHA256 3ae80254bd5650afc21954d3b21e692882b8fd1a437b7f9b8c067b11914c2cab
2204
python - <<'PY' p='hearth/components/interior.py';s=open(p).read().replace('for y in range(i):','for y in range(max(0,i-1),i):');open(p,'w').write(s)
python - <<'PY' p='hearth/components/interior.py';s=open(p).read().replace('for y in range(i):','for y in range(max(0,i-1),i):');open(p,'w').write(s) p='hearth/components/building.py';s=open(p).read().replace(" def validate(self):\n", " @property\n def contact_footprint(self):\n return tuple(sorted(set(self.footprint) | ({(x,z) for x in range(self.bay) for z in range(-3,0)} if self.porch else set())))\n\n def validate(self):\n").replace('survey(ctx,self.design.footprint,self.site_limits)','survey(ctx,self.design.contact_footprint,self.site_limits)').replace("Foundation(self.design.footprint,floor","Foundation(self.design.contact_footprint,floor") open(p,'w').write(s) PY python - <<'PY' from hearth.programs import PROGRAMS,building_scene for name,recipe in PROGRAMS.items(): for seed in range(8): try: s=building_scene(recipe(seed),seed);print(name,seed,'ok',len(s.blocks),flush=True) except Exception as e:print(name,seed,type(e).__name__,str(e),flush=True) PY
dwelling 0 ok 15366 dwelling 1 ok 9049 dwelling 2 ok 15438 dwelling 3 ok 11301 dwelling 4 ok 18976 dwelling 5 ok 18982 dwelling 6 ok 10190 dwelling 7 ok 11314 atelier 0 ok 14043 atelier 1 ok 14230 atelier 2 ok 18884 atelier 3 ok 14084 atelier 4 ok 11936 atelier 5 ok 15084 atelier 6 ok 15377 atelier 7 ok 18414 commons 0 ok 18918 commons 1 ok 19946 commons 2 ok 19356 commons 3 ok 19567 commons 4 ok 18992 commons 5 ok 19010 commons 6 ok 15667 commons 7 ok 19901
2300
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace('from dataclasses import dataclass, field, replace','from dataclasses import datac
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace('from dataclasses import dataclass, field, replace','from dataclasses import dataclass, field, replace, is_dataclass, fields') s=s.replace(' stale: bool = False\n',' stale: bool = False\n bindings: tuple = ()\n') s=s.replace(' self.operations = {}',' self.operations = {}\n self.displaced = {}',1) s=s.replace(' other.operations = copy.deepcopy(self.operations)',' other.operations = copy.deepcopy(self.operations)\n other.displaced = {k:dict(v) for k,v in self.displaced.items()}') s=s.replace('self.nodes[path] = Node(path, cap.name, cap.version, dict(params), frame, scope, contract, parent, complete=complete)','self.nodes[path] = Node(path, cap.name, cap.version, {"construction": describe_inputs(component), "arguments": dict(params)}, frame, scope, contract, parent, complete=complete, bindings=bindings)\n self.displaced[path] = {}') s=s.replace(' if old:\n self.reverse[old.owner].discard(p)',' if old and old.owner != path:\n self.displaced[path].setdefault(p,old)\n if old:\n self.reverse[old.owner].discard(p)',1) s=s.replace(' self.relations.update(plan.relations)',' for source, kind, target in plan.relations:\n if source not in self.nodes or target not in self.nodes:\n raise ContractError("dangling-relation",path,conditions=f"{source} {kind} {target}")\n self.relations.add((source,kind,target))') s=s.replace(' self.nodes.pop(path, None)',' node=self.nodes.get(path)\n if node:\n for binding in node.bindings:\n key=(binding.host,binding.port)\n self.port_uses[key]=max(0,self.port_uses.get(key,0)-1)\n self.nodes.pop(path, None)',1) start=s.index(' affected = set()\n',s.index(' def _remove_branch')) end=s.index(' for d in self.dependencies:',start) s=s[:start]+''' affected = set() for k in sorted(paths,reverse=True): current=set(self.reverse[k]) | set(self.displaced.get(k,{})) for p in current: record=self.blocks.get(p) if record is None or (record.owner not in paths and self.operations[record.operation]['component'] not in paths): continue affected.add(p) self.reverse[record.owner].discard(p) previous=self.displaced.get(k,{}).get(p) if previous and previous.owner in self.nodes and previous.owner not in paths: self.blocks[p]=previous self.reverse[previous.owner].add(p) else: self.blocks.pop(p,None) self.displaced.pop(k,None) ''' +s[end:] # Add bounds and dependency invalidation for writes to existing, completed input users. s=s.replace(' final_writes = {}',' existing_consumers=set(self.nodes)-{path}\n final_writes = {}',1) s=s.replace(' for old in retired:\n',' for dependency in self.dependencies:\n consumer=dependency["consumer"]\n if consumer in existing_consumers and consumer != parent and not path.startswith(consumer+"/") and any(dependency["region"].contains(p) for p in final_writes):\n # Binding consumers remain valid only if their actual invariants hold.\n self.events.append({"kind":"revalidated-input","consumer":consumer,"cause":path,"version":self.version})\n for old in retired:\n') s += '''\n\ndef describe_inputs(value): """Record declared public inputs without concrete-component dispatch.""" if value is None or isinstance(value,(str,int,float,bool)): return value if isinstance(value,(list,tuple)): return [describe_inputs(v) for v in value] if isinstance(value,dict): return {str(k):describe_inputs(v) for k,v in value.items()} if is_dataclass(value): return {'type':type(value).__module__+'.'+type(value).__qualname__,'inputs':{f.name:describe_inputs(getattr(value,f.name)) for f in fields(value)}} if callable(value): return {'program':value.__module__+'.'+value.__qualname__} return {'type':type(value).__module__+'.'+type(value).__qualname__,'inputs':{k:describe_inputs(v) for k,v in vars(value).items() if not k.startswith('_')}} ''' open(p,'w').write(s) p='hearth/kernel/validation.py';s=open(p).read();s=s.replace(" if rule.phase == 'complete' and not final:\n continue", " if rule.phase == 'complete' and not final:\n scope=node;closed=True\n while scope:\n closed=closed and scope.complete\n scope=scene.nodes.get(scope.parent)\n if not closed:\n continue") # NBT validates item inventories rather than retaining unchecked declarations. s=s.replace(" name, props = parse(record.state)"," if record.nbt is not None:\n if record.nbt.get('id') != 'minecraft:'+name_of(record.state):\n diagnostics.append(Diagnostic('block-entity',record.owner,p,'Block entity type mismatches actual block'))\n slots=set()\n for item in record.nbt.get('Items',[]):\n if not 0<=item.get('Slot',-1)<27 or item['Slot'] in slots or not 1<=item.get('count',0)<=64 or not item.get('id','').startswith('minecraft:'):\n diagnostics.append(Diagnostic('inventory',record.owner,p,'Invalid or duplicate inventory slot/item count'))\n slots.add(item.get('Slot'))\n name, props = parse(record.state)") open(p,'w').write(s) p='hearth/persistence.py';s=open(p).read().replace("'events': encode(scene.events)","'displaced': {k:[[list(p),encode(c)] for p,c in sorted(v.items())] for k,v in scene.displaced.items()}, 'events': encode(scene.events)") s=s.replace(" scene.events = decode(data['events'])"," scene.events = decode(data['events'])\n scene.displaced={k:{tuple(p):decode(c) for p,c in v} for k,v in data.get('displaced',{}).items()}") open(p,'w').write(s) PY python -m pytest -q test/test_kernel.py
....... [100%] 7 passed in 0.30s
2407
python - <<'PY' p='hearth/space.py';s=open(p).read().replace(' def expand(self, n: int):',' def intersection(self, other):\n low=tuple(ma
python - <<'PY' p='hearth/space.py';s=open(p).read().replace(' def expand(self, n: int):',' def intersection(self, other):\n low=tuple(max(a,b) for a,b in zip(self.lo,other.lo))\n high=tuple(min(a,b) for a,b in zip(self.hi,other.hi))\n return None if any(a>b for a,b in zip(low,high)) else Box(low,high)\n\n def expand(self, n: int):');open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace("'region': binding.region or port.region, 'reason': binding.verb","'region': binding.region or port.region.intersection(contract.envelope.expand(1)) or contract.envelope, 'reason': binding.verb") # Raise attempts to property-adjust a different block type. s=s.replace(' if old and old.owner != path:\n authorization'," if old and write.preserve_owner and old.state.split('[')[0] != write.state.split('[')[0]:\n raise ContractError('property-update',path,p,'Property adjustment must retain block type')\n if old and old.owner != path:\n authorization",1) open(p,'w').write(s) p='hearth/kernel/validation.py';s=open(p).read();start=s.index(' # Bounded Manhattan attenuation model');end=s.index('\n\n@validator(\'furnishing\')',start) s=s[:start]+''' # Propagate actual sources through transmissive cells, with one unit attenuation. levels={p:LIGHTS[name_of(state(scene,p))] for p in sources} queue=deque(sources) domain=rule.box.expand(1) while queue: p=queue.popleft();level=levels[p]-1 if level<rule.data.get('minimum',1):continue for dx,dy,dz in ((1,0,0),(-1,0,0),(0,1,0),(0,-1,0),(0,0,1),(0,0,-1)): q=(p[0]+dx,p[1]+dy,p[2]+dz) if not domain.contains(q) or levels.get(q,0)>=level:continue material=state(scene,q) if passable(material) or 'glass' in name_of(material) or name_of(material)=='chain': levels[q]=level;queue.append(q) for p in rule.cells: if levels.get(p,0)<rule.data.get('minimum',1): yield fail('lighting',node,p,'Actual source attenuation/occlusion leaves required location dark') ''' +s[end:] open(p,'w').write(s) PY cat > extension_demo/__init__.py <<'EOF' # Independent component package; imports only Hearth's public protocols and components. from dataclasses import dataclass from hearth.kernel import Capability, Contract, Plan, Child, Rule from hearth.space import Box, Frame from hearth.blocks import state_of, slab from hearth.components.interior import Room @dataclass(frozen=True) class Pendant: def capability(self): return Capability('extension.pendant',('light','room-light'),guarantees=('actual light source',)) def negotiate(self,context,parameters): return Contract(Box((0,0,0),(0,1,0)),rules=(Rule('expected',((0,0,0),),data={'names':['ochre_froglight']}),)) def realize(self,context,contract): plan=Plan() plan.block((0,0,0),state_of('ochre_froglight',axis='y')) plan.block((0,1,0),slab('dark_oak')) return plan @dataclass(frozen=True) class ReadingSuite: width: int=11 def capability(self): return Capability('extension.reading-suite',('room','habitable','composite'),guarantees=('lit','furnished','enclosed','reachable')) def negotiate(self,context,parameters): return Contract(Box((-1,0,-1),(self.width,9,self.width))) def realize(self,context,contract): return Plan(children=[Child('reading-room',Room('library',self.width,self.width,light_component=Pendant()))]) EOF cat > examples/inspection.py <<'EOF' # Generate a real glass query, highlight membership, export and repeat after reload. import argparse import json from pathlib import Path from hearth.programs import dwelling, building_scene from hearth.persistence import export_scene, load_scene from hearth.blocks import name_of def demonstrate(seed,output): scene=building_scene(dwelling(seed),seed) point=next(p for p,c in sorted(scene.blocks.items()) if name_of(c.state)=='glass' and 'room-' in c.owner) query=scene.inspect(point) print(json.dumps(query,default=lambda v:sorted(v),indent=2)) print('Exact current component cells:',sorted(scene.cells(query['instance']))) export_scene(scene,output) restored=load_scene(output) assert restored.inspect(point)==query print('Reloaded query identical; world coordinate:',point) return query if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--seed',type=int,default=0);p.add_argument('--output',type=Path,default=Path('samples/inspection.litematic'));a=p.parse_args();demonstrate(a.seed,a.output) EOF cat > examples/building.py <<'EOF' # Run any of the three short room-composition programs with an explicit seed. import argparse from pathlib import Path from hearth.programs import PROGRAMS,building_scene from hearth.persistence import export_scene if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('program',choices=PROGRAMS);p.add_argument('--seed',type=int,default=0);p.add_argument('--output',type=Path,default=Path('samples/building.litematic'));a=p.parse_args() export_scene(building_scene(PROGRAMS[a.program](a.seed),a.seed),a.output) EOF cat > examples/extension.py <<'EOF' # Substitute independent lighting and encapsulate an independently packaged room. import argparse from pathlib import Path from hearth import Scene,Box,Frame from hearth.kernel import Registry from hearth.components.interior import Light from hearth.components.building import Blueprint,RoomSpec from hearth.programs import building_scene from hearth.persistence import export_scene from extension_demo import Pendant,ReadingSuite def build(seed): registry=Registry();registry.register(Light());registry.register(Pendant()) lights=registry.select('room-light') design=Blueprint((RoomSpec(0,0,0,'library'),RoomSpec(0,0,1,'bedroom')),light_component=lights[seed%len(lights)]) return building_scene(design,seed) if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--seed',type=int,default=0);p.add_argument('--output',type=Path,default=Path('samples/extension.litematic'));a=p.parse_args();export_scene(build(a.seed),a.output) EOF python -m pytest -q test/test_kernel.py python generate.py
....... [100%] 7 passed in 0.33s Validated 5 buildings, 126170 blocks, 842 components. output.litematic | semantic SHA256 fef61d94debf4d6f3e85fd047087947182c0a629f3b4e529e2f4c17c69ef5f78
25072
python - <<'PY' p='hearth/adapters/site.py';s=open(p).read();old="ground=max(ctx.view.elevation(ctx.world((x,0,z))[0],ctx.world((x,0,z))[2])-ctx.frame
python - <<'PY' p='hearth/adapters/site.py';s=open(p).read();old="ground=max(ctx.view.elevation(ctx.world((x,0,z))[0],ctx.world((x,0,z))[2])-ctx.frame.origin[1] for x in range(self.center-1,self.center+2))";new="ground=max(max(ctx.view.elevation(ctx.world((x,0,z))[0],ctx.world((x,0,z))[2]), (ctx.view.water(ctx.world((x,0,z))[0],ctx.world((x,0,z))[2]) or -10000)+1)-ctx.frame.origin[1] for x in range(self.center-1,self.center+2))";s=s.replace(old,new);open(p,'w').write(s) PY cat > reports/sampling-policy.json <<'EOF' { "version": 1, "frozen_before_evaluation": true, "adaptation_count": 64, "environment_seeds": [0, 15], "building_seeds": [0, 3], "pairing": "Cartesian product of 16 independent environmental seeds and four independent building seeds. First eight environment seeds are development compositions; last eight use a previously unused field blend and transform.", "satisfiable_domain": {"gradient_per_block": [-0.045, 0.045], "wave_amplitude": [0, 0.8], "radial_amplitude": [0, 0.7], "base": 4, "water_level": [null, 5, 6], "height_clamp": [2, 7], "room_bay": [9, 11], "site_relief_max": 5, "post_height_max": 8, "approach_length_max": 12}, "stress_count": 32, "stress_policy": "Retain every input. Independent expression seed 1000+i, slopes through 0.45, amplitudes through 5, optional high water. No rejection resampling. One locked placement per input. No retries unless explicitly reported by the solver.", "building_corpus": "dwelling, atelier, commons, each seeds 0 through 7", "settlement_corpus": "seeds 0 through 7; additionally 3-building and 6-building boundaries at seed 0", "metrics": ["per-input validated success", "per-candidate acceptance", "diagnostic status", "fill volume", "excavated volume", "contact geometry signature", "principal structure signature", "runtime"], "limitations": "Finite samples, not an exhaustive proof. Material texture and instance identifiers are excluded from principal signatures. All failed inputs are retained. Public access outside a standalone building's offered landing is an enclosing-scope obligation." } EOF cat > hearth/assessment.py <<'EOF' # Reproducible corpus inputs, structural measurements and retained diagnostics. import hashlib import json import time from pathlib import Path from hearth.randomness import Scope from hearth.programs import PROGRAMS,building_scene,settlement_scene from hearth.environment import gradient,wave,radial,constant from hearth.kernel import ContractError,SearchExhausted from hearth.persistence import semantic_digest,export_scene from hearth.blocks import name_of def adaptation_expression(environment_seed): rng=Scope(environment_seed).stream('frozen-environment') # Degenerate coefficients deliberately include exact flat ground. sx=rng.choice((-.045,0,.045));sz=rng.choice((-.035,0,.035));amplitude=rng.choice((0,.4,.8)) expression=gradient(sx,sz,4)+wave(amplitude,.13,.11,rng.random()*6) if environment_seed>=8: mask=radial(8,9,28,.7).transformed(dx=2,dz=-1,scale=1.2) expression=expression.blend(gradient(-sz,sx,4)+wave(.6,.07,.19),mask) else: expression=expression+radial(7,8,22,rng.choice((0,.4,.7))) expression=expression.clamp(2,7) water=rng.choice((None,5,6)) return expression,water def principal_signature(scene): buildings=[] for path,node in sorted(scene.nodes.items()): if node.type!='building.rooms':continue decision=node.contract.decisions # Realized node topology plus occupied envelope per room, normalized to building. rooms=[];roofs=[] for child,part in sorted(scene.nodes.items()): if not child.startswith(path+'/'):continue if part.type.startswith('room.'): origin=node.frame.inverse(part.frame.origin) occupied=scene.cells(child,True) relative=[part.frame.inverse(p) for p in occupied] bounds=[min(p[i] for p in relative) for i in range(3)]+[max(p[i] for p in relative) for i in range(3)] rooms.append([origin[0],origin[1]-decision['floor'],origin[2],part.type,part.contract.decisions['doors'],part.contract.decisions['stair_up'],bounds]) if part.type=='roof.gable': roofs.append([part.contract.decisions['axis'],part.contract.decisions['span'],part.contract.decisions['steep'],len(scene.cells(child,True))]) buildings.append({'rooms':rooms,'roofs':roofs,'porch':decision['porch'],'bay':decision['bay']}) layout=[] for node in scene.nodes.values(): if node.type=='landscape.paths': pts=node.contract.decisions['waypoints'] layout.append({'points':[(p[0],p[-1]) for p in pts],'links':node.contract.decisions['links']}) data={'buildings':buildings,'organization':layout} return hashlib.sha256(json.dumps(data,sort_keys=True,default=list).encode()).hexdigest(),data def contact_metrics(scene): foundations=[n for n in scene.nodes.values() if n.type=='adapter.foundation'] data=[n.contract.decisions for n in foundations] return {'fill':sum(d['fill'] for d in data),'excavation':sum(d['excavation'] for d in data),'strategies':[d['strategy'] for d in data],'signature':hashlib.sha256(json.dumps(data,sort_keys=True).encode()).hexdigest()} def measured(label,recipe,inputs,output=None): start=time.perf_counter() result={'label':label,'inputs':inputs,'attempts':1,'retries':0} try: scene=recipe();scene.finalize() signature,structure=principal_signature(scene) result.update(status='validated',blocks=len(scene.blocks),components=len(scene.nodes),digest=semantic_digest(scene),principal_signature=signature,structure=structure,contact=contact_metrics(scene),accepted_candidates=1) # Hash independently frozen terrain before placement using persisted field input and current unchanged bed cells. if output: export_scene(scene,output);result['artifact']=str(output) except SearchExhausted as exc: result.update(status='budget-exhausted',diagnostic=str(exc),accepted_candidates=0) except (ContractError,ValueError) as exc: result.update(status='incompatible' if isinstance(exc,ContractError) and exc.diagnostic.rule in ('site-relief','support-height','fill-volume','approach-detour') else 'defect',diagnostic=str(exc),accepted_candidates=0) result['seconds']=round(time.perf_counter()-start,4) return result def run_corpus(output:Path,seed=0,artifacts=False): output.mkdir(parents=True,exist_ok=True) rows=[] specs=[] for env in range(16): expression,water=adaptation_expression(env+seed*100) # Freeze the complete sampled environment independently of building seeds. frozen=[[x,z,int(__import__('math').floor(expression(x,z)))] for x in range(-8,35) for z in range(-18,35)] digest=hashlib.sha256(json.dumps([frozen,water],separators=(',',':')).encode()).hexdigest() for build in range(4): specs.append({'environment_seed':env+seed*100,'building_seed':build,'expression':expression.expression(),'water':water,'frozen_environment_digest':digest,'held_out':env>=8}) (output/'adaptation-inputs.json').write_text(json.dumps(specs,indent=2)) for i,spec in enumerate(specs): expression,water=adaptation_expression(spec['environment_seed']);bs=spec['building_seed'] recipe=lambda e=expression,w=water,b=bs:building_scene(PROGRAMS['dwelling'](b),b,e,w) artifact=Path('samples')/f'adaptation-{i:02d}.litematic' if artifacts and i in (0,8,35,60) else None row=measured(f'adaptation-{i:02d}',recipe,spec,artifact);rows.append(row);print(row['label'],row['status'],flush=True) for name,program in PROGRAMS.items(): for bs in range(8): artifact=Path('samples')/f'{name}-{bs}.litematic' if artifacts and bs in (0,1,6) else None row=measured(f'{name}-{bs}',lambda p=program,b=bs:building_scene(p(b),b),{'program':name,'seed':bs},artifact);rows.append(row);print(row['label'],row['status'],flush=True) for bs,count in [(s,None) for s in range(8)]+[(0,3),(0,6)]: label=f'settlement-{bs}-{count or "seeded"}' artifact=Path('samples')/(label+'.litematic') if artifacts and ((bs==1 and count is None) or count in (3,6)) else None row=measured(label,lambda b=bs,c=count:settlement_scene(b,c),{'program':'settlement','seed':bs,'count':count},artifact);rows.append(row);print(label,row['status'],flush=True) for i in range(32): es=1000+seed*100+i;rng=Scope(es).stream('stress') expression=(gradient(rng.choice((0,.12,.28,.45)),rng.choice((0,-.15,.2)),4)+wave(rng.choice((0,2,5)),.13,.17,rng.random()*6)).clamp(-2,20) water=rng.choice((None,5,12));bs=i%8 row=measured(f'stress-{i:02d}',lambda e=expression,w=water,b=bs:building_scene(PROGRAMS['dwelling'](b),b,e,w),{'environment_seed':es,'building_seed':bs,'expression':expression.expression(),'water':water});rows.append(row);print(row['label'],row['status'],flush=True) (output/'results.json').write_text(json.dumps(rows,indent=2)) summary={} for name,subset in [('adaptation',rows[:64]),('buildings',rows[64:88]),('settlements',rows[88:98]),('stress',rows[98:])]: good=[r for r in subset if r['status']=='validated'] summary[name]={'inputs':len(subset),'validated':len(good),'incompatible':sum(r['status']=='incompatible' for r in subset),'defects':sum(r['status']=='defect' for r in subset),'budget_exhausted':sum(r['status']=='budget-exhausted' for r in subset),'candidate_attempts':sum(r['attempts'] for r in subset),'accepted_candidates':sum(r['accepted_candidates'] for r in subset),'retries':sum(r['retries'] for r in subset),'seconds':round(sum(r['seconds'] for r in subset),3),'observed_principal_signatures':len({r['principal_signature'] for r in good}),'observed_contact_signatures':len({r['contact']['signature'] for r in good}),'fill_range':[min((r['contact']['fill'] for r in good),default=0),max((r['contact']['fill'] for r in good),default=0)]} (output/'summary.json').write_text(json.dumps(summary,indent=2)) manifest=[{'artifact':r['artifact'],'inputs':r['inputs'],'digest':r['digest'],'status':r['status']} for r in rows if 'artifact' in r] (Path('samples')/'replay-manifest.json').write_text(json.dumps(manifest,indent=2)) return summary EOF cat > examples/assess.py <<'EOF' # Explicit finite batch output, never an unnoticed unit-test side effect. import argparse import json from pathlib import Path from hearth.assessment import run_corpus if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--seed',type=int,default=0);p.add_argument('--output',type=Path,default=Path('reports/corpus'));p.add_argument('--artifacts',action='store_true');a=p.parse_args() print(json.dumps(run_corpus(a.output,a.seed,a.artifacts),indent=2)) EOF PYTHONPATH=. python examples/assess.py --seed 0 --output reports/corpus --artifacts
ble stress-06 incompatible stress-07 incompatible stress-08 incompatible stress-09 validated stress-10 incompatible stress-11 incompatible stress-12 incompatible stress-13 incompatible stress-14 validated stress-15 incompatible stress-16 incompatible stress-17 validated stress-18 validated stress-19 incompatible stress-20 validated stress-21 incompatible stress-22 validated stress-23 incompatible stress-24 incompatible stress-25 validated stress-26 validated stress-27 incompatible stress-28 incompatible stress-29 incompatible stress-30 incompatible stress-31 incompatible { "adaptation": { "inputs": 64, "validated": 64, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 64, "accepted_candidates": 64, "retries": 0, "seconds": 17.503, "observed_principal_signatures": 3, "observed_contact_signatures": 48, "fill_range": [ 0, 159 ] }, "buildings": { "inputs": 24, "validated": 24, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 24, "accepted_candidates": 24, "retries": 0, "seconds": 10.81, "observed_principal_signatures": 18, "observed_contact_signatures": 24, "fill_range": [ 0, 70 ] }, "settlements": { "inputs": 10, "validated": 10, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 10, "accepted_candidates": 10, "retries": 0, "seconds": 37.462, "observed_principal_signatures": 10, "observed_contact_signatures": 10, "fill_range": [ 49, 205 ] }, "stress": { "inputs": 32, "validated": 9, "incompatible": 23, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 32, "accepted_candidates": 9, "retries": 0, "seconds": 6.377, "observed_principal_signatures": 4, "observed_contact_signatures": 9, "fill_range": [ 40, 174 ] } }
2603
xvfb-run -a /work/generator/MCRender/node_modules/.bin/vite-node --script /opt/tools/render_schematic.mjs -- --input output.litematic --output preview
xvfb-run -a /work/generator/MCRender/node_modules/.bin/vite-node --script /opt/tools/render_schematic.mjs -- --input output.litematic --output previews/settlement-first.png --size 1400 --azimuth 205 --elevation 38 --radius 2.8 --fov 30 --ambient 0.8
parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! Using WebGL2 context for WebGL requests instead of WebGL Loaded structure from /work/generator/workspace/output.litematic in 144 ms Set structure in renderer in 1734 ms Rendering output at azimuth 0 (1/1)... Rendered image in 117 ms (azimuth: 3.5779249665883754, elevation: 0.6632251157578452) wrote /work/generator/workspace/previews/settlement-first.png (1400x1400, azimuth 205, elevation 38)
2711
mkdir -p reports/baseline-corpus && cp reports/corpus/summary.json reports/corpus/results.json reports/corpus/adaptation-inputs.json reports/baseline-
mkdir -p reports/baseline-corpus && cp reports/corpus/summary.json reports/corpus/results.json reports/corpus/adaptation-inputs.json reports/baseline-corpus/ python - <<'PY' p='hearth/components/primitives.py';s=open(p).read().replace("box=Box((0,0,-1),(self.width-1,self.height-1,depth-1))","box=Box((-1,-1,-1),(self.width,self.height-1,depth-1))") old=""" if self.shutters: for x in (0,self.width-1): p.block((x,0,-1),state_of('spruce_trapdoor',facing='north',half='bottom',open='true',powered='false',waterlogged='false'),'shutters') """ new=""" if self.shutters: from hearth.blocks import slab for x in (-1,self.width): for y in range(self.height): p.block((x,y,-1),state_of('spruce_trapdoor',facing='north',half='bottom',open='true',powered='false',waterlogged='false'),'shutters') for x in range(self.width): p.block((x,-1,-1),slab('spruce','top'),'sill') """ s=s.replace(old,new);open(p,'w').write(s) p='hearth/components/roofs.py';s=open(p).read().replace("box=Box((0,0,-1),(self.span-1,height-1,0))","box=Box((0,-1,-1),(self.span-1,height-1,0))");open(p,'w').write(s) p='test/test_kernel.py';s=open(p).read().replace("assert len(s.cells('/house/window'))==6","assert len(s.cells('/house/window'))==10");open(p,'w').write(s) PY cat >> hearth/components/landscape.py <<'EOF' @dataclass(frozen=True) class FacadeGarden: width: int depth: int sides: tuple[str,...] def capability(self): return Capability('facade.garden',('decoration','plant'),adaptations=('avoid facade openings',),guarantees=('unobstructed doorways',)) def negotiate(self,ctx,parameters): return Contract(Box((-1,0,-1),(self.width,3,self.depth))) def realize(self,ctx,contract): p=Plan();w,d=self.width,self.depth frames={'north':Frame((0,0,-1)),'south':Frame((w-1,0,d),2),'east':Frame((w,0,0),1),'west':Frame((-1,0,d-1),3)} for side in self.sides: f=frames[side];length=w if side in ('north','south') else d for y in range(1,4): q=f.point((0,y,0)) if name_of(ctx.view.state(ctx.world(q)))=='air': p.block(q,leaves('oak'),'climber') for x in (2,length-3): q=f.point((x,0,0));above=f.point((x,1,0)) if name_of(ctx.view.state(ctx.world(q)))=='air' and name_of(ctx.view.state(ctx.world(above)))=='air': p.block(q,slab('spruce','top'),'flower-shelf') p.block(above,state_of('potted_poppy' if x==2 else 'potted_fern'),'pot') return p @dataclass(frozen=True) class Well: def capability(self): return Capability('square.well',('amenity','composite'),guarantees=('contained water','grounded cover')) def negotiate(self,ctx,parameters): basin=tuple((x,1,z) for x in range(1,3) for z in range(1,3)) return Contract(Box((-1,0,-1),(4,6,4)),rules=(Rule('support',tuple((x,-1,z) for x in range(4) for z in range(4))),Rule('pool',basin))) def realize(self,ctx,contract): p=Plan();p.fill(Box((0,0,0),(3,1,3)),state_of('stone_bricks'),'basin') p.fill(Box((1,1,1),(2,1,2)),state_of('water',level='0'),'water') for x,z in ((0,0),(3,3)): p.fill(Box((x,2,z),(x,4,z)),log(),'post') for x in range(-1,5): for z in range(-1,5): p.block((x,5 if x in (-1,4) else 6,z),slab('dark_oak'),'shelter') return p @dataclass(frozen=True) class Terrace: width: int=10 depth: int=10 def capability(self): return Capability('site.terrace',('siteworks','composite'),adaptations=('small local fill','retaining border'),guarantees=('level civic amenity pad',)) def negotiate(self,ctx,parameters): heights=[ctx.view.elevation(ctx.world((x,0,z))[0],ctx.world((x,0,z))[2])-ctx.frame.origin[1] for x in range(self.width) for z in range(self.depth)] top=max(heights) if top-min(heights)>3: raise ContractError('terrace-relief',ctx.path,conditions='Small terrace limit is 3') return Contract(Box((0,min(heights),0),(self.width-1,top+8,self.depth-1)),decisions={'height':top}) def realize(self,ctx,contract): p=Plan();top=contract.decisions['height'] for x in range(self.width): for z in range(self.depth): wx,_,wz=ctx.world((x,0,z));bed=ctx.view.elevation(wx,wz)-ctx.frame.origin[1] for y in range(bed,top+1): material='cobblestone' if y<top else ('stone_bricks' if x in (0,self.width-1) or z in (0,self.depth-1) else 'andesite') p.block((x,y,z),state_of(material),'terrace-paving') p.children.append(Child('well',Well(),frame=Frame((3,top+1,3)))) for i,x in enumerate((1,self.width-2)): p.children.append(Child(f'planter-{i}',Planter(2),frame=Frame((x if i==0 else x-1,top+1,1)))) return p EOF python - <<'PY' p='hearth/components/interior.py';s=open(p).read();s=s.replace(" if self.stair_up:\n p.children.append(Child('stairs'", " from .landscape import FacadeGarden\n p.children.append(Child('facade-garden',FacadeGarden(w,d,tuple(s for s in self.windows if s not in self.doors))))\n if self.stair_up:\n p.children.append(Child('stairs'") open(p,'w').write(s) PY python -m pytest -q test/test_kernel.py python generate.py
....... [100%] 7 passed in 0.33s Traceback (most recent call last): File "/work/generator/workspace/generate.py", line 21, in <module> main() File "/work/generator/workspace/generate.py", line 14, in main scene=settlement_scene(args.seed,args.count) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/work/generator/workspace/hearth/programs.py", line 116, in settlement_scene scene.place('village',Settlement(designs,domain,'/land')) File "/work/generator/workspace/hearth/kernel/scene.py", line 111, in place candidate._instantiate(path, component, params or {}, frame, tuple(bindings), None, Scope(self.seed).child(key, seed), complete) File "/work/generator/workspace/hearth/kernel/scene.py", line 241, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 241, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 241, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 207, in _instantiate raise ContractError('write-authority', path, p, f'Owned by {old.owner}; no scoped grant') hearth.kernel.errors.ContractError: write-authority: /village/plot-0/room-0-0-0/window-west-1 at (-20, 8, -5): Owned by /village/plot-0/room-0-0-0/window-west-0; no scoped grant
2810
python - <<'PY' p='hearth/components/landscape.py';s=open(p).read();old="return Contract(Box((0,min(heights),0),(self.width-1,top+8,self.depth-1)),dec
python - <<'PY' p='hearth/components/landscape.py';s=open(p).read();old="return Contract(Box((0,min(heights),0),(self.width-1,top+8,self.depth-1)),decisions={'height':top})";new="region=Box((0,top,0),(self.width-1,top+2,self.depth-1))\n return Contract(Box((0,min(heights),0),(self.width-1,top+8,self.depth-1)),ports=(Port('entrance','public-access',Frame((0,top+1,self.depth//2)),region,10,'paving'),),grants=(Grant('paving',region,('surface',),('path',),32),),decisions={'height':top,'fill':sum(top-h for h in heights),'excavation':0})";s=s.replace(old,new);open(p,'w').write(s) p='hearth/programs.py';s=open(p).read().replace('PathNetwork, Landscape, LampPost','PathNetwork, Landscape, LampPost, Terrace') s=s.replace(" p.children.append(Child('connections',SettlementConnections", " p.children.append(Child('square',Terrace(),frame=Frame((5,0,10)),bindings=(Binding(self.terrain,'construction','fill'),)))\n p.children.append(Child('connections',SettlementConnections") s=s.replace(" return Contract(self.domain,rules=(Rule('route',targets", " targets=targets+(ctx.view.port(parent+'/square','entrance').frame.origin,)\n return Contract(self.domain,rules=(Rule('route',targets") s=s.replace(" p=Plan(children=[Child('paths',PathNetwork", " square=ctx.view.port(parent+'/square','entrance').frame.origin\n points.extend((square,(0,ctx.view.elevation(0,square[2])+1,square[2])))\n links.extend(((len(points)-2,len(points)-1),(1,len(points)-1)))\n bindings.append(Binding(parent+'/square','entrance','surface'))\n p=Plan(children=[Child('paths',PathNetwork") # Do not put a lamp on the civic connector. s=s.replace("sorted({q[-1] for q in points})","sorted({q[-1] for q in points[:self.count*2]})") open(p,'w').write(s) PY python generate.py
Traceback (most recent call last): File "/work/generator/workspace/generate.py", line 21, in <module> main() File "/work/generator/workspace/generate.py", line 14, in main scene=settlement_scene(args.seed,args.count) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/work/generator/workspace/hearth/programs.py", line 122, in settlement_scene scene.place('village',Settlement(designs,domain,'/land')) File "/work/generator/workspace/hearth/kernel/scene.py", line 111, in place candidate._instantiate(path, component, params or {}, frame, tuple(bindings), None, Scope(self.seed).child(key, seed), complete) File "/work/generator/workspace/hearth/kernel/scene.py", line 241, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 241, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 241, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 207, in _instantiate raise ContractError('write-authority', path, p, f'Owned by {old.owner}; no scoped grant') hearth.kernel.errors.ContractError: write-authority: /village/plot-0/room-0-0-0/window-west-1 at (-20, 8, -5): Owned by /village/plot-0/room-0-0-0/window-west-0; no scoped grant
2912
python - <<'PY' p='hearth/components/interior.py';s=open(p).read().replace("bays=(2,length-4) if length>=11 else (1,length-3)","bays=(2,length-4) if l
python - <<'PY' p='hearth/components/interior.py';s=open(p).read().replace("bays=(2,length-4) if length>=11 else (1,length-3)","bays=(2,length-4) if length>=11 else ((1,length-3) if length>=9 else ((length-2)//2,))");open(p,'w').write(s) p='hearth/components/primitives.py';s=open(p).read().replace(" for y in range(3,h+1):\n r=", " for y in range(3,h+1):\n if y%3==0 and y!=h:\n continue\n r=");open(p,'w').write(s) p='hearth/programs.py';s=open(p).read();a=s.index(' recipes=(dwelling,atelier,commons)');b=s.index(' rows=(count+1)//2',a) s=s[:a]+''' designs=[] for i in range(count): local=scope.child(f'building-{i}').stream('room-graph') rooms=[RoomSpec(0,0,0,local.choice(('living','workshop','library')))] for x,z in local.sample(((1,0),(0,1)),local.choice((0,1,2))): rooms.append(RoomSpec(x,z,0,local.choice(('storage','kitchen','living')))) if local.choice((True,True,False)): column=local.choice(rooms) for level in range(1,local.choice((2,2,3))): rooms.append(RoomSpec(column.x,column.z,level,'bedroom' if level==1 else 'library')) designs.append(Blueprint(tuple(rooms),bay=local.choice((9,11)),porch=local.choice((True,True,False)),roof_axis=local.choice(('auto','x','z')),roof_material=local.choice(('deepslate_tile','brick')),steep=local.choice((True,True,False)))) ''' +s[b:] open(p,'w').write(s) PY python generate.py
Traceback (most recent call last): File "/work/generator/workspace/generate.py", line 21, in <module> main() File "/work/generator/workspace/generate.py", line 14, in main scene=settlement_scene(args.seed,args.count) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/work/generator/workspace/hearth/programs.py", line 131, in settlement_scene scene.place('village',Settlement(designs,domain,'/land')) File "/work/generator/workspace/hearth/kernel/scene.py", line 112, in place candidate._check(False) File "/work/generator/workspace/hearth/kernel/scene.py", line 267, in _check raise ValidationError(errors) hearth.kernel.errors.ValidationError: clearance: /village/plot-0/porch at (-15, 8, -1): Protected player headroom is obstructed clearance: /village/plot-0/porch at (-15, 8, 1): Protected player headroom is obstructed clearance: /village/plot-1/porch at (15, 9, -1): Protected player headroom is obstructed clearance: /village/plot-1/porch at (15, 9, -3): Protected player headroom is obstructed clearance: /village/plot-3/porch at (15, 9, 39): Protected player headroom is obstructed clearance: /village/plot-3/porch at (15, 9, 37): Protected player headroom is obstructed
3010
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace(' search: int = 24',' search: int = 24\n instances: int = 10000') s=s.rep
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace(' search: int = 24',' search: int = 24\n instances: int = 10000') s=s.replace(' self.reverse = {}',' self.reverse = {}\n self.reverse_shared = {}',1).replace(' other.reverse = {k: set(v) for k, v in self.reverse.items()}',' other.reverse = {k: set(v) for k, v in self.reverse.items()}\n other.reverse_shared = {k:set(v) for k,v in self.reverse_shared.items()}') s=s.replace(" if len(path.split('/')) > self.limits.depth:"," if len(self.nodes)>=self.limits.instances:\n raise ContractError('instance-budget',path)\n if len(path.split('/')) > self.limits.depth:") s=s.replace("if (frame.origin[0] - port.frame.origin[0]) % port.alignment:","if port.frame.inverse(frame.origin)[0] % port.alignment or frame.turn%4 != port.frame.turn%4:") s=s.replace(' def cells(self, path, descendants=False):',' def cells(self, path, descendants=False, shared=False):').replace(" return frozenset(p for k in paths for p in self.reverse.get(k, ()))"," return frozenset(p for k in paths for p in (self.reverse.get(k,set()) | (self.reverse_shared.get(k,set()) if shared else set())))") s=s.replace(" trial.blocks[p] = replace(record, shared=", " if participant in record.shared:\n return\n use_key=(host,port)\n if trial.port_uses.get(use_key,0)>=offered.capacity:\n raise ContractError('port-capacity',participant,p)\n trial.port_uses[use_key]=trial.port_uses.get(use_key,0)+1\n trial.reverse_shared.setdefault(participant,set()).add(p)\n from .contracts import Rule\n node=trial.nodes[participant]\n node.contract=replace(node.contract,rules=node.contract.rules+(Rule('support',(p,)),))\n trial.blocks[p] = replace(record, shared=",1) s=s.replace(' for k in sorted(paths, reverse=True):\n self.reverse[k].clear()', ' for k in sorted(paths, reverse=True):\n self.reverse_shared.pop(k,None)\n self.reverse[k].clear()') # Reject deletion of an existing shared support through actual support rules. # Loaded scenes can regenerate with an explicitly supplied implementation, safely without importing metadata. s=s.replace(' recipes = {p: trial._recipes[p] for p in targets}'," recipes={}\n for p in targets:\n if p in trial._recipes:\n recipes[p]=trial._recipes[p]\n elif p==path and component is not None:\n n=trial.nodes[p];recipes[p]=(component,n.parameters.get('arguments',{}),n.frame,n.bindings,n.parent,n.scope,n.complete)\n else:\n raise ContractError('replay-implementation',p,conditions='Reloaded branch needs an explicitly supplied component implementation')") open(p,'w').write(s) p='hearth/persistence.py';s=open(p).read().replace(" scene.reverse[owner].add(p)"," scene.reverse[owner].add(p)\n for participant in shared:\n scene.reverse_shared.setdefault(participant,set()).add(p)") open(p,'w').write(s) p='hearth/kernel/validation.py';s=open(p).read().replace(" if record.owner not in scene.nodes:"," if p not in scene.reverse.get(record.owner,set()):\n diagnostics.append(Diagnostic('reverse-index',record.owner,p,'Current cell absent from reverse index'))\n if record.owner not in scene.nodes:") s=s.replace(' for node in scene.nodes.values():'," for owner,points in scene.reverse.items():\n for p in points:\n if p not in scene.blocks or scene.blocks[p].owner!=owner:\n diagnostics.append(Diagnostic('reverse-index',owner,p,'Obsolete current membership'))\n for node in scene.nodes.values():",1) open(p,'w').write(s) PY cat > test/test_contracts_provenance.py <<'EOF' # Mutation, sharing, phases, rotations, extension and synchronized provenance tests. from dataclasses import dataclass,replace import json import pytest from hearth import Scene,Box,Frame,Binding,ContractError from hearth.kernel import Capability,Contract,Grant,Port,Rule,Plan,Child,Limits,SearchExhausted from hearth.blocks import state_of from hearth.components.primitives import Volume,Assembly,Window,Wall,Grass,Tree,Pool from hearth.kernel.scene import Cell from hearth.persistence import export_scene,load_scene,semantic_digest from hearth.randomness import Scope from hearth.composition import encapsulate,repeat,arrange,scatter from extension_demo import Pendant,ReadingSuite @dataclass(frozen=True) class Editable: def capability(self):return Capability('editable',('support',)) def negotiate(self,c,p): b=Box((0,0,0),(0,0,0)) return Contract(b,(Port('edit','adjust',Frame(),b,10,'edit'),Port('shared','shared-support',Frame(),b,4)),(Grant('edit',b,('adjust','excavate'),('editor',),1),)) def realize(self,c,b): p=Plan();p.block((0,0,0),state_of('oak_log',axis='y'));return p @dataclass(frozen=True) class Editor: material: str preserve: bool=True def capability(self):return Capability('editor',('editor',)) def negotiate(self,c,p):return Contract(Box((0,0,0),(0,0,0))) def realize(self,c,b): p=Plan();p.block((0,0,0),self.material,preserve_owner=self.preserve);return p def test_adjustment_membership_history_deletion_and_reload(work): s=Scene();s.place('owner',Editable()) s.place('adjust',Editor(state_of('oak_log',axis='x')),bindings=(Binding('/owner','edit','adjust'),)) q=s.inspect((0,0,0));assert q['instance']=='/owner' and q['operation']['component']=='/adjust' assert s.cells('/adjust')==frozenset() export_scene(s,work/'adjust.litematic');r=load_scene(work/'adjust.litematic');assert r.inspect((0,0,0))==q s.remove('/adjust');assert s.inspect((0,0,0))['state']==state_of('oak_log',axis='y') s.place('erase',Editor(state_of('air'),False),bindings=(Binding('/owner','edit','excavate'),)) assert s.inspect((0,0,0))['instance'] is None and not s.cells('/owner') s.remove('/erase');assert s.cells('/owner')=={(0,0,0)} def test_identical_blocks_do_not_grant_sharing_and_explicit_shared_support(): s=Scene();s.place('support',Editable());s.place('bridge',Assembly('bridge',Box((0,0,0),(2,2,2)),())) with pytest.raises(ContractError,match='write-authority'): s.place('intruder',Volume(Box((0,0,0),(0,0,0)),state_of('oak_log',axis='y'))) s.share((0,0,0),'/bridge','/support','shared') assert s.cells('/bridge',shared=True)=={(0,0,0)} assert ('/bridge','shares_support','/support') in s.inspect((0,0,0))['related'] with pytest.raises(ContractError,match='support'): s.remove('/support') s.remove('/bridge');assert not s.inspect((0,0,0))['shared'] def test_partial_tall_plant_replacement_atomicity(): from hearth.environment import Terrain,constant s=Scene(domain=Box((-2,-2,-2),(4,15,4)));s.place('terrain',Terrain(s.domain,constant(0))) s.place('grass',Grass(True),frame=Frame((0,1,0))) @dataclass class Pruner: def capability(self):return Capability('pruner',('tree',)) def negotiate(self,c,p):return Contract(Box((0,0,0),(0,0,0))) def realize(self,c,b): p=Plan();p.block((0,0,0),state_of('oak_log',axis='y'));return p snapshot=(semantic_digest(s),set(s.nodes),set(s.relations),dict(s.port_uses),list(s.dependencies)) with pytest.raises(ContractError,match='whole-object'): s.place('prune',Pruner(),frame=Frame((0,1,0)),bindings=(Binding('/grass','replacement','plant'),)) assert snapshot==(semantic_digest(s),set(s.nodes),set(s.relations),dict(s.port_uses),list(s.dependencies)) @pytest.mark.parametrize('turn',range(4)) def test_rotated_attachment_ports_claims_membership(turn,work): frame=Frame((-13,5,17),turn) def compose(c): return Plan(children=[Child('wall',Wall(thickness=3)),Child('a',Window(),frame=Frame((2,1,0)),bindings=(Binding(c.path+'/wall','infill'),)),Child('b',Window(shutters=False),frame=Frame((6,1,0)),bindings=(Binding(c.path+'/wall','infill'),))]) s=Scene(31);s.place('house',encapsulate('house',Box((-1,-1,-2),(10,8,4)),compose),frame=frame) a,b=frame.point((2,1,0)),frame.point((6,1,0)) assert s.inspect(a)['instance']!=s.inspect(b)['instance'] assert [n['type'] for n in s.inspect(a)['chain']]==['window.shuttered','wall.framed','house'] assert s.nodes['/house/wall'].contract.ports[0].frame.turn==turn assert all(s.nodes['/house/a'].contract.envelope.contains(p) for p in s.cells('/house/a')) export_scene(s,work/'rotated.litematic');assert load_scene(work/'rotated.litematic').inspect(a)==s.inspect(a) def test_completion_obligation_and_late_decoration(): s=Scene() b=Box((0,0,0),(3,4,3)) s.place('unfinished',Assembly('room',b,(),(Rule('light',((1,1,1),),b,phase='complete'),)),complete=False) with pytest.raises(ContractError):s.finalize() s.place('lamp',Pendant(),frame=Frame((1,2,1))) s.finish_scope('/unfinished');s.finalize() with pytest.raises(ContractError,match='lighting'):s.remove('/lamp') def test_extension_low_level_composite_and_nested_protocol(): s=Scene(4) room=ReadingSuite() wrapper=encapsulate('independent-suite',Box((-2,0,-2),(14,11,14)),lambda c:Plan(children=[Child('suite',room)])) s.place('hall',wrapper);s.finalize() assert any(n.type=='extension.pendant' for n in s.nodes.values()) assert any(n.type=='extension.reading-suite' for n in s.nodes.values()) def test_independent_order_and_failed_alternative_streams(): @dataclass class Seeded: def capability(self):return Capability('seeded',()) def negotiate(self,c,p):return Contract(Box((0,0,0),(2,0,0))) def realize(self,c,b): p=Plan();p.block((c.rng('geometry').randrange(3),0,0),state_of('stone'));return p a,b=Scene(81),Scene(81) for scene,order in ((a,('one','two')),(b,('two','one'))): for key in order:scene.place(key,Seeded(),frame=Frame((10 if key=='two' else 0,0,0))) assert semantic_digest(a)==semantic_digest(b) before=a.cells('/one') with pytest.raises(SearchExhausted): a.choose('failed',[Child('x',Volume(Box((0,0,0),(2,0,0)),state_of('dirt')))]) a.place('planter',Seeded(),frame=Frame((20,0,0))) assert a.cells('/one')==before c=Scene(81);c.place('one',Seeded(),seed=123) assert c.nodes['/one'].scope.seed==123 def test_regeneration_restores_displaced_terrain_and_no_stale_cells(): from hearth.environment import Terrain,constant s=Scene(domain=Box((-2,-3,-2),(12,20,12)));s.place('land',Terrain(s.domain,constant(0))) before=semantic_digest(s) s.place('pool',Pool(),frame=Frame((1,0,1)),bindings=(Binding('/land','construction','excavate'),)) s.remove('/pool');assert semantic_digest(s)==before assert not any('/pool' in (a,c) for a,b,c in s.relations) def test_edit_limits_unknown_space_and_budget(): from hearth.environment import Terrain,constant s=Scene(domain=Box((-3,-3,-3),(12,20,12)));s.place('land',Terrain(s.domain,constant(0),edit_limit=1)) with pytest.raises(ContractError,match='edit-limit'): s.place('pool',Pool(),bindings=(Binding('/land','construction','excavate'),)) with pytest.raises(ContractError,match='unknown-space'):s.view.state((100,1,1)) s=Scene(limits=Limits(blocks=1)) with pytest.raises(ContractError,match='block-budget'):s.place('large',Volume(Box((0,0,0),(3,0,0)),state_of('stone'))) assert not s.nodes and not s.blocks EOF python -m pytest -q test/test_contracts_provenance.py
F........... [100%] =================================== FAILURES =================================== ____________ test_adjustment_membership_history_deletion_and_reload ____________ work = PosixPath('/work/generator/workspace/test/tmp-vuvv0kx3') def test_adjustment_membership_history_deletion_and_reload(work): s=Scene();s.place('owner',Editable()) s.place('adjust',Editor(state_of('oak_log',axis='x')),bindings=(Binding('/owner','edit','adjust'),)) q=s.inspect((0,0,0));assert q['instance']=='/owner' and q['operation']['component']=='/adjust' assert s.cells('/adjust')==frozenset() export_scene(s,work/'adjust.litematic');r=load_scene(work/'adjust.litematic');assert r.inspect((0,0,0))==q s.remove('/adjust');assert s.inspect((0,0,0))['state']==state_of('oak_log',axis='y') s.place('erase',Editor(state_of('air'),False),bindings=(Binding('/owner','edit','excavate'),)) assert s.inspect((0,0,0))['instance'] is None and not s.cells('/owner') > s.remove('/erase');assert s.cells('/owner')=={(0,0,0)} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E assert frozenset() == {(0, 0, 0)} E E Extra items in the right set: E (0, 0, 0) E Use -v to get more diff test/test_contracts_provenance.py:45: AssertionError =========================== short test summary info ============================ FAILED test/test_contracts_provenance.py::test_adjustment_membership_history_deletion_and_reload 1 failed, 11 passed in 0.36s
3107
python - <<'PY' p='hearth/components/roofs.py';s=open(p).read().replace('for y in (1,2,3) for z','for y in (1,2) for z');open(p,'w').write(s) p='heart
python - <<'PY' p='hearth/components/roofs.py';s=open(p).read().replace('for y in (1,2,3) for z','for y in (1,2) for z');open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace(' self.displaced = {}',' self.displaced = {}\n self.erasures = {}',1).replace(' other.displaced = {k:dict(v) for k,v in self.displaced.items()}',' other.displaced = {k:dict(v) for k,v in self.displaced.items()}\n other.erasures = dict(self.erasures)') s=s.replace(" if old and write.preserve_owner", " if old and old.shared and not write.preserve_owner:\n raise ContractError('shared-consumer',path,p,'Shared support requires explicit consumer rebinding')\n if old and write.preserve_owner",1) s=s.replace(" self.blocks.pop(p, None)\n else:"," self.blocks.pop(p, None)\n self.erasures[p]=path\n else:\n self.erasures.pop(p,None)",1) s=s.replace("if record is None or (record.owner not in paths and self.operations[record.operation]['component'] not in paths):\n continue\n affected.add(p)\n self.reverse[record.owner].discard(p)","if record is None and self.erasures.get(p) not in paths:\n continue\n if record is not None and record.owner not in paths and self.operations[record.operation]['component'] not in paths:\n continue\n affected.add(p)\n if record is not None:\n self.reverse[record.owner].discard(p)\n self.erasures.pop(p,None)") open(p,'w').write(s) p='hearth/persistence.py';s=open(p).read().replace("'displaced': {k:","'erasures': [[list(p),owner] for p,owner in sorted(scene.erasures.items())], 'displaced': {k:").replace(" scene.events = decode(data['events'])"," scene.erasures={tuple(p):owner for p,owner in data.get('erasures',[])}\n scene.events = decode(data['events'])") open(p,'w').write(s) PY python -m pytest -q test python generate.py
................... [100%] 19 passed in 0.39s Validated 5 buildings, 125493 blocks, 798 components. output.litematic | semantic SHA256 791602abf9fa1e46e54c666a46e334182baa46a92575336e917a24c493081942
3207
python - <<'PY' p='hearth/kernel/contracts.py';s=open(p).read().replace(' facts: dict = field(default_factory=dict)\n',' facts: dict = field(def
python - <<'PY' p='hearth/kernel/contracts.py';s=open(p).read().replace(' facts: dict = field(default_factory=dict)\n',' facts: dict = field(default_factory=dict)\n delegate: tuple[str,str] | None = None\n',1).replace('p.capacity, p.grant, p.alignment, p.facts) for p in self.ports','p.capacity, p.grant, p.alignment, p.facts, p.delegate) for p in self.ports');open(p,'w').write(s) p='hearth/kernel/view.py';s=open(p).read();marker=' def contract(self, path):';s=s.replace(marker," def resolved_port(self, host, key):\n seen=set()\n while True:\n if (host,key) in seen:\n raise ContractError('port-cycle',host,conditions=key)\n seen.add((host,key))\n port=self.port(host,key)\n if not port.delegate:\n return host,port\n child,key=port.delegate\n host=host+'/'+child\n\n"+marker);open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read();s=s.replace(" host = self.nodes[binding.host]\n port = self.view.port(binding.host, binding.port)"," effective_host,port = self.view.resolved_port(binding.host,binding.port)\n host = self.nodes[effective_host]") s=s.replace(' grants.append((binding, grant))',' grants.append((Binding(effective_host,port.key,binding.verb,binding.region), grant))') s=s.replace(" for source, kind, target in plan.relations:"," for port in contract.ports:\n if port.delegate:\n target,actual=self.view.resolved_port(path,port.key)\n if actual.frame!=port.frame or actual.region!=port.region or actual.kind!=port.kind:\n raise ContractError('forwarded-interface',path,port.frame.origin,'Realized child changed the negotiated public interface')\n self.relations.add((path,'exposes',target))\n for source, kind, target in plan.relations:") open(p,'w').write(s) p='hearth/components/building.py';s=open(p).read();s=s.replace(" return Contract(box,ports=(port,),rules=(route,),decisions=decisions,reads=", " approach=Approach(b//2,floor,3 if self.design.porch else 0,self.site_limits).negotiate(ctx,{})\n access=approach.ports[0]\n street=Port('street',access.kind,access.frame,access.region,access.capacity,facts={'external_connection_required':True},delegate=('approach','street'))\n return Contract(box,ports=(port,street),rules=(route,),decisions=decisions,reads=") open(p,'w').write(s) p='hearth/programs.py';s=open(p).read().replace("f'{parent}/plot-{i}/approach'","f'{parent}/plot-{i}'") open(p,'w').write(s) PY python -m pytest -q test python generate.py
................... [100%] 19 passed in 0.41s Validated 5 buildings, 125493 blocks, 798 components. output.litematic | semantic SHA256 791602abf9fa1e46e54c666a46e334182baa46a92575336e917a24c493081942
33049
python - <<'PY' p='hearth/space.py';s=open(p).read().replace(" if any(a > b", " if any(not isinstance(v,int) for v in (*self.lo,*self.hi
python - <<'PY' p='hearth/space.py';s=open(p).read().replace(" if any(a > b", " if any(not isinstance(v,int) for v in (*self.lo,*self.hi)):\n raise TypeError('Box coordinates must be integers')\n if any(a > b",1) s=s.replace(" def vector(self, p: Pos) -> Pos:"," def __post_init__(self):\n if not isinstance(self.turn,int) or any(not isinstance(v,int) for v in self.origin):\n raise TypeError('Frames use integer coordinates and quarter turns')\n\n def vector(self, p: Pos) -> Pos:") s=s.replace(" if key == 'axis'", " if key in ('shape','orientation') and any(v in dirs for v in value.split('_')):\n from .blocks import SCHEMA\n tokens=[dirs[(dirs.index(v)+self.turn)%4] if v in dirs else v for v in value.split('_')]\n value='_'.join(tokens)\n allowed=SCHEMA[name.removeprefix('minecraft:')][0][key]\n if value not in allowed:\n matches=[candidate for candidate in allowed if sorted(candidate.split('_'))==sorted(tokens)]\n if matches:value=sorted(matches)[0]\n if key == 'axis'") open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace(" candidate = self._fork()\n path = '/' + key.strip('/')", " if not isinstance(key,str) or not key or any(c in key for c in '/#'):\n raise ContractError('instance-key',conditions='Keys must be nonempty and exclude / and #')\n candidate = self._fork()\n path = '/' + key") s=s.replace(" for child in plan.children:\n self._instantiate", " for child in plan.children:\n if not child.key or any(c in child.key for c in '/#'):\n raise ContractError('instance-key',path,conditions=child.key)\n self._instantiate") open(p,'w').write(s) PY cat > test/test_geometry_environment.py <<'EOF' # Actual-geometry damage tests, independent environment sampling and regeneration. from dataclasses import replace,dataclass from pathlib import Path import pytest from hearth import Scene,Box,Frame,Binding,ContractError from hearth.kernel import validate,Capability,Contract,Plan,Port,Grant,Child,Rule from hearth.kernel.scene import Cell from hearth.blocks import state_of,name_of,blockstates_equivalent,validate_state from hearth.environment import Terrain,constant,gradient,wave,radial from hearth.components.building import Building,Blueprint,RoomSpec from hearth.components.primitives import Pool,Volume from hearth.programs import PROGRAMS,building_scene,settlement_scene from hearth.assessment import adaptation_expression,principal_signature from hearth.persistence import export_scene,load_scene,semantic_digest,companion_path,_mcio def damage(scene,p,material=None): scene=scene._fork();old=scene.blocks.get(p) if old: scene.reverse[old.owner].discard(p) scene.blocks.pop(p) if material: owner=old.owner if old else next(n.path for n in scene.nodes.values() if n.type.startswith('room.')) operation=old.operation if old else next(iter(scene.operations)) scene.blocks[p]=Cell(material,owner,operation) scene.reverse[owner].add(p) return scene @pytest.fixture def house(): return building_scene(Blueprint((RoomSpec(0,0,0,'living'),RoomSpec(0,0,1,'bedroom'))),7,gradient(.04,0,4),6) def test_removed_support_blocked_stair_exit_and_paired_door(house): foundation=next(n for n in house.nodes.values() if n.type=='adapter.foundation') p=foundation.contract.rules[0].cells[0] assert 'support' in {d.rule for d in validate(damage(house,p),True)} stair=next(n for n in house.nodes.values() if n.type=='circulation.stair') p=next(r for r in stair.contract.rules if r.kind=='clear').cells[4] assert 'clearance' in {d.rule for d in validate(damage(house,p,state_of('stone')),True)} door=next(p for p,c in house.blocks.items() if 'spruce_door' in c.state and 'half=lower' in c.state) issues=validate(damage(house,door,state_of('stone')),True) assert {'door-pair','reachability'} <= {d.rule for d in issues} assert all(d.component.startswith('/') and d.conditions for d in issues) def test_lights_furniture_seal_and_inventory_are_actual(house): room='/building/room-0-0-0';s=house for p in house.cells(room,True): if name_of(house.blocks[p].state)=='lantern':s=damage(s,p) assert 'lighting' in {d.rule for d in validate(s,True)} glass=next(p for p in house.cells(room,True) if name_of(house.blocks[p].state)=='glass') assert 'enclosure' in {d.rule for d in validate(damage(house,glass),True)} bed=next(p for p,c in house.blocks.items() if name_of(c.state)=='red_bed') assert 'bed-pair' in {d.rule for d in validate(damage(house,bed),True)} barrel=next(p for p,c in house.blocks.items() if c.nbt) s=house._fork();nbt=dict(s.blocks[barrel].nbt);nbt['Items']=[{'Slot':0,'id':'minecraft:bread','count':100}];s.blocks[barrel]=replace(s.blocks[barrel],nbt=nbt) assert 'inventory' in {d.rule for d in validate(s,True)} def test_pool_boundary_damage_and_unsupported_substrate(): s=Scene(domain=Box((-3,-3,-3),(14,20,14)));s.place('land',Terrain(s.domain,constant(0))) s.place('pool',Pool(),bindings=(Binding('/land','construction','excavate'),)) assert 'pool-containment' in {d.rule for d in validate(damage(s,(0,0,2)),True)} def test_nbt_roundtrip_and_real_schematic_mismatch(house,work): path=work/'inventory and spaces.litematic';export_scene(house,path) restored=load_scene(path) assert semantic_digest(restored)==semantic_digest(house) assert {p:c.nbt for p,c in restored.blocks.items() if c.nbt}=={p:c.nbt for p,c in house.blocks.items() if c.nbt} _,_,tag,nbtfile=_mcio();nbt=nbtfile.load_regardless_of_gzipped(filename=path) region=next(iter(nbt['Regions'].values()));region['TileEntities'][0]['Items'][0]['count']=tag.Int(7) nbtfile(nbt).save(path) with pytest.raises(ContractError,match='geometry-mismatch'):load_scene(path) companion_path(path).unlink() with pytest.raises(ContractError,match='untrusted-structure'):load_scene(path) @pytest.mark.parametrize('environment_seed',range(16)) @pytest.mark.parametrize('building_seed',range(4)) def test_64_frozen_independent_pairings(environment_seed,building_seed): field,water=adaptation_expression(environment_seed) domain=Box((-8,-4,-18),(34,64,34));s=Scene(building_seed,domain=domain) s.place('ground',Terrain(domain,field,water)) before={p:c.state for p,c in s.blocks.items()} # An existing protected environmental observation outside all building edits. protected=(32,s.view.elevation(32,32),32) from hearth.components.primitives import Assembly s.place('preserved',Assembly('protected-soil',Box(protected,protected),(),(Rule('expected',(protected,),data={'names':[name_of(s.blocks[protected].state)]}),))) design=PROGRAMS['dwelling'](building_seed) s.place('house',Building(design,'/ground'));s.finalize() assert s.nodes['/house'].contract.decisions['rooms']==[(r.x,r.z,r.level,r.purpose) for r in design.normalized()] allowed=set() for path,old in s.displaced.items(): if path.startswith('/house/'): allowed.update(old) assert all(s.nodes[path].contract.envelope.contains(p) for p in old) assert all(p in allowed or (p in s.blocks and s.blocks[p].state==material) for p,material in before.items()) assert s.blocks[protected].state==before[protected] assert s.nodes['/house/approach'].contract.decisions['rows'] assert all(s.view.supports(p) for p in s.nodes['/house/foundation'].contract.rules[0].cells) def test_environment_implementation_substitution_and_public_forwarding(): @dataclass(frozen=True) class IndependentField: def __call__(self,x,z):return 4+0.01*x-0.01*z def expression(self):return {'polynomial':[4,.01,-.01]} @dataclass(frozen=True) class WrappedEnvironment: domain:Box def capability(self):return Capability('extension.environment',('environment','composite')) def negotiate(self,c,p): ports=tuple(Port(key,key,Frame(self.domain.lo),self.domain,100000,delegate=('strata',key)) for key in ('construction','planting')) return Contract(self.domain,ports=ports) def realize(self,c,b):return Plan(children=[Child('strata',Terrain(self.domain,IndependentField()))]) domain=Box((-8,-4,-18),(30,50,30));s=Scene(2,domain=domain);s.place('world',WrappedEnvironment(domain)) s.place('house',Building(Blueprint((RoomSpec(0,0,0,'living'),)), '/world')) s.finalize();assert s.view.port('/house','street').delegate==('approach','street') assert any(d['source']=='/world' for d in s.dependencies) def test_environment_dependency_regeneration_is_explicit_and_atomic(): domain=Box((-8,-4,-18),(28,55,28));s=Scene(3,domain=domain) s.place('land',Terrain(domain,constant(3))) design=Blueprint((RoomSpec(0,0,0,'living'),RoomSpec(0,0,1,'bedroom'))) s.place('house',Building(design,'/land'));before=semantic_digest(s) with pytest.raises(ContractError):s.regenerate('/land',Terrain(domain,constant(4))) assert semantic_digest(s)==before old_floor=s.nodes['/house'].contract.decisions['floor'] s.regenerate('/land',Terrain(domain,constant(4)),dependents=('/house',)) assert s.nodes['/house'].contract.decisions['floor']==old_floor+1 assert not any(n.stale for n in s.nodes.values()) assert all(p in s.blocks for cells in s.reverse.values() for p in cells) @pytest.mark.parametrize('program',tuple(PROGRAMS)) @pytest.mark.parametrize('seed',range(8)) def test_three_composition_programs(program,seed): s=building_scene(PROGRAMS[program](seed),seed) assert s.completed and any(n.type.startswith('room.') for n in s.nodes.values()) @pytest.mark.parametrize('seed,count',[(i,None) for i in range(8)]+[(0,3),(0,6)]) def test_settlement_corpus_and_boundaries(seed,count): s=settlement_scene(seed,count) assert s.completed buildings=[n for n in s.nodes.values() if n.type=='building.rooms'] assert len(buildings)==count if count else 3<=len(buildings)<=6 route=next(n for n in s.nodes.values() if n.type=='settlement.connections') assert len(route.contract.rules[0].cells)==len(buildings)+1 def test_blockstate_explicit_semantics_and_rotation(): assert blockstates_equivalent('minecraft:oak_log[axis=x]','minecraft:oak_log[axis=x]') assert not blockstates_equivalent('minecraft:oak_log','minecraft:oak_log[axis=y]') assert not blockstates_equivalent('minecraft:oak_log[axis=x]','minecraft:oak_log[axis=z]') assert not blockstates_equivalent('minecraft:oak_log[axis=x]','minecraft:spruce_log[axis=x]') with pytest.raises(ValueError):validate_state('minecraft:stone[facing=north]') for turn in range(4): validate_state(Frame(turn=turn).state('minecraft:rail[shape=north_east,waterlogged=false]')) EOF python -m pytest -q test/test_geometry_environment.py -x
........................................................................ [ 68%] ................................. [100%] 105 passed in 49.29s
3400
cat > hearth/components/constraints.py <<'EOF' # Reusable hard preservation and clearance components. from dataclasses import dataclass from hearth.ke
cat > hearth/components/constraints.py <<'EOF' # Reusable hard preservation and clearance components. from dataclasses import dataclass from hearth.kernel import Capability,Contract,Plan,Rule from hearth.space import Box @dataclass(frozen=True) class Preserve: region: Box def capability(self): return Capability('constraint.preserve',('constraint','protected-region'),guarantees=('immutable existing region',)) def negotiate(self,ctx,parameters): cells=tuple(self.region.cells()) return Contract(self.region,rules=(Rule('protected',cells,self.region,{'states':[ctx.view.state(ctx.world(p)) for p in cells]}),)) def realize(self,ctx,contract): return Plan() EOF python - <<'PY' p='hearth/kernel/view.py';s=open(p).read().replace('from dataclasses import dataclass','from dataclasses import dataclass\nfrom types import MappingProxyType') s=s.replace(' def state(self, p):',' @property\n def style(self):\n return MappingProxyType(self.__scene.style)\n\n def preference(self,name,point):\n if self.domain and not self.domain.contains(point):\n raise ContractError("unknown-space",position=point)\n field=self.__scene.preferences.get(name)\n return None if field is None else field(point[0],point[2])\n\n def state(self, p):') s=s.replace("r.kind == 'clear' and any(box.contains(p) for p in r.cells)","r.kind in ('clear','protected') and any(box.contains(p) for p in r.cells)") open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace('def __init__(self, seed=0, limits=None, domain=None):','def __init__(self, seed=0, limits=None, domain=None, style=None, preferences=None):').replace(' self.seed = seed',' self.seed = seed\n self.style = dict(style or {"timber":"spruce","infill":"minecraft:smooth_sandstone","roof":"deepslate_tile"})\n self.preferences = dict(preferences or {})',1) s=s.replace(" old = self.blocks.get(p)"," for protected_node in self.nodes.values():\n for rule in protected_node.contract.rules:\n if rule.kind=='protected' and rule.box and rule.box.contains(p) and protected_node.path!=path:\n raise ContractError('protected-region',path,p,'Immutable region held by '+protected_node.path)\n old = self.blocks.get(p)",1) # Avoid scanning all component rules per voxel if there are no preservation constraints. s=s.replace(' retired = set()',' protected_rules=[(n.path,r.box) for n in self.nodes.values() for r in n.contract.rules if r.kind=="protected" and r.box]\n retired = set()',1) start=s.index(' for protected_node in self.nodes.values():');end=s.index(' old = self.blocks.get(p)',start) s=s[:start]+" for protector,region in protected_rules:\n if region.contains(p) and protector!=path:\n raise ContractError('protected-region',path,p,'Immutable region held by '+protector)\n"+s[end:] open(p,'w').write(s) p='hearth/kernel/validation.py';s=open(p).read();marker="@validator('support')";s=s.replace(marker,"@validator('protected')\ndef protected(scene,node,rule):\n from hearth.blocks import blockstates_equivalent\n for p,expected in zip(rule.cells,rule.data['states']):\n if not blockstates_equivalent(state(scene,p),expected):\n yield fail('protected-region',node,p,'Preserved geometry changed')\n\n\n"+marker);open(p,'w').write(s) p='hearth/components/primitives.py';s=open(p).read().replace("infill: str = 'minecraft:smooth_sandstone'","infill: str | None = None").replace("p=Plan(); p.fill(contract.envelope,self.infill)","p=Plan(); p.fill(contract.envelope,self.infill or ctx.view.style['infill'])") open(p,'w').write(s) p='hearth/persistence.py';s=open(p).read().replace("'seed': scene.seed, 'domain'","'seed': scene.seed, 'style': scene.style, 'preferences': {k:v.expression() for k,v in scene.preferences.items()}, 'domain'").replace("scene = Scene(data['seed'], decode(data['limits']), decode(data['domain']))","from .environment.fields import from_expression\n scene = Scene(data['seed'], decode(data['limits']), decode(data['domain']), data.get('style'), {k:from_expression(v) for k,v in data.get('preferences',{}).items()})") open(p,'w').write(s) p='hearth/environment/fields.py';s=open(p).read();s+='''\n\ndef from_expression(expression): """Restore only declared field operations, never execute a serialized program.""" return Field(expression['op'],tuple(from_expression(a) if isinstance(a,dict) and 'op' in a else a for a in expression['args'])) ''';open(p,'w').write(s) PY cat > examples/courtyard.py <<'EOF' # New composition written after the core abstractions; no library changes needed. import argparse from pathlib import Path from hearth.components.building import Blueprint,RoomSpec from hearth.programs import building_scene from hearth.randomness import Scope from hearth.persistence import export_scene def build(seed): rng=Scope(seed).stream('courtyard') ring=((0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,1)) functions=('living','library','workshop','storage','kitchen','bedroom','bedroom','storage') rooms=[RoomSpec(x,z,0,purpose) for (x,z),purpose in zip(ring,functions)] for x,z in rng.sample(((0,0),(2,0),(0,2),(2,2)),rng.choice((1,2))): rooms.append(RoomSpec(x,z,1,'bedroom')) return building_scene(Blueprint(tuple(rooms),bay=9,porch=True,roof_axis='auto'),seed) if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--seed',type=int,default=0);p.add_argument('--output',type=Path,default=Path('samples/courtyard.litematic'));a=p.parse_args();export_scene(build(a.seed),a.output) EOF PYTHONPATH=. python examples/courtyard.py --seed 0 python -m pytest -q test/test_contracts_provenance.py test/test_kernel.py
/examples/courtyard.py", line 21, in <module> p=argparse.ArgumentParser();p.add_argument('--seed',type=int,default=0);p.add_argument('--output',type=Path,default=Path('samples/courtyard.litematic'));a=p.parse_args();export_scene(build(a.seed),a.output) ^^^^^^^^^^^^^ File "/work/generator/workspace/examples/courtyard.py", line 17, in build return building_scene(Blueprint(tuple(rooms),bay=9,porch=True,roof_axis='auto'),seed) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/work/generator/workspace/hearth/programs.py", line 52, in building_scene scene.place('building',Building(design,'/land')) File "/work/generator/workspace/hearth/kernel/scene.py", line 120, in place candidate._instantiate(path, component, params or {}, frame, tuple(bindings), None, Scope(self.seed).child(key, seed), complete) File "/work/generator/workspace/hearth/kernel/scene.py", line 262, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 262, in _instantiate self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) File "/work/generator/workspace/hearth/kernel/scene.py", line 224, in _instantiate raise ContractError('write-authority', path, p, f'Owned by {old.owner}; no scoped grant') hearth.kernel.errors.ContractError: write-authority: /building/room-1-2-0/window-north-1 at (17, 8, 17): Owned by /building/room-2-1-0/facade-garden; no scoped grant ................... [100%] 19 passed in 0.44s
35011
python - <<'PY' p='hearth/components/landscape.py';s=open(p).read().replace('q=f.point((0,y,0))','q=f.point((1,y,0))');open(p,'w').write(s) PY cat > e
python - <<'PY' p='hearth/components/landscape.py';s=open(p).read().replace('q=f.point((0,y,0))','q=f.point((1,y,0))');open(p,'w').write(s) PY cat > examples/gallery.py <<'EOF' # A later client composes a public gallery with connected reading and work rooms. import argparse from pathlib import Path from hearth.components.building import Blueprint,RoomSpec from hearth.programs import building_scene from hearth.randomness import Scope from hearth.persistence import export_scene from extension_demo import Pendant def build(seed): rng=Scope(seed).stream('gallery-layout') length=rng.choice((2,3)) rooms=[RoomSpec(0,z,0,'library' if z%2 else 'living') for z in range(length)] rooms.append(RoomSpec(1,length-1,0,'workshop')) rooms.append(RoomSpec(0,length-1,1,'bedroom')) return building_scene(Blueprint(tuple(rooms),bay=9,roof_axis='z',light_component=Pendant()),seed) if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--seed',type=int,default=0);p.add_argument('--output',type=Path,default=Path('samples/gallery.litematic'));a=p.parse_args();export_scene(build(a.seed),a.output) EOF PYTHONPATH=. python examples/courtyard.py --seed 0 PYTHONPATH=. python examples/gallery.py --seed 0 PYTHONPATH=. python examples/extension.py --seed 0 PYTHONPATH=. python examples/inspection.py --seed 0 > reports/inspection.txt python generate.py
Validated 5 buildings, 125471 blocks, 798 components. output.litematic | semantic SHA256 05225d7a0eac7d891be94d4d5e27b561a207ae728b8fc17b123f8c92af77a843
36075
python - <<'PY' p='hearth/kernel/contracts.py';s=open(p).read().replace(" version: str = '1'"," version: str = '1'\n inputs: dict = field(def
python - <<'PY' p='hearth/kernel/contracts.py';s=open(p).read().replace(" version: str = '1'"," version: str = '1'\n inputs: dict = field(default_factory=dict)\n locked: tuple[str,...] = ()",1);open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace(' bindings: tuple = ()\n',' bindings: tuple = ()\n capability: Capability | None = None\n',1).replace('complete=complete, bindings=bindings)','complete=complete, bindings=bindings, capability=cap)') open(p,'w').write(s) p='hearth/kernel/view.py';s=open(p).read().replace('from types import MappingProxyType','from types import MappingProxyType\nimport copy').replace(' return p\n',' return copy.deepcopy(p)\n').replace(' return self.__scene.nodes[path].contract',' return copy.deepcopy(self.__scene.nodes[path].contract)') s=s.replace(' def resolved_port(self, host, key):'," def offers(self,host,kind=None):\n return tuple(copy.deepcopy(p) for p in self.__scene.nodes[host].contract.ports if kind is None or p.kind==kind)\n\n def capability(self,host):\n return copy.deepcopy(self.__scene.nodes[host].capability)\n\n def resolved_port(self, host, key):") open(p,'w').write(s) p='hearth/persistence.py';s=open(p).read().replace('contracts.Binding)}','contracts.Binding, contracts.Capability, contracts.Domain)}');open(p,'w').write(s) p='hearth/space.py';s=open(p).read().replace(" def __post_init__(self):\n if any(not", " def __post_init__(self):\n object.__setattr__(self,'lo',tuple(self.lo));object.__setattr__(self,'hi',tuple(self.hi))\n if any(not",1).replace(" def __post_init__(self):\n if not isinstance(self.turn", " def __post_init__(self):\n object.__setattr__(self,'origin',tuple(self.origin))\n if not isinstance(self.turn",1);open(p,'w').write(s) p='hearth/components/primitives.py';s=open(p).read().replace("guarantees=('frame preserved','sealed infill'))","guarantees=('frame preserved','sealed infill'),inputs={'width':[5,64],'height':[4,12],'thickness':[1,3],'orientations':[0,1,2,3]},locked=('width','height','thickness','infill'))").replace('if w<5 or h<4 or not 1<=t<=3:','if not 5<=w<=64 or not 4<=h<=12 or not 1<=t<=3:') open(p,'w').write(s) p='hearth/components/interior.py';s=open(p).read().replace("adaptations=('facade grid','substitutable windows and lights'))","adaptations=('facade grid','substitutable windows and lights'),inputs={'width':[9,11,13],'depth':[9,11,13],'purpose':['living','bedroom','library','workshop','kitchen','storage']},locked=('purpose','width','depth','doors','stair_up','stair_down'))").replace('if w<9 or d<9:','if w not in (9,11,13) or d not in (9,11,13):') open(p,'w').write(s) p='hearth/components/building.py';s=open(p).read().replace("guarantees=('locked room graph','internal reachability','furnishing','lighting'))","guarantees=('locked room graph','internal reachability','furnishing','lighting'),inputs={'bay':[9,11,13],'room_graph':'connected integer grid with supported levels','relief_limit':self.site_limits.relief,'support_height_limit':self.site_limits.support_height,'orientations':[0,1,2,3]},locked=('design.rooms','design.bay','design.roof_axis','design.porch','frame.x','frame.z'))") open(p,'w').write(s) PY python -m pytest -q test/test_kernel.py test/test_contracts_provenance.py PYTHONPATH=. python examples/assess.py --seed 0 --output reports/corpus --artifacts
le stress-06 incompatible stress-07 incompatible stress-08 incompatible stress-09 validated stress-10 incompatible stress-11 incompatible stress-12 incompatible stress-13 incompatible stress-14 validated stress-15 incompatible stress-16 incompatible stress-17 validated stress-18 validated stress-19 incompatible stress-20 validated stress-21 incompatible stress-22 validated stress-23 incompatible stress-24 incompatible stress-25 validated stress-26 validated stress-27 incompatible stress-28 incompatible stress-29 incompatible stress-30 incompatible stress-31 incompatible { "adaptation": { "inputs": 64, "validated": 64, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 64, "accepted_candidates": 64, "retries": 0, "seconds": 18.558, "observed_principal_signatures": 3, "observed_contact_signatures": 48, "fill_range": [ 0, 159 ] }, "buildings": { "inputs": 24, "validated": 24, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 24, "accepted_candidates": 24, "retries": 0, "seconds": 11.397, "observed_principal_signatures": 18, "observed_contact_signatures": 24, "fill_range": [ 0, 70 ] }, "settlements": { "inputs": 10, "validated": 10, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 10, "accepted_candidates": 10, "retries": 0, "seconds": 37.715, "observed_principal_signatures": 10, "observed_contact_signatures": 10, "fill_range": [ 19, 173 ] }, "stress": { "inputs": 32, "validated": 9, "incompatible": 23, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 32, "accepted_candidates": 9, "retries": 0, "seconds": 6.856, "observed_principal_signatures": 4, "observed_contact_signatures": 9, "fill_range": [ 40, 174 ] } }
3709
python - <<'PY' p='hearth/kernel/contracts.py';s=open(p).read();i=s.index('\n\n@dataclass\nclass Plan:');s=s[:i]+'''\n\n@dataclass(frozen=True) class
python - <<'PY' p='hearth/kernel/contracts.py';s=open(p).read();i=s.index('\n\n@dataclass\nclass Plan:');s=s[:i]+'''\n\n@dataclass(frozen=True) class Choice: key: str candidates: tuple[Child,...] score: Any tolerance: float = 0.5 ''' +s[i:];open(p,'w').write(s) p='hearth/kernel/__init__.py';s=open(p).read().replace('Binding, Capability, Child, Component','Binding, Capability, Child, Choice, Component');open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace('Capability, Child, Contract, Plan','Capability, Child, Choice, Contract, Plan') s=s.replace('complete=complete, bindings=bindings, capability=cap)','complete=False, bindings=bindings, capability=cap)') s=s.replace(' for child in plan.children:\n if not child.key'," for child in plan.children:\n if isinstance(child,Choice):\n self._select_child(path,child,frame,scope)\n continue\n if not child.key") s=s.replace(' if len(self.blocks) > self.limits.blocks:', ' self.nodes[path].complete=complete\n if len(self.blocks) > self.limits.blocks:') s=s.replace(' def _check(self, final):\n errors = validate(self, final)',' def _check(self, final, completed_scope=None):\n errors = validate(self, final, completed_scope)') idx=s.index(' def _retire(self, path):') s=s[:idx]+''' def _select_child(self,parent,choice,frame,scope): accepted=[];rejected=[] path=parent+'/'+choice.key for i,option in enumerate(choice.candidates[:self.limits.search]): trial=self._fork() try: trial._instantiate(path,option.component,option.params,frame.compose(option.frame),option.bindings,parent,scope.child(choice.key,option.seed).child(f'alternative-{i}')) trial._check(False,completed_scope=path) accepted.append((choice.score(trial.view,path),i,trial)) except ContractError as exc: rejected.append(exc.diagnostic) if not accepted: rules={d.rule for d in rejected} if len(rules)==1 and len(choice.candidates)<=self.limits.search: raise ContractError(next(iter(rules)),path,conditions='All declared alternatives violate the same condition: '+str(rejected[0])) raise SearchExhausted('search-budget',path,conditions=str(rejected)) accepted.sort(key=lambda item:(item[0],item[1])) feasible=[a for a in accepted if a[0]<=accepted[0][0]+choice.tolerance] chosen=scope.child(choice.key).choose(feasible,'adaptation-selection') self.__dict__.update(chosen[2].__dict__) self.events.append({'kind':'candidate-selection','component':path,'attempts':len(accepted)+len(rejected),'accepted':len(accepted),'rejected':[d.__dict__ for d in rejected],'scores':[(a[1],round(a[0],4)) for a in accepted],'chosen':chosen[1]}) ''' +s[idx:];open(p,'w').write(s) p='hearth/kernel/validation.py';s=open(p).read().replace('def validate(scene, final=False):','def validate(scene, final=False, completed_scope=None):').replace(" if not closed:\n continue"," if completed_scope and (node.path==completed_scope or node.path.startswith(completed_scope+'/')):\n closed=node.complete\n if not closed:\n continue") open(p,'w').write(s) p='hearth/kernel/view.py';s=open(p).read();idx=s.index(' def offers(self,host,kind=None):');s=s[:idx]+''' def cost(self,path,tag=None): paths=[key for key,n in self.__scene.nodes.items() if (key==path or key.startswith(path+'/')) and (tag is None or (n.capability and tag in n.capability.tags))] occupied=sum(len(self.__scene.reverse.get(key,())) for key in paths) replaced=sum(len(self.__scene.displaced.get(key,())) for key in paths) return {'occupied':occupied,'replaced':replaced,'instances':len(paths)} ''' +s[idx:];open(p,'w').write(s) p='hearth/components/building.py';s=open(p).read().replace('Plan, Child, Binding','Plan, Child, Choice, Binding').replace(' site_limits: SiteLimits=SiteLimits()',' site_limits: SiteLimits=SiteLimits()\n support_strategy: str | None=None',1) s=s.replace(" floor=measured['floor'];height=", " if self.support_strategy is not None:\n if self.support_strategy not in measured['feasible_strategies']:\n raise ContractError('contact-strategy',ctx.path,ctx.frame.origin,'Requested strategy incompatible with measured water/relief')\n measured['strategy']=self.support_strategy\n floor=measured['floor'];height=") s+='''\n\ndef contact_quality(view,path): """Score actual candidate sitework plus exposed-support proportions.""" facts=view.contract(path).decisions cost=view.cost(path,'siteworks') exposure=0.4 if facts['foundation']=='piers' and not facts['wet'] and facts['relief']<2 else 0 return cost['occupied']/100+cost['replaced']/50+exposure def adapted(key,design,terrain,frame=Frame(),limits=SiteLimits()): """Compare complete bounded support alternatives with the principal design locked.""" candidates=tuple(Child(key,Building(design,terrain,limits,strategy),frame=frame) for strategy in ('stepped','piers')) return Choice(key,candidates,contact_quality) ''';open(p,'w').write(s) p='hearth/adapters/site.py';s=open(p).read().replace("'strategy':strategy,'samples':samples","'strategy':strategy,'samples':samples,'feasible_strategies':strategies");open(p,'w').write(s) p='hearth/programs.py';s=open(p).read().replace('Blueprint, Building, RoomSpec','Blueprint, Building, RoomSpec, adapted') s=s.replace(" scene.place('building',Building(design,'/land'))", " # Encapsulation preserves the public building instance as the selected child.\n choice=adapted('building',design,'/land')\n scene._select_child('',choice,Frame(),Scope(seed))\n scene.version+=1") # Replace private entry call with public operation below. s=s.replace(" scene._select_child('',choice,Frame(),Scope(seed))\n scene.version+=1", " scene.compose_choice(choice)") s=s.replace("p.children.append(Child(f'plot-{i}',Building(design,self.terrain),frame=Frame(origin,1 if left else 3)))","p.children.append(adapted(f'plot-{i}',design,self.terrain,Frame(origin,1 if left else 3)))") open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read();idx=s.index(' def choose(self, key, candidates, score=');s=s[:idx]+''' def compose_choice(self,choice): trial=self._fork() trial._select_child('',choice,Frame(),Scope(self.seed)) trial._check(False) self._commit(trial) return '/'+choice.key ''' +s[idx:] # Root selection uses no structural parent, preserving a real root rather than a fake wrapper. s=s.replace("frame.compose(option.frame),option.bindings,parent,scope.child", "frame.compose(option.frame),option.bindings,parent or None,scope.child") open(p,'w').write(s) p='hearth/assessment.py';s=open(p).read().replace("result.update(status='validated',blocks=", "choices=[e for e in scene.events if e['kind']=='candidate-selection']\n if choices:\n result['attempts']=sum(e['attempts'] for e in choices)\n result.update(status='validated',blocks=").replace("contact=contact_metrics(scene),accepted_candidates=1)","contact=contact_metrics(scene),accepted_candidates=sum(e['accepted'] for e in choices) if choices else 1,candidates=choices)") open(p,'w').write(s) PY python -m pytest -q test/test_kernel.py test/test_contracts_provenance.py python generate.py
................... [100%] 19 passed in 0.39s Validated 5 buildings, 125489 blocks, 798 components. output.litematic | semantic SHA256 2274ed34636b51d847d7f8424eb42673409747fd9d3cdfc71747a0dbc92402cf
38070
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read();old=""" if len(rules)==1 and len(choice.candidates)<=self.limits.search:
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read();old=""" if len(rules)==1 and len(choice.candidates)<=self.limits.search: raise ContractError(next(iter(rules)),path,conditions='All declared alternatives violate the same condition: '+str(rejected[0])) raise SearchExhausted('search-budget',path,conditions=str(rejected))""";new=""" if len(rules)==1 and len(choice.candidates)<=self.limits.search: error=ContractError(next(iter(rules)),path,conditions='All declared alternatives violate the same condition: '+str(rejected[0])) else: error=SearchExhausted('search-budget',path,conditions=str(rejected)) error.attempts=len(rejected) error.candidates=[d.__dict__ for d in rejected] raise error""";s=s.replace(old,new);open(p,'w').write(s) p='hearth/assessment.py';s=open(p).read().replace("result.update(status='budget-exhausted',diagnostic=str(exc),accepted_candidates=0)","result.update(status='budget-exhausted',diagnostic=str(exc),accepted_candidates=0,attempts=getattr(exc,'attempts',1),candidates=getattr(exc,'candidates',[]))").replace("diagnostic=str(exc),accepted_candidates=0)","diagnostic=str(exc),accepted_candidates=0,attempts=getattr(exc,'attempts',1),candidates=getattr(exc,'candidates',[]))") open(p,'w').write(s) PY python -m pytest -q test
........................................................................ [ 58%] .................................................... [100%] 124 passed in 70.42s (0:01:10)
3910
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace(' self.relations = set()',' self.relations = set()\n self.mem
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace(' self.relations = set()',' self.relations = set()\n self.members = {}',1).replace(' other.relations = set(self.relations)',' other.relations = set(self.relations)\n other.members={k:set(v) for k,v in self.members.items()}') s=s.replace(" self.relations.add((path, 'contained_by', parent))", " self.relations.add((path, 'contained_by', parent))\n self.members.setdefault(parent,set()).add(path)") s=s.replace(" if kind == 'attached_to' and self.nodes[path].primary is None:"," if kind=='attached_to':\n self.members.setdefault(binding.host,set()).add(path)\n if kind == 'attached_to' and self.nodes[path].primary is None:") s=s.replace(' self.nodes.pop(path, None)',' self.members.pop(path,None)\n for children in self.members.values():children.discard(path)\n self.nodes.pop(path, None)',1) s=s.replace(" if descendants:\n paths = [k for k in self.nodes if k == path or k.startswith(path + '/')] ", " if descendants:\n paths=list(self.descendants(path))\n") # Append method before cells. idx=s.index(' def cells(self, path, descendants=False, shared=False):');s=s[:idx]+''' def descendants(self,path): result=set();pending=[path] while pending: current=pending.pop() if current in result:continue result.add(current);pending.extend(sorted(self.members.get(current,()))) return frozenset(result) ''' +s[idx:] s=s.replace('def regenerate(self, path, component=None, params=None, dependents=()):','def regenerate(self, path, component=None, params=None, dependents=(), seed=None):') s=s.replace(" comp, oldparams, frame, bindings, parent, scope, complete = recipes[p]\n trial._instantiate", " comp, oldparams, frame, bindings, parent, scope, complete = recipes[p]\n if p==path and seed is not None:scope=scope.child('override',seed)\n trial._instantiate") open(p,'w').write(s) p='hearth/kernel/validation.py';s=open(p).read().replace(" for node in scene.nodes.values():\n if final", " for node in scene.nodes.values():\n for parent in (node.parent,node.primary):\n if parent is not None and parent not in scene.nodes:\n diagnostics.append(Diagnostic('structure-graph',node.path,None,'Current structural parent missing: '+parent))\n if final") open(p,'w').write(s) p='hearth/persistence.py';s=open(p).read().replace(" scene.relations = decode(data['relations'])", " scene.relations = decode(data['relations'])\n for child,kind,parent in scene.relations:\n if kind in ('contained_by','attached_to'):\n scene.members.setdefault(parent,set()).add(child)") open(p,'w').write(s) PY cat >> test/test_contracts_provenance.py <<'EOF' def test_attachment_membership_across_encapsulation_boundaries(): s=Scene();s.place('house',Assembly('house',Box((-2,0,-2),(12,8,5)),(Child('wall',Wall()),))) s.place('facade-window',Window(),frame=Frame((3,1,0)),bindings=(Binding('/house/wall','infill'),)) assert s.cells('/facade-window') <= s.cells('/house/wall',descendants=True) assert s.cells('/facade-window') <= s.cells('/house',descendants=True) assert s.inspect((3,1,0))['chain'][-1]['id']=='/house' with pytest.raises(ContractError):s.remove('/house') s.regenerate('/house',dependents=('/facade-window',)) assert s.inspect((3,1,0))['instance']=='/facade-window' def test_public_readonly_contracts_and_protected_preference(): from hearth.components.constraints import Preserve from hearth.environment import Terrain,constant s=Scene(domain=Box((-3,-3,-3),(12,20,12)),preferences={'planting':constant(100)}) s.place('land',Terrain(s.domain,constant(0))) s.place('reserve',Preserve(Box((1,-2,1),(3,1,3)))) assert s.view.preference('planting',(2,0,2))==100 with pytest.raises(ContractError,match='protected-region'): s.place('pool',Pool(),bindings=(Binding('/land','construction','excavate'),)) original=s.nodes['/land'].contract.decisions['water'] public=s.view.contract('/land');public.decisions['water']=99 assert s.nodes['/land'].contract.decisions['water']==original def test_explicit_candidate_budget_exhaustion(): from hearth.kernel import Choice s=Scene(limits=Limits(search=1));s.place('occupied',Volume(Box((0,0,0),(0,0,0)),state_of('stone'))) choice=Choice('choice',(Child('bad',Volume(Box((0,0,0),(0,0,0)),state_of('dirt'))),Child('valid',Volume(Box((3,0,0),(3,0,0)),state_of('stone')))),lambda view,path:0) with pytest.raises(SearchExhausted,match='search-budget'):s.compose_choice(choice) assert '/choice' not in s.nodes s.limits=replace(s.limits,search=2);s.compose_choice(choice) assert s.cells('/choice')=={(3,0,0)} EOF python -m pytest -q test/test_contracts_provenance.py test/test_kernel.py
............F......... [100%] =================================== FAILURES =================================== __________ test_attachment_membership_across_encapsulation_boundaries __________ def test_attachment_membership_across_encapsulation_boundaries(): s=Scene();s.place('house',Assembly('house',Box((-2,0,-2),(12,8,5)),(Child('wall',Wall()),))) s.place('facade-window',Window(),frame=Frame((3,1,0)),bindings=(Binding('/house/wall','infill'),)) > assert s.cells('/facade-window') <= s.cells('/house/wall',descendants=True) E AssertionError: assert frozenset({(2... 0, -1), ...}) <= frozenset({(0..., 0, 0), ...}) E E Extra items in the left set: E (4, 0, -1) E (3, 0, -1) E (3, 1, 0) E (5, 1, -1) E (5, 2, -1)... E E ...Full output truncated (5 lines hidden), use '-vv' to show test/test_contracts_provenance.py:152: AssertionError =========================== short test summary info ============================ FAILED test/test_contracts_provenance.py::test_attachment_membership_across_encapsulation_boundaries 1 failed, 21 passed in 0.44s
4000
python - <<'PY' p='hearth/kernel/scene.py' s=open(p).read() s=s.replace(' self.relations = set()',' self.relations = set()\n self
python - <<'PY' p='hearth/kernel/scene.py' s=open(p).read() s=s.replace(' self.relations = set()',' self.relations = set()\n self.members = {}',1) s=s.replace(' other.relations = set(self.relations)',' other.relations = set(self.relations)\n other.members={k:set(v) for k,v in self.members.items()}') s=s.replace(" self.relations.add((path, 'contained_by', parent))", " self.relations.add((path, 'contained_by', parent))\n self.members.setdefault(parent,set()).add(path)") s=s.replace(" if kind == 'attached_to' and self.nodes[path].primary is None:"," if kind=='attached_to':\n self.members.setdefault(binding.host,set()).add(path)\n if kind == 'attached_to' and self.nodes[path].primary is None:") s=s.replace(' self.nodes.pop(path, None)',' self.members.pop(path,None)\n for children in self.members.values():children.discard(path)\n self.nodes.pop(path, None)',1) s=s.replace(" if descendants:\n paths = [k for k in self.nodes if k == path or k.startswith(path + '/')]", " if descendants:\n paths=list(self.descendants(path))") idx=s.index(' def cells(self, path, descendants=False, shared=False):') s=s[:idx]+''' def descendants(self,path): result=set();pending=[path] while pending: current=pending.pop() if current in result:continue result.add(current);pending.extend(sorted(self.members.get(current,()))) return frozenset(result) ''' +s[idx:] s=s.replace('def regenerate(self, path, component=None, params=None, dependents=()):','def regenerate(self, path, component=None, params=None, dependents=(), seed=None):') s=s.replace(" comp, oldparams, frame, bindings, parent, scope, complete = recipes[p]\n trial._instantiate", " comp, oldparams, frame, bindings, parent, scope, complete = recipes[p]\n if p==path and seed is not None:scope=scope.child('override',seed)\n trial._instantiate") open(p,'w').write(s) p='hearth/kernel/validation.py' s=open(p).read().replace(" for node in scene.nodes.values():\n if final", " for node in scene.nodes.values():\n for parent in (node.parent,node.primary):\n if parent is not None and parent not in scene.nodes:\n diagnostics.append(Diagnostic('structure-graph',node.path,None,'Current structural parent missing: '+parent))\n if final") open(p,'w').write(s) p='hearth/persistence.py' s=open(p).read().replace(" scene.relations = decode(data['relations'])", " scene.relations = decode(data['relations'])\n for child,kind,parent in scene.relations:\n if kind in ('contained_by','attached_to'):\n scene.members.setdefault(parent,set()).add(child)") open(p,'w').write(s) PY python -m pytest -q test/test_contracts_provenance.py test/test_kernel.py
...................... [100%] 22 passed in 0.46s
41045
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read();idx=s.index(' def _commit(self, candidate):');s=s[:idx]+''' def fork(self,seed=None)
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read();idx=s.index(' def _commit(self, candidate):');s=s[:idx]+''' def fork(self,seed=None): """Copy a frozen composition; an optional seed controls future placements only.""" result=self._fork() if seed is not None: if not isinstance(seed,int):raise TypeError('Seed must be an integer') result.seed=seed return result ''' +s[idx:];open(p,'w').write(s) p='hearth/programs.py';s=open(p).read().replace("decisions={'buildings':len(self.designs),'arrangement':'opposed street with staggered frontage'}","decisions={'buildings':len(self.designs),'arrangement':'opposed street with staggered frontage','circulation':ctx.scope.choose(('spine','loop'),'circulation')}") s=s.replace('SettlementConnections(len(self.designs),self.domain,self.terrain)','SettlementConnections(len(self.designs),self.domain,self.terrain,contract.decisions[\'circulation\'])') s=s.replace('def __init__(self,count,domain,terrain):\n self.count=count;self.domain=domain;self.terrain=terrain','def __init__(self,count,domain,terrain,mode=\'spine\'):\n self.count=count;self.domain=domain;self.terrain=terrain;self.mode=mode') s=s.replace("points.extend(((x,y,z),(0,ctx.view.elevation(0,z)+1,z)))", "lane=(-3 if x<0 else 3) if self.mode=='loop' else 0\n points.extend(((x,y,z),(lane,ctx.view.elevation(lane,z)+1,z)))") s=s.replace(' if i:links.append((2*i-1,2*i+1))',' if i and self.mode==\'spine\':links.append((2*i-1,2*i+1))') s=s.replace(" square=ctx.view.port(parent+'/square','entrance').frame.origin", " if self.mode=='loop':\n low=min(q[2] for q in points);high=max(q[2] for q in points)\n base=len(points)\n for x,z in ((-3,low),(-3,high),(3,high),(3,low)):\n points.append((x,ctx.view.elevation(x,z)+1,z))\n links.extend((base+i,base+(i+1)%4) for i in range(4))\n square=ctx.view.port(parent+'/square','entrance').frame.origin") s=s.replace("points.extend((square,(0,ctx.view.elevation(0,square[2])+1,square[2])))\n links.extend(((len(points)-2,len(points)-1),(1,len(points)-1)))", "lane=3 if self.mode=='loop' else 0\n points.extend((square,(lane,ctx.view.elevation(lane,square[2])+1,square[2])))\n links.append((len(points)-2,len(points)-1))\n if self.mode=='spine':links.append((1,len(points)-1))") open(p,'w').write(s) p='hearth/assessment.py';s=open(p).read().replace('from hearth.programs import PROGRAMS,building_scene,settlement_scene','from hearth.programs import PROGRAMS,building_scene,settlement_scene\nfrom hearth import Scene,Box\nfrom hearth.environment import Terrain\nfrom hearth.components.building import adapted') idx=s.index('\ndef principal_signature(scene):');s=s[:idx]+'''\ndef freeze_environment(seed): expression,water=adaptation_expression(seed) scene=Scene(seed,domain=Box((-8,-4,-18),(34,64,34))) scene.place('land',Terrain(scene.domain,expression,water)) return scene.finalize() def adapt_frozen(environment,design,building_seed): scene=environment.fork(seed=building_seed) scene.compose_choice(adapted('building',design,'/land')) return scene.finalize() ''' +s[idx:] s=s.replace(' specs=[]\n for env in range(16):',' specs=[];environments={}\n for env in range(16):') a=s.index(' # Freeze the complete sampled environment independently');b=s.index(' for build in range(4):',a) s=s[:a]+" frozen=freeze_environment(env+seed*100)\n environments[env+seed*100]=frozen\n digest=semantic_digest(frozen)\n"+s[b:] s=s.replace("'frozen_environment_digest':digest,'held_out'","'frozen_environment_digest':digest,'environment_domain':[list(frozen.domain.lo),list(frozen.domain.hi)],'held_out'") s=s.replace("recipe=lambda e=expression,w=water,b=bs:building_scene(PROGRAMS['dwelling'](b),b,e,w)","recipe=lambda e=environments[spec['environment_seed']],b=bs:adapt_frozen(e,PROGRAMS['dwelling'](b),b)") s=s.replace("row=measured(f'adaptation-{i:02d}',recipe,spec,artifact);rows.append(row)","row=measured(f'adaptation-{i:02d}',recipe,spec,artifact)\n if semantic_digest(environments[spec['environment_seed']])!=spec['frozen_environment_digest']:raise AssertionError('Frozen environment mutated')\n rows.append(row)") open(p,'w').write(s) PY python generate.py python -m pytest -q test/test_geometry_environment.py -k 'settl'
Validated 5 buildings, 125474 blocks, 783 components. output.litematic | semantic SHA256 9d6ea1207afd7fb6ef179212c891e3ff5ee77e53856fc1cb2e9179ff2328f3be .......... [100%] 10 passed, 95 deselected in 36.61s
4200
wc -l hearth/kernel/*.py hearth/components/*.py hearth/adapters/*.py hearth/environment/*.py hearth/*.py examples/*.py test/*.py && sed -n '1,250p' he
wc -l hearth/kernel/*.py hearth/components/*.py hearth/adapters/*.py hearth/environment/*.py hearth/*.py examples/*.py test/*.py && sed -n '1,250p' hearth/programs.py
Network(tuple(points), tuple(links)), bindings=tuple(bindings))]) for i in range(self.count): p.relations.append((ctx.path + '/paths', 'connects', f'{parent}/plot-{i}')) for i, z in enumerate(sorted({q[-1] for q in points[:self.count * 2]})): x = 5 if i % 2 else -5 y = ctx.view.elevation(x, z + 4) + 1 p.children.append(Child(f'lamp-{i}', LampPost(), frame=Frame((x, y, z + 4)))) return p def settlement_scene(seed=0, count=None): scope = Scope(seed) rng = scope.stream('settlement-layout') if count is None: count = rng.choice((3, 4, 5)) if count < 1: raise ValueError('A settlement needs at least one building') designs = [] for i in range(count): local = scope.child(f'building-{i}').stream('room-graph') rooms = [RoomSpec(0, 0, 0, local.choice(('living', 'workshop', 'library')))] for x, z in local.sample(((1, 0), (0, 1)), local.choice((0, 1, 2))): rooms.append(RoomSpec(x, z, 0, local.choice(('storage', 'kitchen', 'living')))) if local.choice((True, True, False)): column = local.choice(rooms) for level in range(1, local.choice((2, 2, 3))): rooms.append(RoomSpec(column.x, column.z, level, 'bedroom' if level == 1 else 'library')) designs.append(Blueprint(tuple(rooms), bay=local.choice((9, 11)), porch=local.choice((True, True, False)), roof_axis=local.choice(('auto', 'x', 'z')), roof_material=local.choice(('deepslate_tile', 'brick')), steep=local.choice((True, True, False)))) rows = (count + 1) // 2 domain = Box((-49, -4, -23), (49, 64, (rows - 1) * 38 + 28)) field = gradient(.012, -.009, 4.8) + wave(.7, .075, .09, rng.random() * 6) + radial(-36, rows * 12, 26, 1.1) scene = Scene(seed, domain=domain) scene.place('land', Terrain(domain, field, edit_limit=20000)) scene.place('village', Settlement(designs, domain, '/land')) return scene.finalize()
4300
cat /work/generator/MCIO/pyproject.toml && sed -n '1,110p' hearth/assessment.py && du -h output.litematic output.litematic.structure.json
cat /work/generator/MCIO/pyproject.toml && sed -n '1,110p' hearth/assessment.py && du -h output.litematic output.litematic.structure.json
cavation'] for d in data), 'strategies': [d['strategy'] for d in data], 'signature': hashlib.sha256(json.dumps(data, sort_keys=True).encode()).hexdigest()} def measured(label, recipe, inputs, output=None): start = time.perf_counter() result = {'label': label, 'inputs': inputs, 'attempts': 1, 'retries': 0} try: scene = recipe() scene.finalize() signature, structure = principal_signature(scene) choices = [e for e in scene.events if e['kind'] == 'candidate-selection'] if choices: result['attempts'] = sum(e['attempts'] for e in choices) result.update(status='validated', blocks=len(scene.blocks), components=len(scene.nodes), digest=semantic_digest(scene), principal_signature=signature, structure=structure, contact=contact_metrics(scene), accepted_candidates=sum(e['accepted'] for e in choices) if choices else 1, candidates=choices) # Hash independently frozen terrain before placement using persisted field input and current unchanged bed cells. if output: export_scene(scene, output) result['artifact'] = str(output) except SearchExhausted as exc: result.update(status='budget-exhausted', diagnostic=str(exc), accepted_candidates=0, attempts=getattr(exc, 'attempts', 1), candidates=getattr(exc, 'candidates', [])) except (ContractError, ValueError) as exc: result.update(status='incompatible' if isinstance(exc, ContractError) and exc.diagnostic.rule in ('site-relief', 'support-height', 'fill-volume', 'approach-detour') else 'defect', diagnostic=str(exc), accepted_candidates=0, attempts=getattr(exc, 'attempts', 1), candidates=getattr(exc, 'candidates', [])) result['seconds'] = round(time.perf_counter() - start, 4) return result def run_corpus(output: Path, seed=0, artifacts=False): output.mkdir(parents=True, exist_ok=True) rows = [] specs = [] environments = {} 412K output.litematic 4.6M output.litematic.structure.json
4400
python - <<'PY' p='hearth/components/primitives.py';s=open(p).read().replace("'width': [5, 64], 'height': [4, 12], 'thickness': [1, 3], 'orientations'
python - <<'PY' p='hearth/components/primitives.py';s=open(p).read().replace("'width': [5, 64], 'height': [4, 12], 'thickness': [1, 3], 'orientations': [0, 1, 2, 3]", "'width': Domain(5,64), 'height': Domain(4,12), 'thickness': Domain(1,3), 'frame.turn': Domain(choices=(0,1,2,3))") open(p,'w').write(s) p='hearth/components/interior.py';s=open(p).read().replace('Capability, Contract, Grant','Capability, Contract, Domain, Grant').replace("'width': [9, 11, 13], 'depth': [9, 11, 13], 'purpose': ['living', 'bedroom', 'library', 'workshop', 'kitchen', 'storage']", "'width': Domain(choices=(9,11,13)), 'depth': Domain(choices=(9,11,13)), 'purpose': Domain(choices=('living','bedroom','library','workshop','kitchen','storage'))") open(p,'w').write(s) p='hearth/components/building.py';s=open(p).read().replace('Capability, Contract, Port','Capability, Contract, Domain, Port').replace("'bay': [9, 11, 13]", "'design.bay': Domain(choices=(9,11,13))").replace("'orientations': [0, 1, 2, 3]","'frame.turn': Domain(choices=(0,1,2,3))") open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace('Child, Choice, Contract, Plan','Child, Choice, Contract, Domain, Plan') needle=" ctx = Context(path, frame, scope, self.view, bindings, self.limits)" s=s.replace(needle,""" for key,domain in cap.inputs.items(): if not isinstance(domain,Domain):continue value=frame if key.startswith('frame.') else component parts=key.split('.')[1:] if key.startswith('frame.') else key.split('.') for part in parts: if part.startswith('_') or not hasattr(value,part): raise ContractError('capability-input',path,conditions=key) value=getattr(value,part) if not domain.accepts(value): raise ContractError('input-domain',path,conditions=f'{key}={value!r}') """+needle) open(p,'w').write(s) p='hearth/space.py';s=open(p).read();needle=" raise TypeError('Frames use integer coordinates and quarter turns')";s=s.replace(needle,needle+"\n object.__setattr__(self,'turn',self.turn%4)") open(p,'w').write(s) PY yapf -i hearth/kernel/scene.py hearth/space.py hearth/components/primitives.py hearth/components/interior.py hearth/components/building.py python -m pytest -q test/test_kernel.py test/test_contracts_provenance.py
...................... [100%] 22 passed in 0.46s
450113
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace(' capability: Capability | None = None',' capability: Capability | None = No
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace(' capability: Capability | None = None',' capability: Capability | None = None\n shared_bindings: tuple = ()',1) s=s.replace('Cell(canonical(world_state), owner, opid, write.nbt)','Cell(canonical(world_state), owner, opid, write.nbt, old.shared if old and write.preserve_owner else ())') s=s.replace(' self.members.pop(path,None)'," if node:\n for shared_host,shared_port,point in node.shared_bindings:\n key=(shared_host,shared_port)\n self.port_uses[key]=max(0,self.port_uses.get(key,0)-1)\n self.members.pop(path,None)",1) s=s.replace(" node=trial.nodes[participant]\n node.contract", " node=trial.nodes[participant]\n node.shared_bindings=node.shared_bindings+((host,port,p),)\n node.contract") open(p,'w').write(s) p='hearth/components/landscape.py';s=open(p).read().replace("p.fill(Box((x,2,z),(x,4,z)),log(),'post')","p.fill(Box((x,2,z),(x,5,z)),log(),'post')") s=s.replace("Rule('pool',basin)))","Rule('pool',basin),Rule('support',tuple((x,y,z) for x,z in ((0,0),(3,3)) for y in range(2,6)))))") open(p,'w').write(s) p='hearth/__init__.py';s=open(p).read().replace("__version__ = '1.0.0'","__version__ = '1.1.0'");open(p,'w').write(s) PY rg --files hearth examples extension_demo test -g '*.py' | xargs yapf -i yapf -i generate.py python -m compileall -q hearth examples extension_demo test python -m pytest -q test/test_contracts_provenance.py test/test_kernel.py PYTHONPATH=. python examples/assess.py --seed 0 --output reports/final-corpus --artifacts
e stress-06 incompatible stress-07 incompatible stress-08 incompatible stress-09 validated stress-10 incompatible stress-11 incompatible stress-12 incompatible stress-13 incompatible stress-14 validated stress-15 incompatible stress-16 incompatible stress-17 validated stress-18 validated stress-19 incompatible stress-20 validated stress-21 incompatible stress-22 validated stress-23 incompatible stress-24 incompatible stress-25 validated stress-26 validated stress-27 incompatible stress-28 incompatible stress-29 incompatible stress-30 incompatible stress-31 incompatible { "adaptation": { "inputs": 64, "validated": 64, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 128, "accepted_candidates": 84, "retries": 0, "seconds": 25.064, "observed_principal_signatures": 3, "observed_contact_signatures": 44, "fill_range": [ 0, 159 ] }, "buildings": { "inputs": 24, "validated": 24, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 48, "accepted_candidates": 48, "retries": 0, "seconds": 17.17, "observed_principal_signatures": 18, "observed_contact_signatures": 24, "fill_range": [ 0, 70 ] }, "settlements": { "inputs": 10, "validated": 10, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 80, "accepted_candidates": 80, "retries": 0, "seconds": 52.661, "observed_principal_signatures": 10, "observed_contact_signatures": 10, "fill_range": [ 16, 216 ] }, "stress": { "inputs": 32, "validated": 9, "incompatible": 23, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 64, "accepted_candidates": 11, "retries": 0, "seconds": 9.835, "observed_principal_signatures": 4, "observed_contact_signatures": 9, "fill_range": [ 40, 174 ] } }
46014
cat > examples/__init__.py <<'EOF' # Runnable public-API examples and explicit assessment tools. EOF cat > pyproject.toml <<'EOF' [project] name = "he
cat > examples/__init__.py <<'EOF' # Runnable public-API examples and explicit assessment tools. EOF cat > pyproject.toml <<'EOF' [project] name = "hearth-composition" version = "1.1.0" description = "Contract-based procedural Minecraft composition and provenance" requires-python = ">=3.12" dependencies = ["numpy>=1.26"] [project.optional-dependencies] transport = ["MCIO==0.2.0"] test = ["pytest>=8"] [build-system] requires = ["setuptools>=64"] build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] include = ["hearth*", "extension_demo*"] [tool.setuptools.package-data] hearth = ["data/*.json"] [tool.pytest.ini_options] testpaths = ["test"] addopts = "-ra" EOF cat > .gitignore <<'EOF' __pycache__/ .pytest_cache/ *.egg-info/ test/tmp-*/ *.tmp EOF python - <<'PY' import importlib.metadata as m,json from pathlib import Path versions={k:m.version(k) for k in ['numpy','pytest','deprecated','tqdm','yapf']} versions['MCIO']='0.2.0 (provided source transport)' versions['additional_installs']='none' Path('reports/dependencies.json').write_text(json.dumps(versions,indent=2)) for directory in ('reports/baseline-corpus','reports/corpus'): p=Path(directory)/'results.json' data=json.loads(p.read_text()) for row in data: if 'artifact' in row: row['artifact_at_assessment']=row.pop('artifact') row['artifact_retained']=False p.write_text(json.dumps(data,indent=2)) PY python generate.py python -m examples.prototype --seed 0 python -m examples.courtyard --seed 0 python -m examples.gallery --seed 0 python -m examples.extension --seed 0 python -m examples.inspection --seed 0 > reports/inspection.txt
Validated 5 buildings, 125476 blocks, 783 components. output.litematic | semantic SHA256 ce3df580ffab796c4a3a491e28a959a2039fef7adcd16f87f8700712e9d23660
4700
python - <<'PY' p='extension_demo/__init__.py';s=open(p).read().replace('Plan, Child, Rule','Plan, Child, Rule, Port').replace("('room', 'habitable',
python - <<'PY' p='extension_demo/__init__.py';s=open(p).read().replace('Plan, Child, Rule','Plan, Child, Rule, Port').replace("('room', 'habitable', 'composite'), guarantees=", "('room', 'habitable', 'composite'), offers=('access',), guarantees=") s=s.replace("return Contract(Box((-1, 0, -1), (self.width, 9, self.width)))", "entry=(self.width//2,1,0)\n port=Port('north','access',Frame(entry),Box(entry,(entry[0],2,0)),10,delegate=('reading-room','north'))\n return Contract(Box((-1,0,-1),(self.width,9,self.width)),ports=(port,))") open(p,'w').write(s) p='hearth/kernel/validation.py';s=open(p).read().replace("diagnostics.append(Diagnostic('blockstate', record.owner, p, str(exc)))", "diagnostics.append(Diagnostic('blockstate', record.owner, p, str(exc)))\n continue") open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace('from hearth.blocks import AIR, canonical','from hearth.blocks import AIR, canonical, validate_state') s=s.replace(' world_state = frame.state(write.state)'," try:\n world_state=frame.state(write.state)\n validate_state(world_state)\n except ValueError as exc:\n raise ContractError('blockstate',path,p,str(exc)) from exc") open(p,'w').write(s) PY cat >> test/test_contracts_provenance.py <<'EOF' def test_validator_extension_and_negotiated_domain(): from hearth.kernel import validator,Diagnostic @validator('test.actual-stone') def actual_stone(scene,node,rule): for p in rule.cells: if scene.inspect(p)['state']!='minecraft:stone': yield Diagnostic('test.actual-stone',node.path,p,'Need actual stone') s=Scene() s.place('rule',Assembly('rule',Box((0,0,0),(0,0,0)),(Child('stone',Volume(Box((0,0,0),(0,0,0)),state_of('stone'))),),(Rule('test.actual-stone',((0,0,0),)),))) with pytest.raises(ContractError,match='test.actual-stone'):s.remove('/rule/stone') with pytest.raises(ContractError,match='input-domain'):s.place('bad-wall',Wall(width=100)) EOF yapf -i extension_demo/__init__.py hearth/kernel/validation.py hearth/kernel/scene.py test/test_contracts_provenance.py python -m pytest -q test/test_contracts_provenance.py test/test_kernel.py python - <<'PY' import json from pathlib import Path rows=json.loads(Path('reports/final-corpus/results.json').read_text()) print({name:len({r['principal_signature'] for r in rows if r['label'].startswith(name+'-') and r['status']=='validated'}) for name in ['dwelling','atelier','commons']}) print(json.loads(Path('reports/dependencies.json').read_text())) PY
....................... [100%] 23 passed in 0.51s {'dwelling': 5, 'atelier': 8, 'commons': 5} {'numpy': '2.5.3', 'pytest': '9.1.1', 'deprecated': '1.3.1', 'tqdm': '4.70.1', 'yapf': '0.43.0', 'MCIO': '0.2.0 (provided source transport)', 'additional_installs': 'none'}
48012
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read();needle=' def local(self, p):\n return self.frame.inverse(p)';s=s.replace(needle,
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read();needle=' def local(self, p):\n return self.frame.inverse(p)';s=s.replace(needle,needle+''' def elevation(self,x,z,maximum=None): world=self.world((x,0,z)) cap=None if maximum is None else maximum+self.frame.origin[1] return self.view.elevation(world[0],world[2],maximum=cap)-self.frame.origin[1] def water(self,x,z): world=self.world((x,0,z));level=self.view.water(world[0],world[2]) return None if level is None else level-self.frame.origin[1] def state(self,point): return self.view.state(self.world(point)) ''');open(p,'w').write(s) p='hearth/components/landscape.py';s=open(p).read().replace(' width: int = 3\n',' width: int = 3\n gateway: tuple | None = None\n',1) s=s.replace('maximum = hint[1] if len(hint) == 3 else None','maximum = hint[1]+ctx.frame.origin[1] if len(hint) == 3 else None') old="return Contract(box, ports=(Port('public', 'public-access', Frame(targets[0]), box, 10000),), rules=" new="public=self.gateway or targets[0]\n interface=Box((public[0]-1,public[1]-1,public[2]),(public[0]+1,public[1]+1,public[2]))\n return Contract(box, ports=(Port('public','public-access',Frame(public),interface,10000,'join'),),grants=(Grant('join',interface,('surface',),('path',),9),), rules=" s=s.replace(old,new) # Only Landscape uses untransformed environmental reads. a=s.index('class Landscape:');b=s.index('class FacadeGarden:',a);part=s[a:b] part=part.replace('ctx.view.elevation(x, z)','ctx.elevation(x,z)').replace('ctx.view.state((x, h, z))','ctx.state((x,h,z))').replace('ctx.view.state((x, h + 1, z))','ctx.state((x,h+1,z))') part=part.replace('ctx.view.domain.contains(c) for c in box.corners()','ctx.view.domain.contains(ctx.world(c)) for c in box.corners()').replace('ctx.view.clear(box)','ctx.view.clear(ctx.frame.box(box))') part=part.replace('ctx.view.protected(Box((x - 3, h, z - 3), (x + 3, h + 2, z + 3)))','ctx.view.protected(ctx.frame.box(Box((x-3,h,z-3),(x+3,h+2,z+3))))') part=part.replace('ctx.view.protected(Box((x, h + 1, z), (x, h + 2, z)))','ctx.view.protected(ctx.frame.box(Box((x,h+1,z),(x,h+2,z))))') s=s[:a]+part+s[b:];open(p,'w').write(s) p='hearth/programs.py';s=open(p).read().replace('Binding, Rule','Binding, Rule, Port') old="return Contract(self.domain, decisions={'buildings': len(self.designs), 'arrangement': 'opposed street with staggered frontage', 'circulation': ctx.scope.choose(('spine', 'loop'), 'circulation')})" new="gateway=(0,ctx.elevation(0,-12)+1,-12)\n interface=Box((-1,gateway[1]-1,-12),(1,gateway[1]+1,-12))\n port=Port('public','public-access',Frame(gateway),interface,10000,delegate=('connections','public'))\n return Contract(self.domain,ports=(port,),decisions={'buildings':len(self.designs),'arrangement':'opposed street with staggered frontage','circulation':ctx.scope.choose(('spine','loop'),'circulation'),'gateway':gateway})" s=s.replace(old,new) s=s.replace("SettlementConnections(len(self.designs), self.domain, self.terrain, contract.decisions['circulation'])","SettlementConnections(len(self.designs),self.domain,self.terrain,contract.decisions['circulation'],contract.decisions['gateway'])") s=s.replace("def __init__(self, count, domain, terrain, mode='spine'):","def __init__(self,count,domain,terrain,mode='spine',gateway=None):").replace(' self.mode = mode',' self.mode = mode\n self.gateway=gateway',1) s=s.replace("ctx.view.port(f'{parent}/plot-{i}', 'street').frame.origin for i", "ctx.local(ctx.view.port(f'{parent}/plot-{i}', 'street').frame.origin) for i") s=s.replace("targets = targets + (ctx.view.port(parent + '/square', 'entrance').frame.origin,)\n return Contract(self.domain, rules=", "targets=targets+(ctx.local(ctx.view.port(parent+'/square','entrance').frame.origin),self.gateway)\n interface=Box((self.gateway[0]-1,self.gateway[1]-1,self.gateway[2]),(self.gateway[0]+1,self.gateway[1]+1,self.gateway[2]))\n port=Port('public','public-access',Frame(self.gateway),interface,10000,delegate=('paths','public'))\n return Contract(self.domain,ports=(port,), rules=") s=s.replace('x, y, z = port.frame.origin','x,y,z=ctx.local(port.frame.origin)') s=s.replace('ctx.view.elevation(lane, z)','ctx.elevation(lane,z)').replace('ctx.view.elevation(x, z)','ctx.elevation(x,z)').replace('ctx.view.elevation(lane, square[2])','ctx.elevation(lane,square[2])').replace('ctx.view.elevation(x, z + 4)','ctx.elevation(x,z+4)') s=s.replace("square = ctx.view.port(parent + '/square', 'entrance').frame.origin","square=ctx.local(ctx.view.port(parent+'/square','entrance').frame.origin)") s=s.replace(" bindings.append(Binding(parent + '/square', 'entrance', 'surface'))", " points.append(self.gateway)\n links.append((len(points)-1,1))\n bindings.append(Binding(parent + '/square', 'entrance', 'surface'))") s=s.replace('PathNetwork(tuple(points), tuple(links))','PathNetwork(tuple(points),tuple(links),gateway=self.gateway)') open(p,'w').write(s) p='test/test_geometry_environment.py';s=open(p).read().replace('len(buildings) + 1','len(buildings) + 2');open(p,'w').write(s) PY yapf -i hearth/kernel/scene.py hearth/components/landscape.py hearth/programs.py test/test_geometry_environment.py python generate.py python - <<'PY' from hearth import Scene,Box,Frame from hearth.environment import Terrain,constant from hearth.programs import Settlement,dwelling,atelier from hearth.persistence import semantic_digest local=Box((-49,-4,-23),(49,64,66));frame=Frame((150,2,80),1) s=Scene(0,domain=frame.box(local));s.place('land',Terrain(s.domain,constant(4))) s.place('moved',Settlement([dwelling(1),atelier(1),dwelling(4)],local,'/land'),frame=frame) s.finalize();print('Rotated settlement:',s.view.port('/moved','public').frame,len(s.blocks)) PY
Validated 5 buildings, 125476 blocks, 783 components. output.litematic | semantic SHA256 a247e5b44a194d17c4ba98a29ea37c372253e5be3e1c6356dee50983aea4f345 Rotated settlement: Frame(origin=(162, 5, 80), turn=1) 70081
4900
python - <<'PY' p='hearth/kernel/view.py';s=open(p).read();idx=s.index('\n\nclass View:');s=s[:idx]+''' class ReadTrace: """Coalesce actual envir
python - <<'PY' p='hearth/kernel/view.py';s=open(p).read();idx=s.index('\n\nclass View:');s=s[:idx]+''' class ReadTrace: """Coalesce actual environmental reads and interface dependencies for one candidate.""" def __init__(self): self.low=None;self.high=None;self.sources={} def point(self,p): if self.low is None:self.low=list(p);self.high=list(p) else: for i in range(3): self.low[i]=min(self.low[i],p[i]);self.high[i]=max(self.high[i],p[i]) def region(self,box): self.point(box.lo);self.point(box.hi) @property def bounds(self): return None if self.low is None else Box(tuple(self.low),tuple(self.high)) ''' +s[idx:] s=s.replace('def __init__(self, scene):\n self.__scene = scene','def __init__(self,scene,trace=None):\n self.__scene=scene\n self.__trace=trace') s=s.replace(' p = tuple(p)\n if self.domain', ' p=tuple(p)\n if self.__trace:self.__trace.point(p)\n if self.domain',1) s=s.replace(' def owner(self, p):\n record', ' def owner(self, p):\n if self.__trace:self.__trace.point(p)\n record') s=s.replace(' return copy.deepcopy(p)',' if self.__trace:self.__trace.sources[host]=p.region\n return copy.deepcopy(p)') s=s.replace(' def contract(self, path):\n return', ' def contract(self, path):\n if self.__trace:self.__trace.sources[path]=self.__scene.nodes[path].contract.envelope\n return') s=s.replace(' def protected(self, box):\n return', ' def protected(self, box):\n if self.__trace:self.__trace.region(box)\n return') open(p,'w').write(s) p='hearth/kernel/scene.py';s=open(p).read().replace('from .view import View','from .view import View, ReadTrace') s=s.replace(' ctx = Context(path, frame, scope, self.view, bindings, self.limits)',' trace=ReadTrace()\n ctx=Context(path,frame,scope,View(self,trace),bindings,self.limits)') s=s.replace(' if not isinstance(plan, Plan):'," if trace.bounds:\n self.dependencies.append({'consumer':path,'source':'environment','version':self.version,'region':trace.bounds,'reason':'observed-spatial-input'})\n for source,region in sorted(trace.sources.items()):\n if source!=path:\n self.dependencies.append({'consumer':path,'source':source,'version':self.version,'region':region,'reason':'observed-interface-input'})\n if not isinstance(plan, Plan):") open(p,'w').write(s) p='hearth/kernel/validation.py';s=open(p).read().replace(" for parent in (node.parent, node.primary):", " for port in node.contract.ports:\n if port.delegate:\n try:\n _,actual=scene.view.resolved_port(node.path,port.key)\n if (port.frame,port.region,port.kind)!=(actual.frame,actual.region,actual.kind):\n diagnostics.append(Diagnostic('forwarded-interface',node.path,port.frame.origin,'Child interface changed without parent renegotiation'))\n except (KeyError,ValueError):\n diagnostics.append(Diagnostic('forwarded-interface',node.path,port.frame.origin,'Delegated port missing'))\n for parent in (node.parent, node.primary):") open(p,'w').write(s) PY yapf -i hearth/kernel/view.py hearth/kernel/scene.py hearth/kernel/validation.py python -m pytest -q test/test_kernel.py test/test_contracts_provenance.py
....................... [100%] 23 passed in 0.44s
50155
cat >> test/test_geometry_environment.py <<'EOF' def test_complete_settlement_transforms_and_public_gateway(): from hearth.programs import Settl
cat >> test/test_geometry_environment.py <<'EOF' def test_complete_settlement_transforms_and_public_gateway(): from hearth.programs import Settlement,dwelling,atelier local=Box((-49,-4,-23),(49,64,66)) frame=Frame((150,2,80),1) s=Scene(0,domain=frame.box(local)) s.place('land',Terrain(s.domain,constant(4))) s.place('district',Settlement((dwelling(1),atelier(1),dwelling(4)),local,'/land'),frame=frame) s.finalize() ports=s.view.offers('/district','public-access') assert len(ports)==1 and ports[0].frame.turn==1 assert ports[0].frame.origin==frame.point((0,3,-12)) assert s.view.capability('/district/plot-0').inputs['design.bay'].accepts(9) assert any(d['reason']=='observed-spatial-input' for d in s.dependencies) EOF python - <<'PY' p='hearth/assessment.py';s=open(p).read();old=" return {'fill': sum(d['fill'] for d in data), 'excavation': sum(d['excavation'] for d in data), 'strategies': [d['strategy'] for d in data], 'signature': hashlib.sha256(json.dumps(data, sort_keys=True).encode()).hexdigest()}";new=""" edit_paths={key for key,n in scene.nodes.items() if n.capability and set(n.capability.tags).intersection(('siteworks','path'))} occupied=sum(len(scene.cells(key)) for key in edit_paths) replacements=sum(len(scene.displaced.get(key,{})) for key in edit_paths) from hearth.blocks import solid,AIR excavated=sum(solid(old.state) and not solid(scene.blocks[p].state if p in scene.blocks else AIR) for key in edit_paths for p,old in scene.displaced.get(key,{}).items()) return {'fill':sum(d['fill'] for d in data),'excavation':excavated,'sitework_occupied_cells':occupied,'replaced_cells':replacements,'new_sitework_cells':occupied-replacements,'strategies':[d['strategy'] for d in data],'signature':hashlib.sha256(json.dumps(data,sort_keys=True).encode()).hexdigest()}""";s=s.replace(old,new);open(p,'w').write(s) PY yapf -i hearth/assessment.py test/test_geometry_environment.py python -m pytest -q test > reports/pytest-final.txt
51085
python -m examples.assess --seed 0 --output reports/final-corpus --artifacts > reports/assessment-final.txt
python -m examples.assess --seed 0 --output reports/final-corpus --artifacts > reports/assessment-final.txt
5200
cat > ARCHITECTURE.md <<'EOF' # Hearth architecture, version 1.1.0 The initial design was written before the kernel or extensive scene geometry. The
cat > ARCHITECTURE.md <<'EOF' # Hearth architecture, version 1.1.0 The initial design was written before the kernel or extensive scene geometry. The executable foundation passed seven tests before the terrain/grass/tree/wall/window prototype, then furnished rooms and buildings were added, followed by settlements and the finite corpus. The original design is retained in [ARCHITECTURE.initial.md](ARCHITECTURE.initial.md). This document describes the implemented design; [GENERATOR.md](GENERATOR.md) contains usage and the R01-R30 evidence ledger. ## Module boundaries | Layer | Modules | Responsibility | |---|---|---| | Values and geometry | `space`, `blocks`, `randomness` | Inclusive integer boxes, frames, Java blockstates, stable random scopes | | Composition kernel | `kernel/contracts`, `scene`, `view`, `validation`, `errors` | Negotiation, permissions, transactions, instances, graphs, queries and rule scheduling | | Environments | `environment/fields`, `terrain` | Composable field expressions, frozen sampled strata and water | | Architectural knowledge | `components/*`, `adapters/site` | Windows, walls, furnishings, rooms, roofs, buildings, contact and access strategies | | Public composition | `composition`, `programs` | Selection, encapsulation, arrangement, repetition, scattering, room graphs and settlement intent | | Transport and assessment | `persistence`, `assessment`, `examples/*` | Verified Litematica export/reload, inspection, explicit batches | | Independent extension | `extension_demo` | A different light and a composite reading suite with a forwarded entrance | The kernel imports no concrete architectural implementation and never imports the CLI. The CLI is an ordinary client. A browser adapter could retain the kernel, field expressions, plans and JSON records, replacing the Python host/transport. No browser runtime or UI is included. ## One protocol for leaves and composites A component implements: ```python capability() -> Capability negotiate(context: Context, parameters: dict) -> Contract realize(context: Context, contract: Contract) -> Plan ``` `Capability` separates feasible offers from a placed instance. It includes semantic tags, executable `Domain` checks for constructor inputs and execution parameters, assumptions, adaptation strategies, guarantees, implementation version and locked decisions. Nested constructor paths such as `design.bay`, and `frame.turn`, have executable domains. Constructors carry explicit principal intent; `parameters` contains only advertised runtime overrides. Unknown overrides fail. Recorded inputs include public constructor fields, execution arguments and negotiated decisions. `Contract` contains a conservative local envelope, ports, grants, rules, decisions, input regions and whole-object status. It becomes a world-space contract through the instance frame. Occupied geometry is derived from effects and indexed exactly; an envelope is never substituted for actual membership. Rules express support, protected clearance, preservation, enclosure, lighting, furnishing and access. Effect coordinates must stay within the negotiated envelope, and child envelopes within their parent's envelope. Expansion requires another negotiation. A `Port` has a kind, oriented frame, region, capacity, alignment, facts and an optional grant. Wall ports expose thickness, sill and excluded frame margins. A `Binding` names a host and port, a verb, and an optional further restriction in **world coordinates**. Installation requires compatible orientation, anchor alignment, available capacity and a compatible grant. Windows negotiate their reveal depth against the public port; parents can substitute shuttered and hooded implementations. Composite ports may delegate to a named child port. The kernel resolves authority through the chain, while callers bind to the composite. It verifies the realized child's frame, region and kind against the negotiated public interface, including during later validation. Buildings forward their street connection; settlements forward a public gateway through their path composition. The independent reading suite forwards its room entrance. Parents do not name private approach children. ## Plans, candidates and transactions `Plan` contains writes, children, bounded `Choice` operations and typed relationships. Component code reads an environmental view and returns effects. It cannot receive the shared mutable store through its context. The view copies contract/port records and exposes styles through a read-only mapping. This is a trusted Python programming protocol, not an arbitrary-code security sandbox. A placement forks the current state. The kernel: 1. Allocates a stable instance path and random scope; checks feasible domains. 2. Negotiates a contract and resolves binding authority. 3. Applies final per-coordinate effects under the executing component/operation identity. 4. Instantiates semantic children through the same protocol. 5. Checks tentative geometry, existing consumers and completed local obligations. 6. Commits the entire state or discards the entire candidate. Multiple writes inside one candidate component are coalesced to their final operation. They do not create false collisions with earlier versions of that component's own local plan. Foreign writes still require authority. The kernel never uses a global priority or identical-state overwrite rule. Failed transactions preserve geometry, nodes, ownership, ports, relationships, dependencies, history and sibling random scopes. `Choice` evaluates complete candidate child compositions in isolated forks. It first checks hard conditions, then scores actual sitework cost and exposed support proportions. It selects by a scoped seed among alternatives within an explicit quality tolerance. `adapted(...)` proposes stepped perimeters and piers under the same locked principal design. Water/high relief constrain the feasible strategy set. Candidate scores and all rejection diagnostics are recorded. A bounded search with unvisited alternatives reports `SearchExhausted`; identical hard failures of every declared contact alternative retain the specific failed constraint. This is not a proof about unimplemented techniques. ## Authority, phases and logical objects A grant identifies an owner, region, allowed verbs, consumer tags, per-binding change limit and whether whole-object replacement is allowed. Binding restrictions can narrow a grant. A high planting preference never grants excavation rights. Soil grants local construction edits, planting consumes substrate support, and grass explicitly grants whole-object replacement to trees. Existing support and clearance rules survive unrelated edits. Pools cannot undermine a supported tree. Paired plants and doors cannot be partially replaced through an ordinary binding. Property adjustments retain the original semantic owner and require the same block type. Deletions remove current ownership; erasure history is separate from current cells. Displaced cells are retained compactly so branch removal/regeneration can restore surviving host content. Retired grass disappears from current nodes, relationships and ownership, while the operation history can still explain its replacement. Explicit shared support records a participant, a capacity use, a support obligation and a typed association. It does not transfer the primary owner. Shared writes require consumer rebinding; identical states alone never authorize sharing. Construction starts with a temporarily open scope. Invariants run throughout; completion rules run when the scope closes. `complete=False` permits an explicitly unfinished scope, and `finish_scope` closes it. Unfinished or stale content cannot be finalized or exported. Once a room is complete, subsequent placements must preserve its access, lighting and enclosure. A building provides internal circulation and an external landing. The settlement discharges its connection to public paths. ## Environmental observations and adaptation `View` uses world coordinates and explicit known bounds. `Context.world/local` convert positions; `Context.elevation/water/state` are local-frame convenience queries. Views expose actual 3D states, owners, solid support, bounded elevation search, water, slope, substrate depth, clearance, protected regions, obstacle distance, style roles, preferences and public interfaces. Unknown space raises an error. A roof is not assumed to be the ground surface: path observations are bounded by the offered access elevation. Field expressions support constants, gradients, waves, radial masks, addition, multiplication, blending, transforms and clamping. They can be nested and supplied by an independent compatible implementation. Water intersects the sampled strata. Adaptation never inspects an environment class, recipe label or particular seed. The 64-case assessment freezes sixteen complete 3D terrain scenes before making four independently seeded building placements on copies of each. Sitework measures support and water, preserves gravity alignment, and bounds relief, post height, fill, excavation grants and approach length. Foundations produce support columns/perimeters to the actual solid bed. The approach examines its full tread width and water surface. The principal room graph, functions, footprint bays, locked horizontal placement and chosen roof intent remain intact. No algorithm levels the whole site to guarantee success. ## Three distinct graphs and exact indexes An instance ID is its stable parent/key path. The kernel automatically records creation type, constructor inputs, resolved decisions, frame, implementation and random scope. Helper calls do not create semantic ancestors. Windows, walls, floors, furniture, lights and adapters are actual instances. * Structural containment and attachment form a graph. Attachment supplies the primary structural chain, while containment remains recorded. Bridges/path networks can relate to many structures. * Data/constraint dependencies have a source, consumer, region, input version and reason. An automatic read trace coalesces actual spatial observations and records interface reads, supplementing declared regions and bindings. These are not false structural ancestors. * Operations retain generating actor, operation key, write count, displaced identities and restorable old cells. These records do not make a displaced object a current owner. The sparse coordinate map stores one current owner and operation per occupied cell. Reverse maps provide exact cells by owner and shared participant. A structural adjacency index supports descendant queries through attachment as well as containment: a window created by an external facade program is still included when highlighting its host wall or building. Queries traverse this graph, never scan the full voxel store or copy ancestor strings onto each cell. Removing a branch updates all indexes. External attached/dependent consumers must be regenerated or removed together; otherwise validation rejects the transaction. `regenerate(path, ..., dependents=...)` restores displaced host output, removes obsolete nodes and replays affected branches from their original inputs/scopes. It never repeatedly cuts the already modified terrain. Explicit co-regeneration is intentional: there is no hidden oscillating terrain/building update loop. ## Persistence, coordinates and replay Positions are `(x,y,z)`, Y up, north -Z. A positive quarter-turn maps `(x,y,z)` to `(-z,y,x)`. Frames transform coordinates, boxes, rule cells, ports and directional block properties, including cardinal connection keys, axes, rotation values and supported rail/orientation strings. Custom rule `data` is uninterpreted; a validator needing directions uses its node frame. Export bounds are derived from every realized occupied cell. MCIO indexing is converted explicitly to `(y,z,x)`. Export-local coordinates equal world coordinates minus the companion's `offset`. The original world frame is restored on reload, including negative coordinates. `persistence` writes one Java 1.21.1 region (data version 3955) and a versioned structural JSON record. It retains capabilities/contracts, nodes, frames, random scopes, styles, field inputs, dependency and structure graphs, current ownership, operation/displacement records, and relevant inventory NBT. The geometry digest canonicalizes parsed names and **explicit** property mappings and includes world coordinates and block-entity data. It ignores property order only, not missing/defaulted properties. Reload reads actual schematic blocks and NBT, verifies dimensions/digest/ownership and reruns the validators. Missing/unknown metadata or mismatched geometry is rejected as untrusted. The companion is not a cryptographic signature, and arbitrary geometry cannot reconstruct a graph. Reload does not execute serialized Python. To regenerate a reloaded branch, explicitly supply its component implementation; inputs and source programs/manifests support replay. Arbitrary entity types and a general block-entity migration system are not implemented; these artifacts export no entities. ## Validation model and limits Validators register through `@validator(name)`; component authors use existing rules or add a named handler without editing dispatch. Missing handlers are errors, including after reload. The physical model uses integer standing positions, two air/passable cells, cardinal moves and elevation changes of at most one block with extra clearance for ascending/descending. Wood doors are considered operable. Stairs are checked as usable flights and declared clearance volumes. This is not a full Minecraft collision/fluid/redstone simulator. Lighting propagates actual source levels through passable/transparent cells with unit attenuation; closed opaque boundaries block propagation. It checks required room locations, not a claim that all possible mob-spawning cells are spawn-proof. Enclosure checks actual room floors/ceilings and wall surfaces. Roof abutments are bounded voxel joins above sealed ceilings; universal flashing or structural mechanics are not proved. Support checks declared load paths, substrate and support grids, not an engineering stress solver for arbitrary blocks or decorative cantilevers. Default limits are 512 blocks per axis, 1,000,000 occupied blocks, depth 40, 10,000 instances and 24 search alternatives. Demo count limits live in the CLI, not the kernel. Costs, bounds and failure conditions are public. Existing tests and finite observations establish only the documented scope. EOF cat > GENERATOR.md <<'EOF' # Hearth procedural composition Hearth generates furnished timber-and-stone buildings and a connected settlement for Minecraft Java 1.21.1. The default seed is **0**; it produces five buildings, public paths, a well terrace, lights, planters, trees and grass. Structural choices include room counts/functions/adjacencies, wings, storeys, stair allocation, roof runs/pitches, porches, foundation strategies and street topology. There is no whole-building family selector in the kernel or settlement generator. ## Quickstart ```sh python generate.py python generate.py --seed 0 --output example.litematic python generate.py --seed 1 --count 6 --output "samples/six building village.litematic" python -m pytest -q test ``` A successful command validates the composition, exports a nonempty single region, reloads it and verifies its semantic content. Each schematic has a `.litematic.structure.json` companion. Keep the pair together. Explicit paths may be relative, absolute or contain spaces. No downloads, reference generator, previous output or credentials are used. Python 3.12 and numpy are required; transport uses the provided MCIO **0.2.0** public API. It is imported normally, then from `/work/generator/MCIO` in this environment. On another host, install MCIO from its source before using export/reload. The Java blockstate reference is bundled under `hearth/data/`. Exact versions observed here are recorded in [reports/dependencies.json](reports/dependencies.json); no additional packages were installed. Rendering additionally needs the optional supplied MCRender toolset. ## Short compositions These are intent descriptions; clients do not write voxels, repair geometry or assign block owners. ```python from hearth.components.building import Blueprint, RoomSpec from hearth.programs import building_scene plan = Blueprint(( RoomSpec(0, 0, 0, "living"), RoomSpec(0, 0, 1, "bedroom"), RoomSpec(1, 0, 0, "workshop"), ), bay=11, porch=True, roof_axis="auto") scene = building_scene(plan, seed=17) # No file export required. ``` Place on a previously generated environment: ```python from hearth import Scene, Box, Frame from hearth.environment import Terrain, gradient, wave from hearth.components.building import adapted scene = Scene(seed=17, domain=Box((-15, -4, -20), (40, 60, 40))) field = gradient(x=0.025, base=4) + wave(amplitude=0.7) scene.place("land", Terrain(scene.domain, field)) scene.compose_choice(adapted("home", plan, "/land", Frame((3, 0, 4), 1))) scene.finalize() ``` Discover and substitute implementations: ```python from hearth.kernel import Registry from hearth.components.interior import Light from extension_demo import Pendant registry = Registry() registry.register(Light()) registry.register(Pendant()) candidates = registry.select("room-light") # Either implementation can be supplied as Blueprint(..., light_component=...). public_ports = scene.view.offers("/home", "access") capability = scene.view.capability("/home") ``` `hearth.composition` provides `encapsulate`, `attach`, `arrange`, `repeat`, `scatter` and `constrain`. A composition returns `Plan(children=[Child(...), Choice(...)])` and uses the same component protocol as a light or tree. Building, reading-suite and settlement interfaces support recursive port forwarding. [ARCHITECTURE.md](ARCHITECTURE.md) documents frames, grants and the complete lifecycle. ## Runnable examples and batches ```sh python -m examples.prototype --seed 0 python -m examples.building dwelling --seed 3 --output samples/dwelling-demo.litematic python -m examples.building atelier --seed 5 --output samples/atelier-demo.litematic python -m examples.building commons --seed 6 --output samples/commons-demo.litematic python -m examples.courtyard --seed 0 python -m examples.gallery --seed 0 python -m examples.extension --seed 0 python -m examples.inspection --seed 0 python -m examples.assess --seed 0 --output reports/reassessment --artifacts ``` The three primary programs are short room-graph recipes in `hearth/programs.py`. The courtyard and gallery clients were written after the abstractions existed. The independent extension supplies an actual pendant light and a nested reading suite using public components/validators. The gallery uses that extension without geometry repairs. The courtyard exposed a generic concave-corner decoration conflict, corrected by moving facade climbers away from corner installation margins. The assessment command is an explicit batch output: it writes all inputs, results, rejections, candidate scores, summaries and selected samples. Unit tests create only cleaned temporary files under `test/`; they do not silently produce corpus artifacts. ## Seeds, domains and adaptation Seeds are explicit signed Python integers. SHA-256 derives streams from seed, stable instance keys and purpose; Python `hash()` and ambient randomness are never used. Planning, adaptation, geometry, materials and decoration use separate purpose keys. `Child(..., seed=...)`, `Scene.place(..., seed=...)` and `regenerate(..., seed=...)` override a subtree. `Scene.fork(seed=...)` preserves existing frozen content and changes only the seed for future placements. Stable independent branches commute; dependent grass/tree replacement intentionally does not. The delivered building planner supports connected grid rooms with bay sizes **9, 11 or 13**, six furnishing purposes, supported stacked levels, shared horizontal circulation and one vertical flight per upper connected group. Ordinary room contracts support the same bay sizes. Walls expose widths 5-64, heights 4-12 and thicknesses 1-3. Other implementations can advertise different feasible domains; the kernel has no room-grid or building-count dispatch. Site policy defaults: measured relief at most **5**, bed-to-floor support height at most **8**, approach length at most **12**, foundation fill at most **1,600** cells and excavation authority bounded by the terrain grant (default 2,500 changes per binding). `SiteLimits` and grants expose these values. Contact alternatives compare actual effects, permitting local piers, stepped perimeter work and access treads. The default buildings do not excavate; the pool component exercises authorized excavation separately. Small terraces fill bounded local differences. The major terrain surface is not flattened. Hard constraints include write authority, existing consumers, declared support/headroom, protected regions, locked room functions and placement. Preference fields and style roles are public observations. Preferences do not override constraints. Unknown space is an error. The kernel rejects effects outside accepted envelopes and derives export bounds from realized content, including vegetation and adapters. `Limits` controls dimensions, block count, instances, recursion and candidate budget. A completed standalone building offers an exterior landing. Its enclosing composition is responsible for a public path beyond that landing; a wet site can offer a boardwalk landing. The settlement fulfills this obligation and exposes its own public gateway. It can be translated and rotated as a composite. ## Inspection, identity and regeneration ```python from pathlib import Path from hearth.persistence import export_scene, load_scene point = next(p for p, cell in scene.blocks.items() if cell.state == "minecraft:glass") explanation = scene.inspect(point) print(explanation["chain"], explanation["related"], explanation["operation"]) cells = scene.cells(explanation["instance"], descendants=True) export_scene(scene, Path("sample.litematic")) restored = load_scene(Path("sample.litematic")) assert restored.inspect(point) == explanation ``` The runnable inspection example selects actual room glass and prints its window, host wall, room and building chain, typed relationships and exact cells before and after reload. See [reports/inspection.txt](reports/inspection.txt). `cells(..., descendants=True)` follows semantic attachment/containment indexes, including windows installed by a higher-level facade program. `shared=True` includes explicitly shared supports. Removed/displaced objects are not current owners. World coordinates are `(x,y,z)`. Export coordinates subtract the JSON `offset`; reload restores the world coordinates. Quarter-turns transform states, ports, claims and ownership consistently. Explicit property mappings compare regardless of order; omitted properties are never inferred for equality. Inventory NBT is transported and verified. Missing, unknown or mismatched companions are rejected; a bare schematic is not claimed to contain its original semantic graph. `scene.regenerate("/land", new_terrain, dependents=("/house",))` explicitly replaces affected output and replays dependent branches. Old displaced terrain is restored before replay. Dependency records include automatic spatial/interface read traces and input versions. Invalidated branches cannot be exported as completed. After reload, regeneration requires an explicit component implementation; serialized metadata is never executed as Python. ## Diagnostics and failure behavior `ContractError.diagnostic` contains `rule`, `component`, `position` and `conditions`. `ValidationError.diagnostics` reports actual geometry violations. Examples include `write-authority`, `whole-object`, `edit-limit`, `protected-region`, `support`, `clearance`, `reachability`, `lighting`, `door-pair`, `pool-containment`, `forwarded-interface` and `geometry-mismatch`. Failed candidates leave the entire scene unchanged. `SearchExhausted` distinguishes a search budget from an established parameter/contact incompatibility. A failed finite search does not prove that no other algorithm or composition can succeed. Tests include a budget-limited rejection where the next, unvisited candidate is valid. ## Evidence and limits The frozen sampling policy is [reports/sampling-policy.json](reports/sampling-policy.json). The current results are [reports/final-corpus/results.json](reports/final-corpus/results.json), [summary.json](reports/final-corpus/summary.json) and [adaptation-inputs.json](reports/final-corpus/adaptation-inputs.json). Earlier result records remain under `reports/baseline-corpus/` and `reports/corpus/`; their historical sample paths are labeled as superseded, not current matching artifacts. The assessed finite budget consists of 64 independent environment/building pairings, 24 building runs (three clients, seeds 0-7), ten settlement runs (seeds 0-7 plus both count boundaries), and 32 unresampled stress inputs. Sixteen complete terrain scenes are frozen independently before placing buildings. Half the environment expressions use the held-out blend/transform composition. The same public measured-geometry adapters handle all cases. The reported successful building corpus has **18** observed principal signatures: dwelling **5/8**, atelier **8/8**, commons **5/8**. The ten settlement runs have **10** observed signatures. Signatures exclude names, surface materials and global placement; they include actual room extents, adjacencies, storeys/stairs, roof geometry and path organization. Foundation/contact signatures are reported separately and never counted as principal architectural variety. This is finite observation only. Known limits remain explicit: * The movement model uses integer standing positions, operable wooden doors, two-cell headroom and bounded one-block elevation changes. It is not the full Minecraft collision or jump simulation. * Lighting uses actual source propagation/occlusion at required room locations; it is not a complete skylight, mob-spawning or Minecraft update simulation. * Declared support paths and bounded spans are checked. Arbitrary structural stress, every decorative cantilever, and universal watertight flashing for arbitrary roof intersections are not proved. The delivered roof system handles bounded gables, runs and wall abutments over sealed ceilings. * General block/entity migration, arbitrary entity generation, a browser viewer, and a full city planner are not implemented. Exported entity lists are empty; barrel inventories are real NBT. * Regeneration is explicit and can be coarse. The kernel records affected dependencies and refuses stale completion; it does not invent an unbounded automatic replan or resolve every terrain shape. * The provided style is coherent timber/stone architecture, with visible modular bays. The small representative render set supports inspection, not an exhaustive aesthetic judgment or a claim to reproduce all sixteen reference images. ## Requirement ledger | ID | Implemented API/module and evidence | Qualification | |---|---|---| | R01 | `kernel/*`, initial design, seven foundation tests before content; thin CLI | Executable foundation, not placeholder interfaces | | R02 | Independent implementation; supplied snapshots unchanged; reference images used as aesthetic goals | No reference generator invoked or imported | | R03 | `Blueprint`, room graph programs, `Choice`, roof planner, spine/loop paths; finite signatures | Room grid and roof primitives are bounded, openly documented | | R04 | Module table in architecture; kernel has no component imports; transport separate | Browser host adapter not implemented | | R05 | `Capability`, executable `Domain`, `Contract`, `Port`, `Grant`, rules and read-only `View` | Free-form descriptive assumptions complement executable checks | | R06 | `Plan/Child/Choice`, registry, composition operations, forwarded ports; extension/nested tests | New primitives can extend beyond the shipped grid vocabulary | | R07 | Scoped authority, whole-object replacement, shared support; tree/grass/pool/window/clearance tests | No universal priority or same-state sharing shortcut | | R08 | Fork/validate/commit kernel, plans and automatic read traces; rollback snapshots | Trusted Python components, not a hostile-code sandbox | | R09 | Open/complete scopes, ancestor-aware obligations, finalization; unfinished/light and late-edit tests | Standalone landing-to-public-path is an enclosing obligation | | R10 | Automatic nodes/operation owners, real window/wall instances; inspection and cross-scope attachment tests | No per-voxel client owner maps or post-hoc tagging | | R11 | Structural graph, dependency graph, operations/displacement records; update/share/removal tests | Historic actors may remain in history, never as current owners | | R12 | `inspect`, owner/shared reverse indexes, semantic descendant index; regeneration and deletion tests | Headless queries delivered; no clickable viewer | | R13 | Paired JSON/Litematica, version/digest/offset checks, actual reload validation; mismatch/NBT tests | Pairing integrity is not cryptographic authenticity | | R14 | General field algebra, masks, transforms, strata, water and constrained scattering | No environment-family dispatch; finite shipped operations are extensible | | R15 | Domain/version-aware 3D view, elevation cap, support/water/slope/clearance/style/preferences | Unknown space errors; no simulation of every Minecraft behavior | | R16 | Foundation, approach, window-depth and roof-abutment components | Universal roof-junction/flashing solver not implemented | | R17 | Frozen terrain, measured site survey, bounded complete candidates, joint tentative validation | Fixed principal intent; failures beyond bounds are retained | | R18 | Hard checks then actual effect cost/exposure score, seeded near-best choice, rejection records | Search-budget negative test; no claim of exhaustive feasibility | | R19 | Automatic/declared input dependencies, stale flags, explicit atomic co-regeneration | Dependency updates are conservative; no implicit arbitrary auto-replan | | R20 | SHA-256 scope keys/purposes, overrides, copied environments; branch/order/retry and hash-seed replay tests | Genuine spatial dependencies may change descendants | | R21 | Configurable `Limits`, `SiteLimits`, effect envelopes and realized export bounds | Demonstration count bound is only in the CLI | | R22 | Initial design, kernel tests, prototype, buildings/extension, corpus/render stages | Generic defects and fixes recorded in development findings | | R23 | `test_kernel`, `test_contracts_provenance`: substitution, independent extension, authority, rollback, sharing, transforms, seeds | Custom validator registration also tested | | R24 | Glass chain, two identities, external attachment membership, updates/deletions/regeneration, shared cells, transport mismatch tests | Actual structure restored from companion, not inferred from materials | | R25 | 64 frozen pairings, compatible independent field/environment, protected outside cells, perturbation and stress records | Finite supported domain; 32 stress inputs retained without resampling | | R26 | Three short clients x eight seeds; settlement x eight seeds plus counts 3 and 6; later courtyard/gallery | Programs use public room/component APIs | | R27 | Actual blocks/NBT: schema, support, headroom/routes, pair consistency, enclosure, lights, furnishings, pools and path joins; deliberate damage tests | Physical/lighting model limitations above apply | | R28 | Structural/contact signatures, exterior views, circulation/furnishing cutaways, inspection notes | Modular aesthetic remains visible; no exhaustive beauty claim | | R29 | `generate.py`, importable scene builders, inspection example, verified one-region transport | Offline runtime uses bundled schema and installed/provided MCIO | | R30 | Library, docs, CLI, tests, extension, output pair, manifest, reports and labeled previews | Broader simulation, arbitrary entities, browser UI and city planner remain unfinished | EOF
5300
python - <<'PY' import json from pathlib import Path p=Path('references/manifest.json');d=json.loads(p.read_text());print(type(d).__name__);print(str(
python - <<'PY' import json from pathlib import Path p=Path('references/manifest.json');d=json.loads(p.read_text());print(type(d).__name__);print(str(d)[:1800]) PY
dict {'schema_version': 1, 'copied_at_utc': '2026-09-26T15:16:32.505996+00:00', 'purpose': 'Aesthetic outcomes only; no source architecture, implementation reuse, family coverage, or one-to-one reproduction requirement.', 'source_paths_relative_to': 'Experiment directory', 'supplied_paths_relative_to': 'task directory / generated workspace', 'image_role': 'Original reference images, not certified renders of the supplied programs.', 'files': [{'group': 'exp8', 'reference': 'mediterranean-villa', 'kind': 'program', 'path': 'references/exp8/mediterranean-villa/generate.py', 'snapshot_source': 'prompts/proc-8/task/references/mediterranean-villa/generate.py', 'original_source': 'runs/exp8/mediterranean-villa/work/generator/workspace/generate.py', 'source_manifest': 'prompts/proc-8/task/references/README.md', 'sha256': '115ed3de3aaa05df491654a45a79368624f05f24d9f2f567e39946264805c5c9', 'bytes': 37250}, {'group': 'exp8', 'reference': 'mediterranean-villa', 'kind': 'original_reference_image', 'path': 'reference_exp8_mediterranean_villa.jpg', 'snapshot_source': 'prompts/proc-8/task/reference_mediterranean_villa.jpg', 'original_source': 'runs/exp8/mediterranean-villa/work/generator/workspace/reference_mediterranean_villa.jpg', 'source_manifest': 'prompts/proc-8/task/references/README.md', 'sha256': '261a1f0d1ecf9469859497f75e00685fedbac47cd20ea405fd689a2aec9fbb9d', 'bytes': 253441}, {'group': 'exp8', 'reference': 'merchant-manor', 'kind': 'program', 'path': 'references/exp8/merchant-manor/generate.py', 'snapshot_source': 'prompts/proc-8/task/references/merchant-manor/generate.py', 'original_source': 'runs/exp8/merchant-manor/work/generator/workspace/generate.py', 'source_manifest': 'prompts/proc-8/task/references/README.md', 'sha256': '99816193d943c27f81384bc0f17f725c3304befc7272014b3
5400
tail -5 reports/pytest-final.txt && tail -70 reports/assessment-final.txt && python - <<'PY' import json from collections import Counter from pathlib
tail -5 reports/pytest-final.txt && tail -70 reports/assessment-final.txt && python - <<'PY' import json from collections import Counter from pathlib import Path rows=json.loads(Path('reports/final-corpus/results.json').read_text()) print('stress_reasons',Counter(r['diagnostic'].split(':')[0] for r in rows if r['label'].startswith('stress') and r['status']!='validated')) print('input_files',len(json.loads(Path('samples/replay-manifest.json').read_text()))) PY
FAILED test/test_geometry_environment.py::test_settlement_corpus_and_boundaries[7-None] FAILED test/test_geometry_environment.py::test_settlement_corpus_and_boundaries[0-3] FAILED test/test_geometry_environment.py::test_settlement_corpus_and_boundaries[0-6] FAILED test/test_geometry_environment.py::test_complete_settlement_transforms_and_public_gateway 11 failed, 118 passed in 54.78s { "adaptation": { "inputs": 64, "validated": 64, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 128, "accepted_candidates": 84, "retries": 0, "seconds": 32.836, "observed_principal_signatures": 3, "observed_contact_signatures": 44, "fill_range": [ 0, 159 ] }, "buildings": { "inputs": 24, "validated": 24, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 48, "accepted_candidates": 48, "retries": 0, "seconds": 22.095, "observed_principal_signatures": 18, "observed_contact_signatures": 24, "fill_range": [ 0, 70 ] }, "settlements": { "inputs": 10, "validated": 0, "incompatible": 0, "defects": 10, "budget_exhausted": 0, "candidate_attempts": 20, "accepted_candidates": 0, "retries": 0, "seconds": 9.881, "observed_principal_signatures": 0, "observed_contact_signatures": 0, "fill_range": [ 0, 0 ] }, "stress": { "inputs": 32, "validated": 9, "incompatible": 23, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 64, "accepted_candidates": 11, "retries": 0, "seconds": 13.636, "observed_principal_signatures": 4, "observed_contact_signatures": 9, "fill_range": [ 40, 174 ] } } stress_reasons Counter({'site-relief': 21, 'support-height': 2}) input_files 13
55011
mkdir -p reports/phase-regression && cp reports/final-corpus/results.json reports/final-corpus/summary.json reports/pytest-final.txt reports/phase-reg
mkdir -p reports/phase-regression && cp reports/final-corpus/results.json reports/final-corpus/summary.json reports/pytest-final.txt reports/phase-regression/ python - <<'PY' p='hearth/kernel/validation.py';s=open(p).read().replace(' if port.delegate:\n try:', ' if port.delegate and (node.complete or final):\n try:');open(p,'w').write(s) p='ARCHITECTURE.md';s=open(p).read().replace('The original design\nis retained in [ARCHITECTURE.initial.md](ARCHITECTURE.initial.md). This document describes the\nimplemented design;', 'The stage sequence and generic fixes\nare recorded in [reports/development-findings.md](reports/development-findings.md). This document\ndescribes the implemented design;');open(p,'w').write(s) PY cat >> test/test_contracts_provenance.py <<'EOF' def test_forwarded_interfaces_discharge_after_scope_construction(): from hearth.kernel import Choice later=Assembly('later',Box((0,0,0),(0,0,0)),(Child('solid',Volume(Box((0,0,0),(0,0,0)),state_of('stone'))),),ports=(Port('access','access',Frame(),Box((0,0,0),(0,0,0))),)) choice=Choice('first',(Child('one',Volume(Box((0,0,0),(0,0,0)),state_of('stone'))),Child('two',Volume(Box((1,0,0),(1,0,0)),state_of('stone')))),lambda v,p:0) wrapper=Assembly('wrapper',Box((0,0,0),(3,1,1)),(choice,Child('later',later,frame=Frame((3,0,0)))),ports=(Port('access','access',Frame((3,0,0)),Box((3,0,0),(3,0,0)),delegate=('later','access')),)) s=Scene();s.place('root',wrapper);s.finalize() assert s.view.port('/root','access').frame.origin==(3,0,0) EOF yapf -i hearth/kernel/validation.py test/test_contracts_provenance.py python -m pytest -q test/test_contracts_provenance.py test/test_kernel.py python generate.py
........................ [100%] 24 passed in 0.42s Validated 5 buildings, 125476 blocks, 783 components. output.litematic | semantic SHA256 a247e5b44a194d17c4ba98a29ea37c372253e5be3e1c6356dee50983aea4f345
5604
python - <<'PY' p='hearth/adapters/site.py';s=open(p).read().replace(' excavation_volume: int = 300',' excavation_volume: int = 300\n bed_thi
python - <<'PY' p='hearth/adapters/site.py';s=open(p).read().replace(' excavation_volume: int = 300',' excavation_volume: int = 300\n bed_thickness: int = 2') s=s.replace(' samples[(x, z)] =', " if obs.support_depth<limits.bed_thickness:\n raise ContractError('substrate-depth',ctx.path,(wx,obs.elevation,wz),f'Require {limits.bed_thickness} contiguous solid bed cells, found {obs.support_depth}')\n samples[(x, z)] =",1) s=s.replace(' supports.append((x, bed, z))',' supports.extend((x,bed-k,z) for k in range(self.limits.bed_thickness))') s=s.replace("[(x, bed, z) for x, bed, z, top in columns]", "[(x,bed-self.limits.bed_thickness+1,z) for x,bed,z,top in columns]") open(p,'w').write(s) p='hearth/components/building.py';s=open(p).read().replace('min(minimum, 0)', 'min(minimum-self.site_limits.bed_thickness+1,0)');open(p,'w').write(s) PY cat >> test/test_geometry_environment.py <<'EOF' def test_actual_subsurface_support_not_just_height(): domain=Box((-8,-4,-18),(28,55,28));s=Scene(0,domain=domain) s.place('ground',Terrain(domain,constant(4))) s.place('local-cavity',Volume(Box((2,3,2),(2,3,2)),state_of('air'),'siteworks'),bindings=(Binding('/ground','construction','excavate'),)) assert s.view.elevation(2,2)==4 and s.view.sample(2,2).support_depth==1 before=semantic_digest(s) with pytest.raises(ContractError,match='substrate-depth'): s.place('house',Building(Blueprint((RoomSpec(0,0,0,'living'),)),'/ground')) assert semantic_digest(s)==before EOF yapf -i hearth/adapters/site.py hearth/components/building.py test/test_geometry_environment.py python -m pytest -q test/test_geometry_environment.py -k 'actual_subsurface or environment_dependency or complete_settlement'
... [100%] 3 passed, 104 deselected in 4.57s
5700
sed -n '1,95p' hearth/components/landscape.py && sed -n '1,65p' hearth/adapters/site.py
sed -n '1,95p' hearth/components/landscape.py && sed -n '1,65p' hearth/adapters/site.py
lse v[0]) for v in samples.values()) floor = surface + 1 if floor - min(heights) > limits.support_height: raise ContractError('support-height', ctx.path, ctx.frame.origin, 'Bounded support depth exceeded') wet = any(v[1] is not None and v[1] >= v[0] for v in samples.values()) strategies = ['piers'] if wet or relief >= 3 else ['stepped', 'piers'] strategy = ctx.scope.choose(strategies, 'adaptation') return {'floor': floor, 'relief': relief, 'wet': wet, 'strategy': strategy, 'samples': samples, 'feasible_strategies': strategies} @dataclass(frozen=True) class Foundation: footprint: tuple[tuple[int, int], ...] floor: int strategy: str limits: SiteLimits = SiteLimits() def capability(self): return Capability('adapter.foundation', ('siteworks', 'support'), offers=('support',), assumptions=('actual bed within bounded depth',), adaptations=('stepped perimeter', 'piers to bed'), guarantees=('grounded support grid',)) def negotiate(self, ctx, parameters): positions = set(self.footprint) supports = [] columns = [] for x, z in sorted(positions): boundary = any((x + dx, z + dz) not in positions for dx, dz in ((1, 0), (-1, 0), (0, 1), (0, -1))) grid = (x % 4 == 0 and z % 4 == 0) # Piers include perimeter every third cell and all corners. edge_pier = boundary and (x % 3 == 0 or z % 3 == 0 or sum((x + dx, z + dz) not in positions for dx, dz in ((1, 0), (-1, 0), (0, 1), (0, -1))) >= 2) if not (grid or (boundary if self.strategy == 'stepped' else edge_pier)): continue wx, _, wz = ctx.world((x, 0, z)) bed = ctx.view.elevation(wx, wz) - ctx.frame.origin[1] if self.floor - bed > self.limits.support_height: raise ContractError('support-height', ctx.path, ctx.world((x, bed, z))) supports.extend((x, bed - k, z) for k in range(self.limits.bed_thickness))
58049
python - <<'PY' p='hearth/components/landscape.py';s=open(p).read();a=s.index(' line = [(v, z)');b=s.index(' return sorted(points)',
python - <<'PY' p='hearth/components/landscape.py';s=open(p).read();a=s.index(' line = [(v, z)');b=s.index(' return sorted(points)',a) s=s[:a]+''' offsets=range(-(self.width//2),self.width//2+1) if x!=xx: for px in range(x,xx+dx,dx): for offset in offsets:points.add((px,z+offset)) if z!=zz: for pz in range(z,zz+dz,dz): for offset in offsets:points.add((xx+offset,pz)) if x==xx and z==zz: for ox in offsets: for oz in offsets:points.add((x+ox,z+oz)) ''' +s[b:];open(p,'w').write(s) p='hearth/programs.py';s=open(p).read().replace('links.append((len(points) - 1, 1))','links.append((1,len(points)-1))');open(p,'w').write(s) p='GENERATOR.md';s=open(p).read().replace('bed-to-floor support height at most **8**, approach','bed-to-floor support height at most **8**, at least **two contiguous solid bed cells**, approach');open(p,'w').write(s) PY cat >> test/test_geometry_environment.py <<'EOF' def test_path_endpoint_respects_host_authority(): from hearth.components.landscape import PathNetwork from hearth.components.primitives import Assembly domain=Box((-4,-3,-4),(12,20,12));s=Scene(0,domain=domain) s.place('ground',Terrain(domain,constant(0))) # An unrelated solid host behind the offered endpoint must survive path widening. s.place('behind',Volume(Box((-1,1,-1),(-1,1,1)),state_of('stone'))) s.place('route',PathNetwork(((0,1,0),(8,1,0)),((0,1),)),bindings=(Binding('/ground','construction','surface'),)) assert s.cells('/behind')=={(-1,1,-1),(-1,1,0),(-1,1,1)} s.finalize() EOF yapf -i hearth/components/landscape.py hearth/programs.py test/test_geometry_environment.py python -m pytest -q test/test_geometry_environment.py -k 'path_endpoint or settlement_corpus'
........... [100%] 11 passed, 97 deselected in 49.48s
59098
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace(' instances: int = 10000',' instances: int = 10000\n export_volume: int =
python - <<'PY' p='hearth/kernel/scene.py';s=open(p).read().replace(' instances: int = 10000',' instances: int = 10000\n export_volume: int = 16000000');open(p,'w').write(s) p='hearth/persistence.py';s=open(p).read();needle=" raise ContractError('export-bounds', conditions=str(bounds))";s=s.replace(needle,needle+"\n if bounds.volume>scene.limits.export_volume:\n raise ContractError('export-volume',conditions=f'{bounds.volume} > {scene.limits.export_volume}')");open(p,'w').write(s) p='ARCHITECTURE.md';s=open(p).read().replace('search alternatives. Demo count','search alternatives, with at most 16,000,000 cells in the dense export bounding box. Demo count');open(p,'w').write(s) p='GENERATOR.md';s=open(p).read().replace('block count, instances, recursion and candidate budget.','block count, instances, recursion, candidate budget and dense export volume.');open(p,'w').write(s) PY cat >> test/test_contracts_provenance.py <<'EOF' def test_dense_export_budget_is_explicit(work): s=Scene(limits=Limits(export_volume=10)) s.place('line',Volume(Box((0,0,0),(10,0,0)),state_of('stone'))) with pytest.raises(ContractError,match='export-volume'):export_scene(s,work/'too large.litematic') assert not (work/'too large.litematic').exists() EOF cat > examples/verify_replay.py <<'EOF' # Explicit cross-process hash-seed replay and paired metadata verification. import argparse import json import os from pathlib import Path import subprocess import sys import tempfile from hearth.persistence import load_scene,semantic_digest from hearth.space import Box def verify(seed,output): root=Path(__file__).resolve().parents[1] rows=[] with tempfile.TemporaryDirectory(dir=root/'test',prefix='tmp-replay-') as temporary: for hash_seed in ('3','8675309'): path=Path(temporary)/f'seed {seed} hash {hash_seed}.litematic' env=dict(os.environ,PYTHONHASHSEED=hash_seed) subprocess.run([sys.executable,str(root/'generate.py'),'--seed',str(seed),'--output',str(path)],check=True,cwd=root,env=env) scene=load_scene(path) rows.append({'seed':seed,'PYTHONHASHSEED':hash_seed,'digest':semantic_digest(scene),'bounds':[Box.enclosing(scene.blocks).lo,Box.enclosing(scene.blocks).hi],'blocks':len(scene.blocks),'buildings':sum(n.type=='building.rooms' for n in scene.nodes.values())}) if rows[0]['digest']!=rows[1]['digest'] or rows[0]['bounds']!=rows[1]['bounds']: raise AssertionError('Cross-process replay mismatch') output.parent.mkdir(parents=True,exist_ok=True) output.write_text(json.dumps({'verified':True,'runs':rows},indent=2)) return rows if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--seed',type=int,default=0);p.add_argument('--output',type=Path,default=Path('reports/replay.json'));a=p.parse_args();verify(a.seed,a.output) EOF yapf -i hearth/kernel/scene.py hearth/persistence.py test/test_contracts_provenance.py examples/verify_replay.py python -m pytest -q test > reports/pytest-final.txt
6000
tail -5 reports/pytest-final.txt && tail -5 reports/assessment-final.txt
tail -5 reports/pytest-final.txt && tail -5 reports/assessment-final.txt
........................................................................ [ 54%] ............................................................. [100%] 133 passed in 97.89s (0:01:37) settlement-0-seeded validated settlement-1-seeded validated settlement-2-seeded validated settlement-3-seeded validated settlement-4-seeded validated
610141
python -m examples.assess --seed 0 --output reports/final-corpus --artifacts > reports/assessment-final.txt
python -m examples.assess --seed 0 --output reports/final-corpus --artifacts > reports/assessment-final.txt
6200
sed -n '1,160p' /opt/tools/cutaway.py && python - <<'PY' import json,hashlib from pathlib import Path root=Path.cwd();manifest=json.loads((root/'refer
sed -n '1,160p' /opt/tools/cutaway.py && python - <<'PY' import json,hashlib from pathlib import Path root=Path.cwd();manifest=json.loads((root/'references/manifest.json').read_text());results=[] for item in manifest['files']: path=(root/item['path']).resolve() if not path.is_relative_to(root):raise ValueError('Reference outside workspace') actual=hashlib.sha256(path.read_bytes()).hexdigest() results.append({'path':item['path'],'matches':actual==item['sha256']}) assert all(r['matches'] for r in results) (root/'reports/reference-integrity.json').write_text(json.dumps({'verified':len(results),'files':results},indent=2)) print('Reference hashes verified:',len(results)) PY
if state.split("[")[0] in AIR: continue target = {"y": y, "z": z, "x": x} target[axis] = index - lower canvas.block((target["y"], target["z"], target["x"]), parse_blockstate(state)) schematic = canvas.to_litematica(name=name, author="cutaway", description=f"{source.name} {axis}<={cut}", minecraft_data_version=source_data_version(source)) # Deterministic output: the schematic metadata otherwise records the current wall clock. schematic.metadata.time_created = 0 schematic.metadata.time_modified = 0 schematic.save(destination) def main(argv: Optional[list] = None) -> None: """Run one slice export. Args: argv (Optional[list]): Command line arguments, defaulting to sys.argv. """ parser = argparse.ArgumentParser(description="Slice a schematic so its interior can be rendered.") parser.add_argument("--input", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) parser.add_argument("--axis", choices=("x", "y", "z"), default="y") parser.add_argument("--max", dest="limit", type=int, default=None, help="Last index to keep along the axis.") parser.add_argument("--max-y", dest="max_y", type=int, default=None, help="Shorthand for --axis y --max N.") parser.add_argument("--keep-above", action="store_true", help="Keep the far side of the cut instead.") parser.add_argument("--name", default="slice") args = parser.parse_args(argv) axis = "y" if args.max_y is not None else args.axis limit = args.max_y if args.max_y is not None else args.limit if limit is None: parser.error("give --max N (with --axis) or --max-y N") slice_schematic(args.input, args.output, axis, limit, args.keep_above, args.name) side = "above" if args.keep_above else "up to" print(f"wrote {args.output} ({side} {axis}={limit})") if __name__ == "__main__": main() Reference hashes verified: 32
63054
python generate.py python generate.py --seed 0 --output example.litematic python generate.py --seed 1 --output samples/harness-seed-1.litematic python
python generate.py python generate.py --seed 0 --output example.litematic python generate.py --seed 1 --output samples/harness-seed-1.litematic python -m examples.verify_replay --seed 0 --output reports/replay.json
Validated 5 buildings, 125475 blocks, 782 components. output.litematic | semantic SHA256 e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9 Validated 5 buildings, 125475 blocks, 782 components. example.litematic | semantic SHA256 e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9 Validated 3 buildings, 90100 blocks, 527 components. samples/harness-seed-1.litematic | semantic SHA256 59aa67be3d333173651d8f3af577d2a0e9f24ca4db341ecc424a2f2be830b2d3 Validated 5 buildings, 125475 blocks, 782 components. /work/generator/workspace/test/tmp-replay-lcqouyaf/seed 0 hash 3.litematic | semantic SHA256 e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9 Validated 5 buildings, 125475 blocks, 782 components. /work/generator/workspace/test/tmp-replay-lcqouyaf/seed 0 hash 8675309.litematic | semantic SHA256 e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9
6401
python - <<'PY' p='hearth/components/primitives.py';s=open(p).read();old="frame = tuple((x, y, z) for x in (0, w - 1) for y in range(h) for z in range
python - <<'PY' p='hearth/components/primitives.py';s=open(p).read();old="frame = tuple((x, y, z) for x in (0, w - 1) for y in range(h) for z in range(t))";new="frame = tuple((x, y, z) for x in (0, w - 1) for y in range(-1,h) for z in range(t))";s=s.replace(old,new);open(p,'w').write(s) p='hearth/adapters/site.py';s=open(p).read();needle=" def capability(self):\n return Capability('adapter.foundation'";i=s.index(needle);s=s[:i]+''' @classmethod def rectangular(cls,width,depth,floor,strategy='stepped',limits=SiteLimits()): """Create a rectangular contact component without client voxel operations.""" if width<1 or depth<1:raise ValueError('Positive footprint dimensions required') return cls(tuple((x,z) for x in range(width) for z in range(depth)),floor,strategy,limits) ''' +s[i:];open(p,'w').write(s) p='examples/prototype.py';s=open(p).read().replace('from hearth.components.primitives import Wall, Window, Grass, Tree','from hearth.components.primitives import Wall, Window, Grass, Tree\nfrom hearth.adapters.site import Foundation') s=s.replace(" scene.place('facade',", " scene.place('footing',Foundation.rectangular(9,2,4),bindings=(Binding('/land','construction','fill'),))\n scene.place('facade',") open(p,'w').write(s) p='test/test_kernel.py';s=open(p).read().replace("children = (Child('wall', Wall(), frame=Frame((0, 1, 0))),", "children = (Child('base',Volume(Box((0,0,0),(8,0,0)),state_of('stone'))),Child('wall', Wall(), frame=Frame((0, 1, 0))),") s=s.replace("Assembly('room', Box((-1, 0, -2), (10, 8, 3)), (Child('wall', Wall()),", "Assembly('room', Box((-1, -1, -2), (10, 8, 3)), (Child('base',Volume(Box((0,-1,0),(8,-1,0)),state_of('stone'))),Child('wall', Wall()),") open(p,'w').write(s) p='test/test_contracts_provenance.py';s=open(p).read();s=s.replace("Plan(children=[Child('wall', Wall(thickness=3)),", "Plan(children=[Child('base',Volume(Box((0,-1,0),(8,-1,2)),state_of('stone'))),Child('wall', Wall(thickness=3)),") s=s.replace("Assembly('house', Box((-2, 0, -2), (12, 8, 5)), (Child('wall', Wall()),))", "Assembly('house',Box((-2,-1,-2),(12,8,5)),(Child('base',Volume(Box((0,-1,0),(8,-1,0)),state_of('stone'))),Child('wall',Wall())))") open(p,'w').write(s) PY yapf -i hearth/components/primitives.py hearth/adapters/site.py examples/prototype.py test/test_kernel.py test/test_contracts_provenance.py python -m pytest -q test/test_kernel.py test/test_contracts_provenance.py python -m examples.prototype --seed 0
......................... [100%] 25 passed in 0.45s
6500
tail -74 reports/assessment-final.txt && cat reports/replay.json
tail -74 reports/assessment-final.txt && cat reports/replay.json
: 128, "accepted_candidates": 84, "retries": 0, "seconds": 33.13, "observed_principal_signatures": 3, "observed_contact_signatures": 44, "fill_range": [ 0, 159 ] }, "buildings": { "inputs": 24, "validated": 24, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 48, "accepted_candidates": 48, "retries": 0, "seconds": 22.308, "observed_principal_signatures": 18, "observed_contact_signatures": 24, "fill_range": [ 0, 70 ] }, "settlements": { "inputs": 10, "validated": 10, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 80, "accepted_candidates": 80, "retries": 0, "seconds": 65.996, "observed_principal_signatures": 10, "observed_contact_signatures": 10, "fill_range": [ 16, 216 ] }, "stress": { "inputs": 32, "validated": 9, "incompatible": 23, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 64, "accepted_candidates": 11, "retries": 0, "seconds": 13.593, "observed_principal_signatures": 4, "observed_contact_signatures": 9, "fill_range": [ 40, 174 ] } } { "verified": true, "runs": [ { "seed": 0, "PYTHONHASHSEED": "3", "digest": "e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9", "bounds": [ [ -49, -4, -23 ], [ 49, 32, 104 ] ], "blocks": 125475, "buildings": 5 }, { "seed": 0, "PYTHONHASHSEED": "8675309", "digest": "e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9", "bounds": [ [ -49, -4, -23 ], [ 49, 32, 104 ] ], "blocks": 125475, "buildings": 5 } ] }
66021
cat >> test/test_geometry_environment.py <<'EOF' def test_upper_room_bay_boundary_with_vertical_circulation(): design=Blueprint((RoomSpec(0,0,0,
cat >> test/test_geometry_environment.py <<'EOF' def test_upper_room_bay_boundary_with_vertical_circulation(): design=Blueprint((RoomSpec(0,0,0,'living'),RoomSpec(0,0,1,'bedroom')),bay=13) s=building_scene(design,5,gradient(base=4),6) assert s.completed and s.nodes['/building'].contract.decisions['bay']==13 assert s.nodes['/building/room-0-0-0/stairs'].contract.rules EOF cat > hearth/components/__init__.py <<'EOF' # Public architectural components and their explicit intent records. from .building import Blueprint, Building, RoomSpec, adapted from .interior import Room, Light, Furniture, Door, Stair from .primitives import Wall, Window, Tree, Grass, Pool, Assembly EOF cat > examples/preview.py <<'EOF' # Render labeled exterior views and geometry-only slices with the optional proc tools. import argparse import json from pathlib import Path import subprocess import sys from hearth.persistence import export_scene,load_scene,companion_path from hearth.programs import settlement_scene RENDER=Path('/opt/tools/render_schematic.mjs') CUTAWAY=Path('/opt/tools/cutaway.py') VITE=Path('/work/generator/MCRender/node_modules/.bin/vite-node') def render(source,target,azimuth,elevation,size,radius): subprocess.run(['xvfb-run','-a',str(VITE),'--script',str(RENDER),'--','--input',str(source),'--output',str(target),'--size',str(size),'--azimuth',str(azimuth),'--elevation',str(elevation),'--radius',str(radius),'--fov','30','--ambient','0.8'],check=True) def preview(seed,source,output,size=1200,cutaways=False): output.mkdir(parents=True,exist_ok=True) if source is None: source=output/'source.litematic' export_scene(settlement_scene(seed),source) scene=load_scene(source) if scene.seed!=seed: raise ValueError(f'--seed {seed} does not match the input artifact seed {scene.seed}') views=[('front',210,28,3.5),('rear',30,26,3.5)] records=[] for label,azimuth,elevation,radius in views: target=output/(label+'.png');render(source,target,azimuth,elevation,size,radius) records.append({'source':str(source),'seed':seed,'label':label,'image':str(target),'azimuth':azimuth,'elevation':elevation}) if cutaways: building=next(n for n in scene.nodes.values() if n.type=='building.rooms') floor=building.contract.decisions['floor']+building.frame.origin[1] offset=json.loads(companion_path(source).read_text())['offset'] cuts=[('floor-cut','y',floor+4-offset[1],210,64),('stair-cut','x',building.frame.origin[0]+building.contract.decisions['bay']-2-offset[0],110,26)] for label,axis,limit,azimuth,elevation in cuts: cut=output/(label+'.litematic') subprocess.run([sys.executable,str(CUTAWAY),'--input',str(source),'--output',str(cut),'--axis',axis,'--max',str(limit),'--name',label],check=True) target=output/(label+'.png');render(cut,target,azimuth,elevation,size,3.2) records.append({'source':str(source),'seed':seed,'label':label,'axis':axis,'export_local_cut':limit,'image':str(target),'geometry_preview_only':True}) (output/'views.json').write_text(json.dumps(records,indent=2)) if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--seed',type=int,default=0);p.add_argument('--input',type=Path);p.add_argument('--output',type=Path,default=Path('previews/default'));p.add_argument('--size',type=int,default=1200);p.add_argument('--cutaways',action='store_true');a=p.parse_args();preview(a.seed,a.input,a.output,a.size,a.cutaways) EOF yapf -i test/test_geometry_environment.py examples/preview.py hearth/components/__init__.py python -m pytest -q test/test_geometry_environment.py -k upper_room_bay python generate.py python -m examples.preview --seed 0 --input output.litematic --output previews/settlement --size 1500
s Validated 5 buildings, 125475 blocks, 782 components. output.litematic | semantic SHA256 e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9 parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! Using WebGL2 context for WebGL requests instead of WebGL Loaded structure from /work/generator/workspace/output.litematic in 165 ms Set structure in renderer in 1719 ms Rendering output at azimuth 0 (1/1)... Rendered image in 118 ms (azimuth: 3.6651914291880923, elevation: 0.4886921905584123) wrote /work/generator/workspace/previews/settlement/front.png (1500x1500, azimuth 210, elevation 28) parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! parent minecraft:builtin/entity does not exist! Using WebGL2 context for WebGL requests instead of WebGL Loaded structure from /work/generator/workspace/output.litematic in 163 ms Set structure in renderer in 1667 ms Rendering output at azimuth 0 (1/1)... Rendered image in 116 ms (azimuth: 0.5235987755982988, elevation: 0.4537856055185257) wrote /work/generator/workspace/previews/settlement/rear.png (1500x1500, azimuth 30, elevation 26)
67097
python -m pytest -q test > reports/pytest-final.txt
python -m pytest -q test > reports/pytest-final.txt
680140
python -m examples.assess --seed 0 --output reports/final-corpus --artifacts > reports/assessment-final.txt
python -m examples.assess --seed 0 --output reports/final-corpus --artifacts > reports/assessment-final.txt
6900
tail -n 6 reports/pytest-final.txt cat reports/assessment-final.txt
tail -n 6 reports/pytest-final.txt cat reports/assessment-final.txt
stress-06 incompatible stress-07 incompatible stress-08 incompatible stress-09 validated stress-10 incompatible stress-11 incompatible stress-12 incompatible stress-13 incompatible stress-14 validated stress-15 incompatible stress-16 incompatible stress-17 validated stress-18 validated stress-19 incompatible stress-20 validated stress-21 incompatible stress-22 validated stress-23 incompatible stress-24 incompatible stress-25 validated stress-26 validated stress-27 incompatible stress-28 incompatible stress-29 incompatible stress-30 incompatible stress-31 incompatible { "adaptation": { "inputs": 64, "validated": 64, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 128, "accepted_candidates": 84, "retries": 0, "seconds": 32.777, "observed_principal_signatures": 3, "observed_contact_signatures": 44, "fill_range": [ 0, 159 ] }, "buildings": { "inputs": 24, "validated": 24, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 48, "accepted_candidates": 48, "retries": 0, "seconds": 22.288, "observed_principal_signatures": 18, "observed_contact_signatures": 24, "fill_range": [ 0, 70 ] }, "settlements": { "inputs": 10, "validated": 10, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 80, "accepted_candidates": 80, "retries": 0, "seconds": 65.221, "observed_principal_signatures": 10, "observed_contact_signatures": 10, "fill_range": [ 16, 216 ] }, "stress": { "inputs": 32, "validated": 9, "incompatible": 23, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 64, "accepted_candidates": 11, "retries": 0, "seconds": 13.515, "observed_principal_signatures": 4, "observed_contact_signatures": 9, "fill_range": [ 40, 174 ] } }
7000
rg --files reports previews test examples | sort
rg --files reports previews test examples | sort
tyard.cpython-312.pyc examples/__pycache__/extension.cpython-312.pyc examples/__pycache__/gallery.cpython-312.pyc examples/__pycache__/inspection.cpython-312.pyc examples/__pycache__/preview.cpython-312.pyc examples/__pycache__/prototype.cpython-312.pyc examples/__pycache__/verify_replay.cpython-312.pyc examples/assess.py examples/building.py examples/courtyard.py examples/extension.py examples/gallery.py examples/inspection.py examples/preview.py examples/prototype.py examples/verify_replay.py previews/development-house.camera.json previews/development-house.png previews/settlement-first.camera.json previews/settlement-first.png previews/settlement/front.camera.json previews/settlement/front.png previews/settlement/rear.camera.json previews/settlement/rear.png previews/settlement/views.json reports/assessment-final.txt reports/baseline-corpus/adaptation-inputs.json reports/baseline-corpus/results.json reports/baseline-corpus/summary.json reports/corpus/adaptation-inputs.json reports/corpus/results.json reports/corpus/summary.json reports/dependencies.json reports/final-corpus/adaptation-inputs.json reports/final-corpus/results.json reports/final-corpus/summary.json reports/inspection.txt reports/phase-regression/pytest-final.txt reports/phase-regression/results.json reports/phase-regression/summary.json reports/pytest-final.txt reports/reference-integrity.json reports/replay.json reports/sampling-policy.json test/__pycache__/conftest.cpython-312-pytest-9.1.1.pyc test/__pycache__/conftest.cpython-312.pyc test/__pycache__/test_contracts_provenance.cpython-312-pytest-9.1.1.pyc test/__pycache__/test_contracts_provenance.cpython-312.pyc test/__pycache__/test_geometry_environment.cpython-312-pytest-9.1.1.pyc test/__pycache__/test_geometry_environment.cpython-312.pyc test/__pycache__/test_kernel.cpython-312-pytest-9.1.1.pyc test/__pycache__/test_kernel.cpython-312.pyc test/conftest.py test/test_contracts_provenance.py test/test_geometry_environment.py test/test_kernel.py
7100
cat GENERATOR.md
cat GENERATOR.md
ervative; no implicit arbitrary auto-replan | | R20 | SHA-256 scope keys/purposes, overrides, copied environments; branch/order/retry and hash-seed replay tests | Genuine spatial dependencies may change descendants | | R21 | Configurable `Limits`, `SiteLimits`, effect envelopes and realized export bounds | Demonstration count bound is only in the CLI | | R22 | Initial design, kernel tests, prototype, buildings/extension, corpus/render stages | Generic defects and fixes recorded in development findings | | R23 | `test_kernel`, `test_contracts_provenance`: substitution, independent extension, authority, rollback, sharing, transforms, seeds | Custom validator registration also tested | | R24 | Glass chain, two identities, external attachment membership, updates/deletions/regeneration, shared cells, transport mismatch tests | Actual structure restored from companion, not inferred from materials | | R25 | 64 frozen pairings, compatible independent field/environment, protected outside cells, perturbation and stress records | Finite supported domain; 32 stress inputs retained without resampling | | R26 | Three short clients x eight seeds; settlement x eight seeds plus counts 3 and 6; later courtyard/gallery | Programs use public room/component APIs | | R27 | Actual blocks/NBT: schema, support, headroom/routes, pair consistency, enclosure, lights, furnishings, pools and path joins; deliberate damage tests | Physical/lighting model limitations above apply | | R28 | Structural/contact signatures, exterior views, circulation/furnishing cutaways, inspection notes | Modular aesthetic remains visible; no exhaustive beauty claim | | R29 | `generate.py`, importable scene builders, inspection example, verified one-region transport | Offline runtime uses bundled schema and installed/provided MCIO | | R30 | Library, docs, CLI, tests, extension, output pair, manifest, reports and labeled previews | Broader simulation, arbitrary entities, browser UI and city planner remain unfinished |
7200
cat examples/preview.py cat samples/replay-manifest.json
cat examples/preview.py cat samples/replay-manifest.json
c58b481fe9beb389f4889f3e467e9d2f", "status": "validated" }, { "artifact": "samples/atelier-1.litematic", "inputs": { "program": "atelier", "seed": 1 }, "digest": "2c618298e44b80076d55170f85bf4ce5e868c3c5ad8a2561b39586449752edbf", "status": "validated" }, { "artifact": "samples/atelier-6.litematic", "inputs": { "program": "atelier", "seed": 6 }, "digest": "5abd655c4bcb521f626a049cf7194a7de48f7bd0564cef9c09d0d774ff7c1771", "status": "validated" }, { "artifact": "samples/commons-0.litematic", "inputs": { "program": "commons", "seed": 0 }, "digest": "bc4f40fb526850968efd7da87830b5483e8f908c740c5c8dd9ee4532fc053b36", "status": "validated" }, { "artifact": "samples/commons-1.litematic", "inputs": { "program": "commons", "seed": 1 }, "digest": "8822663aa5b6881c5d3abeb63cde45a698ee2ae5eec1bb32bc9682eac592e939", "status": "validated" }, { "artifact": "samples/commons-6.litematic", "inputs": { "program": "commons", "seed": 6 }, "digest": "8c5eefc70effe4a689bc5d027bb64885f1cb85cf45ae955e91e4390034654898", "status": "validated" }, { "artifact": "samples/settlement-1-seeded.litematic", "inputs": { "program": "settlement", "seed": 1, "count": null }, "digest": "59aa67be3d333173651d8f3af577d2a0e9f24ca4db341ecc424a2f2be830b2d3", "status": "validated" }, { "artifact": "samples/settlement-0-3.litematic", "inputs": { "program": "settlement", "seed": 0, "count": 3 }, "digest": "dac1f641e1ef26ddef201176065c7016b1cda048616feb4cb5774d9a97b3eb9d", "status": "validated" }, { "artifact": "samples/settlement-0-6.litematic", "inputs": { "program": "settlement", "seed": 0, "count": 6 }, "digest": "570364443fe2cb60745267ef0dfe24feb1c8ccb8f2bdbbe8f69e173b79354cd1", "status": "validated" } ]
7307
python -m examples.preview --seed 6 --input samples/commons-6.litematic --output previews/commons-6 --size 1000 --cutaways > reports/render-commons-6.
python -m examples.preview --seed 6 --input samples/commons-6.litematic --output previews/commons-6 --size 1000 --cutaways > reports/render-commons-6.txt
7400
cat examples/extension.py cat examples/courtyard.py cat examples/gallery.py cat reports/final-corpus/summary.json
cat examples/extension.py cat examples/courtyard.py cat examples/gallery.py cat reports/final-corpus/summary.json
3)) rooms = [RoomSpec(0, z, 0, 'library' if z % 2 else 'living') for z in range(length)] rooms.append(RoomSpec(1, length - 1, 0, 'workshop')) rooms.append(RoomSpec(0, length - 1, 1, 'bedroom')) return building_scene(Blueprint(tuple(rooms), bay=9, roof_axis='z', light_component=Pendant()), seed) if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('samples/gallery.litematic')) a = p.parse_args() export_scene(build(a.seed), a.output) { "adaptation": { "inputs": 64, "validated": 64, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 128, "accepted_candidates": 84, "retries": 0, "seconds": 32.777, "observed_principal_signatures": 3, "observed_contact_signatures": 44, "fill_range": [ 0, 159 ] }, "buildings": { "inputs": 24, "validated": 24, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 48, "accepted_candidates": 48, "retries": 0, "seconds": 22.288, "observed_principal_signatures": 18, "observed_contact_signatures": 24, "fill_range": [ 0, 70 ] }, "settlements": { "inputs": 10, "validated": 10, "incompatible": 0, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 80, "accepted_candidates": 80, "retries": 0, "seconds": 65.221, "observed_principal_signatures": 10, "observed_contact_signatures": 10, "fill_range": [ 16, 216 ] }, "stress": { "inputs": 32, "validated": 9, "incompatible": 23, "defects": 0, "budget_exhausted": 0, "candidate_attempts": 64, "accepted_candidates": 11, "retries": 0, "seconds": 13.515, "observed_principal_signatures": 4, "observed_contact_signatures": 9, "fill_range": [ 40, 174 ] } }
7500
cat examples/prototype.py cat examples/inspection.py cat reports/sampling-policy.json
cat examples/prototype.py cat examples/inspection.py cat reports/sampling-policy.json
t) restored = load_scene(output) assert restored.inspect(point) == query print('Reloaded query identical; world coordinate:', point) return query if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('samples/inspection.litematic')) a = p.parse_args() demonstrate(a.seed, a.output) { "version": 1, "frozen_before_evaluation": true, "adaptation_count": 64, "environment_seeds": [0, 15], "building_seeds": [0, 3], "pairing": "Cartesian product of 16 independent environmental seeds and four independent building seeds. First eight environment seeds are development compositions; last eight use a previously unused field blend and transform.", "satisfiable_domain": {"gradient_per_block": [-0.045, 0.045], "wave_amplitude": [0, 0.8], "radial_amplitude": [0, 0.7], "base": 4, "water_level": [null, 5, 6], "height_clamp": [2, 7], "room_bay": [9, 11], "site_relief_max": 5, "post_height_max": 8, "approach_length_max": 12}, "stress_count": 32, "stress_policy": "Retain every input. Independent expression seed 1000+i, slopes through 0.45, amplitudes through 5, optional high water. No rejection resampling. One locked placement per input. No retries unless explicitly reported by the solver.", "building_corpus": "dwelling, atelier, commons, each seeds 0 through 7", "settlement_corpus": "seeds 0 through 7; additionally 3-building and 6-building boundaries at seed 0", "metrics": ["per-input validated success", "per-candidate acceptance", "diagnostic status", "fill volume", "excavated volume", "contact geometry signature", "principal structure signature", "runtime"], "limitations": "Finite samples, not an exhaustive proof. Material texture and instance identifiers are excluded from principal signatures. All failed inputs are retained. Public access outside a standalone building's offered landing is an enclosing-scope obligation." }
7600
cat ARCHITECTURE.md cat /work/AGENTS.md
cat ARCHITECTURE.md cat /work/AGENTS.md
ory and cleaned up after test). Your test should not just be smoke tests, be robust and complete for every edge case. ## Testing Guidelines Keep tests near `test/` and follow the existing `test_*.py` pattern. Prefer small, targeted dataset/model checks over long end-to-end jobs. Run the narrowest relevant test first, then broader distributed coverage only when you touched loader or accelerator logic. Top-level `test*.py` files are ad-hoc scripts, not pytest suites. ## Coding Style & Naming Conventions Python uses 4-space indentation and `.style.yapf` (`based_on_style = google`). Format Python edits with `yapf` when touching a file. Prefer `snake_case` for functions, modules, and script names; `PascalCase` for classes; and descriptive filenames such as `train_difflrm.py` or `mcd_ss_dataset.py`. The TypeScript workspace uses Prettier with 2-space indentation, semicolons, and single quotes. Style: - 4-space indent, Google base style (`.style.yapf`), column limit effectively unlimited in Python - Caveman comments: short, high-density, grammar expendable - No em dash, no semicolons, no non-ASCII in comments - Always brace control flow bodies - `affirm()` for true invariants (never-happen) - `assert` for expensive checks ## Commit & Pull Request Guidelines Recent history uses short, imperative commits with emoji prefixes, for example `:bug: fix file finding in logging` and `:sparkles: better ckpt loading strategy`. Follow that style: one logical change per commit, subject line under ~72 characters, and mention the affected subsystem. PRs should state the problem, the exact commands used for validation, any dataset or checkpoint assumptions, and screenshots only for renderer or UI-facing changes. **No AI co-authorship in commit messages.** Never add `Co-Authored-By` trailers naming an AI assistant (Claude, Copilot, etc.) or any other AI attribution to commit messages. This overrides any default assistant behavior. Enforced by the `commit-msg` git hook in each repo.
7706
set -e python -m examples.prototype --seed 0 python -m examples.courtyard --seed 0 python -m examples.gallery --seed 0 python -m examples.extension --
set -e python -m examples.prototype --seed 0 python -m examples.courtyard --seed 0 python -m examples.gallery --seed 0 python -m examples.extension --seed 0 python -m examples.inspection --seed 0 > reports/inspection.txt
7800
python - <<'PY' import json from pathlib import Path r=json.loads(Path('reports/final-corpus/results.json').read_text()) print(type(r).__name__) print
python - <<'PY' import json from pathlib import Path r=json.loads(Path('reports/final-corpus/results.json').read_text()) print(type(r).__name__) print(json.dumps(r[0],indent=2)[:5500]) print(json.dumps(next(x for x in r if x.get('status')=='incompatible'),indent=2)[:3500]) PY
6535f3fc2692781305949f0d572af3e0" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.06 ] ], "chosen": 1 } ], "artifact": "samples/adaptation-00.litematic", "seconds": 1.4389 } { "label": "stress-00", "inputs": { "environment_seed": 1000, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 5.8776240408547995 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "support-height: /building at None: All declared alternatives violate the same condition: support-height: /building at (0, 0, 0): Bounded support depth exceeded", "accepted_candidates": 0, "candidates": [ { "rule": "support-height", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Bounded support depth exceeded" }, { "rule": "support-height", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Bounded support depth exceeded" } ], "seconds": 0.4137 }
7900
rg -n 'def contact|fill|excavation|def structure|signature|protected' hearth/assessment.py test/test_geometry_environment.py sed -n '1,215p' hearth/as
rg -n 'def contact|fill|excavation|def structure|signature|protected' hearth/assessment.py test/test_geometry_environment.py sed -n '1,215p' hearth/assessment.py
1000 + seed * 100 + i rng = Scope(es).stream('stress') expression = (gradient(rng.choice((0, .12, .28, .45)), rng.choice((0, -.15, .2)), 4) + wave(rng.choice((0, 2, 5)), .13, .17, rng.random() * 6)).clamp(-2, 20) water = rng.choice((None, 5, 12)) bs = i % 8 row = measured(f'stress-{i:02d}', lambda e=expression, w=water, b=bs: building_scene(PROGRAMS['dwelling'](b), b, e, w), {'environment_seed': es, 'building_seed': bs, 'expression': expression.expression(), 'water': water}) rows.append(row) print(row['label'], row['status'], flush=True) (output / 'results.json').write_text(json.dumps(rows, indent=2)) summary = {} for name, subset in [('adaptation', rows[:64]), ('buildings', rows[64:88]), ('settlements', rows[88:98]), ('stress', rows[98:])]: good = [r for r in subset if r['status'] == 'validated'] summary[name] = {'inputs': len(subset), 'validated': len(good), 'incompatible': sum(r['status'] == 'incompatible' for r in subset), 'defects': sum(r['status'] == 'defect' for r in subset), 'budget_exhausted': sum(r['status'] == 'budget-exhausted' for r in subset), 'candidate_attempts': sum(r['attempts'] for r in subset), 'accepted_candidates': sum(r['accepted_candidates'] for r in subset), 'retries': sum(r['retries'] for r in subset), 'seconds': round(sum(r['seconds'] for r in subset), 3), 'observed_principal_signatures': len({r['principal_signature'] for r in good}), 'observed_contact_signatures': len({r['contact']['signature'] for r in good}), 'fill_range': [min((r['contact']['fill'] for r in good), default=0), max((r['contact']['fill'] for r in good), default=0)]} (output / 'summary.json').write_text(json.dumps(summary, indent=2)) manifest = [{'artifact': r['artifact'], 'inputs': r['inputs'], 'digest': r['digest'], 'status': r['status']} for r in rows if 'artifact' in r] (Path('samples') / 'replay-manifest.json').write_text(json.dumps(manifest, indent=2)) return summary
8000
python - <<'PY' import json from collections import Counter from pathlib import Path r=json.loads(Path('reports/final-corpus/results.json').read_text(
python - <<'PY' import json from collections import Counter from pathlib import Path r=json.loads(Path('reports/final-corpus/results.json').read_text()) print('stress constraints',Counter(x.get('diagnostic','').split(':')[0] for x in r[98:] if x['status']!='validated')) for label,part in [('adaptation',r[:64]),('buildings',r[64:88]),('settlements',r[88:98]),('stress',r[98:])]: p=[x for x in part if x['status']=='validated'] print(label, {k:[min(x['contact'][k] for x in p),max(x['contact'][k] for x in p)] for k in ('fill','excavation','replaced_cells','new_sitework_cells','sitework_occupied_cells')},Counter(y for x in p for y in x['contact']['strategies'])) PY
stress constraints Counter({'site-relief': 21, 'support-height': 2}) adaptation {'fill': [0, 159], 'excavation': [0, 0], 'replaced_cells': [3, 168], 'new_sitework_cells': [3, 87], 'sitework_occupied_cells': [6, 171]} Counter({'piers': 46, 'stepped': 18}) buildings {'fill': [0, 70], 'excavation': [0, 0], 'replaced_cells': [1, 3], 'new_sitework_cells': [0, 73], 'sitework_occupied_cells': [3, 76]} Counter({'stepped': 18, 'piers': 6}) settlements {'fill': [16, 216], 'excavation': [0, 0], 'replaced_cells': [369, 797], 'new_sitework_cells': [19, 336], 'sitework_occupied_cells': [388, 1133]} Counter({'stepped': 23, 'piers': 17}) stress {'fill': [40, 174], 'excavation': [0, 0], 'replaced_cells': [3, 141], 'new_sitework_cells': [1, 199], 'sitework_occupied_cells': [51, 211]} Counter({'piers': 9})
8108
python -m examples.preview --seed 0 --input samples/adaptation-00.litematic --output previews/adaptation-00 --size 1000 --cutaways > reports/render-ad
python -m examples.preview --seed 0 --input samples/adaptation-00.litematic --output previews/adaptation-00 --size 1000 --cutaways > reports/render-adaptation-00.txt
8200
rg --files samples -g '*.litematic' | wc -l rg --files samples -g '*.litematic' | head -n 35
rg --files samples -g '*.litematic' | wc -l rg --files samples -g '*.litematic' | head -n 35
23 samples/gallery.litematic samples/courtyard.litematic samples/settlement-0-6.litematic samples/settlement-0-3.litematic samples/settlement-1-seeded.litematic samples/commons-6.litematic samples/commons-1.litematic samples/commons-0.litematic samples/atelier-6.litematic samples/atelier-1.litematic samples/atelier-0.litematic samples/dwelling-6.litematic samples/dwelling-1.litematic samples/dwelling-0.litematic samples/harness-seed-1.litematic samples/adaptation-60.litematic samples/adaptation-35.litematic samples/inspection.litematic samples/adaptation-08.litematic samples/adaptation-00.litematic samples/extension.litematic samples/development-house.litematic samples/prototype.litematic
83011
set -e python -m examples.preview --seed 1 --input samples/atelier-1.litematic --output previews/atelier-1 --size 1000 > reports/render-atelier-1.txt
set -e python -m examples.preview --seed 1 --input samples/atelier-1.litematic --output previews/atelier-1 --size 1000 > reports/render-atelier-1.txt python -m examples.preview --seed 0 --input samples/courtyard.litematic --output previews/courtyard-0 --size 1000 --cutaways > reports/render-courtyard-0.txt
84012
python - <<'PY' import json from pathlib import Path from hearth.persistence import load_scene,semantic_digest manifest=json.loads(Path('samples/repla
python - <<'PY' import json from pathlib import Path from hearth.persistence import load_scene,semantic_digest manifest=json.loads(Path('samples/replay-manifest.json').read_text()) extras=[('output.litematic',0,'python generate.py'),('example.litematic',0,'python generate.py --seed 0 --output example.litematic'),('samples/harness-seed-1.litematic',1,'python generate.py --seed 1 --output samples/harness-seed-1.litematic')] extras += [(f'samples/{name}.litematic',0,f'python -m examples.{name} --seed 0') for name in ('prototype','courtyard','gallery','extension','inspection')] extra_rows=[] audit=[] for row in manifest: s=load_scene(Path(row['artifact'])) digest=semantic_digest(s) assert digest==row['digest'],row['artifact'] audit.append({'artifact':row['artifact'],'status':'validated-reloaded','digest':digest,'blocks':len(s.blocks),'instances':len(s.nodes)}) for artifact,seed,command in extras: s=load_scene(Path(artifact)) assert s.seed==seed digest=semantic_digest(s) row={'artifact':artifact,'seed':seed,'command':command,'digest':digest,'status':'validated-reloaded','blocks':len(s.blocks),'instances':len(s.nodes)} extra_rows.append(row) audit.append(row) Path('samples/examples-manifest.json').write_text(json.dumps(extra_rows,indent=2)) Path('reports/artifact-audit.json').write_text(json.dumps(audit,indent=2)) print(f'{len(audit)} complete artifact pairs validated and reloaded; all recorded digests match.') PY
24 complete artifact pairs validated and reloaded; all recorded digests match.
8500
cat extension_demo/__init__.py rg -n -A42 -B8 'ReadingSuite|extension|substitut' test/test_contracts_provenance.py
cat extension_demo/__init__.py rg -n -A42 -B8 'ReadingSuite|extension|substitut' test/test_contracts_provenance.py
dator, Diagnostic 248- 249- @validator('test.actual-stone') 250- def actual_stone(scene, node, rule): 251- for p in rule.cells: 252- if scene.inspect(p)['state'] != 'minecraft:stone': 253- yield Diagnostic('test.actual-stone', node.path, p, 'Need actual stone') 254- 255- s = Scene() 256- s.place('rule', Assembly('rule', Box((0, 0, 0), (0, 0, 0)), (Child('stone', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('stone'))),), (Rule('test.actual-stone', ((0, 0, 0),)),))) 257- with pytest.raises(ContractError, match='test.actual-stone'): 258- s.remove('/rule/stone') 259- with pytest.raises(ContractError, match='input-domain'): 260- s.place('bad-wall', Wall(width=100)) 261- 262- 263-def test_forwarded_interfaces_discharge_after_scope_construction(): 264- from hearth.kernel import Choice 265- later = Assembly('later', Box((0, 0, 0), (0, 0, 0)), (Child('solid', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('stone'))),), ports=(Port('access', 'access', Frame(), Box((0, 0, 0), (0, 0, 0))),)) 266- choice = Choice('first', (Child('one', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('stone'))), Child('two', Volume(Box((1, 0, 0), (1, 0, 0)), state_of('stone')))), lambda v, p: 0) 267- wrapper = Assembly('wrapper', Box((0, 0, 0), (3, 1, 1)), (choice, Child('later', later, frame=Frame((3, 0, 0)))), ports=(Port('access', 'access', Frame((3, 0, 0)), Box((3, 0, 0), (3, 0, 0)), delegate=('later', 'access')),)) 268- s = Scene() 269- s.place('root', wrapper) 270- s.finalize() 271- assert s.view.port('/root', 'access').frame.origin == (3, 0, 0) 272- 273- 274-def test_dense_export_budget_is_explicit(work): 275- s = Scene(limits=Limits(export_volume=10)) 276- s.place('line', Volume(Box((0, 0, 0), (10, 0, 0)), state_of('stone'))) 277- with pytest.raises(ContractError, match='export-volume'): 278- export_scene(s, work / 'too large.litematic') 279- assert not (work / 'too large.litematic').exists()
8600
sed -n '1,300p' hearth/components/building.py sed -n '1,220p' hearth/programs.py
sed -n '1,300p' hearth/components/building.py sed -n '1,220p' hearth/programs.py
nts), tuple(links), gateway=self.gateway), bindings=tuple(bindings))]) for i in range(self.count): p.relations.append((ctx.path + '/paths', 'connects', f'{parent}/plot-{i}')) for i, z in enumerate(sorted({q[-1] for q in points[:self.count * 2]})): x = 5 if i % 2 else -5 y = ctx.elevation(x, z + 4) + 1 p.children.append(Child(f'lamp-{i}', LampPost(), frame=Frame((x, y, z + 4)))) return p def settlement_scene(seed=0, count=None): scope = Scope(seed) rng = scope.stream('settlement-layout') if count is None: count = rng.choice((3, 4, 5)) if count < 1: raise ValueError('A settlement needs at least one building') designs = [] for i in range(count): local = scope.child(f'building-{i}').stream('room-graph') rooms = [RoomSpec(0, 0, 0, local.choice(('living', 'workshop', 'library')))] for x, z in local.sample(((1, 0), (0, 1)), local.choice((0, 1, 2))): rooms.append(RoomSpec(x, z, 0, local.choice(('storage', 'kitchen', 'living')))) if local.choice((True, True, False)): column = local.choice(rooms) for level in range(1, local.choice((2, 2, 3))): rooms.append(RoomSpec(column.x, column.z, level, 'bedroom' if level == 1 else 'library')) designs.append(Blueprint(tuple(rooms), bay=local.choice((9, 11)), porch=local.choice((True, True, False)), roof_axis=local.choice(('auto', 'x', 'z')), roof_material=local.choice(('deepslate_tile', 'brick')), steep=local.choice((True, True, False)))) rows = (count + 1) // 2 domain = Box((-49, -4, -23), (49, 64, (rows - 1) * 38 + 28)) field = gradient(.012, -.009, 4.8) + wave(.7, .075, .09, rng.random() * 6) + radial(-36, rows * 12, 26, 1.1) scene = Scene(seed, domain=domain) scene.place('land', Terrain(domain, field, edit_limit=20000)) scene.place('village', Settlement(designs, domain, '/land')) return scene.finalize()
8700
sed -n '210,440p' hearth/components/interior.py sed -n '110,310p' hearth/adapters/site.py
sed -n '210,440p' hearth/components/interior.py sed -n '110,310p' hearth/adapters/site.py
return Plan(writes=list(self.writes)) break else: raise ContractError('approach-detour', ctx.path, ctx.frame.origin, 'Cannot meet terrain within length bound') cells = [] support = [] for z, y in rows: cells.extend((x, y + k, z) for x in range(self.center - 1, self.center + 2) for k in (1, 2)) support.extend((x, y, z) for x in range(self.center - 1, self.center + 2)) low = min(ctx.view.elevation(*((lambda p: (p[0], p[2]))(ctx.world((x, 0, z))))) - ctx.frame.origin[1] for z, y in rows for x in range(self.center - 1, self.center + 2)) box = Box((self.center - 1, low, rows[-1][0]), (self.center + 1, max(y for z, y in rows) + 3, -self.porch - 1)) end = (self.center, rows[-1][1] + 1, rows[-1][0]) region = Box((self.center - 1, rows[-1][1], rows[-1][0]), (self.center + 1, self.floor + 2, min(-self.porch - 1, rows[-1][0] + 1))) port = Port('street', 'access', Frame(end), region, 10, 'surface') grant = Grant('surface', region, ('surface',), ('path',), 18) route = tuple((self.center, y + 1, z) for z, y in rows) return Contract(box, (port,), (grant,), (Rule('clear', tuple(cells)), Rule('support', tuple(support)), Rule('route', route, box.expand(1), phase='complete')), decisions={'rows': rows, 'end': end}, reads=(box,)) def realize(self, ctx, contract): p = Plan() rows = contract.decisions['rows'] for index, (z, y) in enumerate(rows): for x in range(self.center - 1, self.center + 2): wx, _, wz = ctx.world((x, 0, z)) bed = ctx.view.elevation(wx, wz) - ctx.frame.origin[1] for yy in range(bed + 1, y): p.block((x, yy, z), state_of('cobblestone'), 'step-footing') p.block((x, y, z), stairs('stone_brick', 'south') if index and rows[index - 1][1] > y else state_of('stone_bricks'), 'treads') return p
8800
sed -n '60,214p' hearth/components/interior.py sed -n '1,145p' hearth/adapters/site.py
sed -n '60,214p' hearth/components/interior.py sed -n '1,145p' hearth/adapters/site.py
ows.append((z, y)) if y == ground: break else: raise ContractError('approach-detour', ctx.path, ctx.frame.origin, 'Cannot meet terrain within length bound') cells = [] support = [] for z, y in rows: cells.extend((x, y + k, z) for x in range(self.center - 1, self.center + 2) for k in (1, 2)) support.extend((x, y, z) for x in range(self.center - 1, self.center + 2)) low = min(ctx.view.elevation(*((lambda p: (p[0], p[2]))(ctx.world((x, 0, z))))) - ctx.frame.origin[1] for z, y in rows for x in range(self.center - 1, self.center + 2)) box = Box((self.center - 1, low, rows[-1][0]), (self.center + 1, max(y for z, y in rows) + 3, -self.porch - 1)) end = (self.center, rows[-1][1] + 1, rows[-1][0]) region = Box((self.center - 1, rows[-1][1], rows[-1][0]), (self.center + 1, self.floor + 2, min(-self.porch - 1, rows[-1][0] + 1))) port = Port('street', 'access', Frame(end), region, 10, 'surface') grant = Grant('surface', region, ('surface',), ('path',), 18) route = tuple((self.center, y + 1, z) for z, y in rows) return Contract(box, (port,), (grant,), (Rule('clear', tuple(cells)), Rule('support', tuple(support)), Rule('route', route, box.expand(1), phase='complete')), decisions={'rows': rows, 'end': end}, reads=(box,)) def realize(self, ctx, contract): p = Plan() rows = contract.decisions['rows'] for index, (z, y) in enumerate(rows): for x in range(self.center - 1, self.center + 2): wx, _, wz = ctx.world((x, 0, z)) bed = ctx.view.elevation(wx, wz) - ctx.frame.origin[1] for yy in range(bed + 1, y): p.block((x, yy, z), state_of('cobblestone'), 'step-footing') p.block((x, y, z), stairs('stone_brick', 'south') if index and rows[index - 1][1] > y else state_of('stone_bricks'), 'treads') return p
8900
sed -n '1,120p' hearth/kernel/scene.py cat previews/courtyard-0/views.json
sed -n '1,120p' hearth/kernel/scene.py cat previews/courtyard-0/views.json
style = dict(style or {"timber": "spruce", "infill": "minecraft:smooth_sandstone", "roof": "deepslate_tile"}) self.preferences = dict(preferences or {}) self.limits = limits or Limits() self.domain = domain self.blocks = {} self.nodes = {} self.reverse = {} self.reverse_shared = {} self.relations = set() self.members = {} self.dependencies = [] self.operations = {} self.displaced = {} self.erasures = {} self.port_uses = {} self.version = 0 self.completed = False self._recipes = {} self.events = [] @property def view(self): return View(self) def _fork(self): other = copy.copy(self) other.blocks = self.blocks.copy() other.nodes = {p: copy.copy(n) for p, n in self.nodes.items()} other.reverse = {k: set(v) for k, v in self.reverse.items()} other.reverse_shared = {k: set(v) for k, v in self.reverse_shared.items()} other.relations = set(self.relations) other.members = {k: set(v) for k, v in self.members.items()} other.dependencies = list(self.dependencies) [ { "source": "samples/courtyard.litematic", "seed": 0, "label": "front", "image": "previews/courtyard-0/front.png", "azimuth": 210, "elevation": 28 }, { "source": "samples/courtyard.litematic", "seed": 0, "label": "rear", "image": "previews/courtyard-0/rear.png", "azimuth": 30, "elevation": 26 }, { "source": "samples/courtyard.litematic", "seed": 0, "label": "floor-cut", "axis": "y", "export_local_cut": 13, "image": "previews/courtyard-0/floor-cut.png", "geometry_preview_only": true }, { "source": "samples/courtyard.litematic", "seed": 0, "label": "stair-cut", "axis": "x", "export_local_cut": 15, "image": "previews/courtyard-0/stair-cut.png", "geometry_preview_only": true } ]
9008
yapf -i examples/preview.py python -m examples.preview --seed 0 --input samples/courtyard.litematic --output previews/courtyard-0 --size 1000 --cutawa
yapf -i examples/preview.py python -m examples.preview --seed 0 --input samples/courtyard.litematic --output previews/courtyard-0 --size 1000 --cutaways > reports/render-courtyard-0.txt
9100
cat examples/verify_replay.py cat previews/commons-6/views.json cat previews/adaptation-00/views.json
cat examples/verify_replay.py cat previews/commons-6/views.json cat previews/adaptation-00/views.json
.mkdir(parents=True, exist_ok=True) output.write_text(json.dumps({'verified': True, 'runs': rows}, indent=2)) return rows if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('reports/replay.json')) a = p.parse_args() verify(a.seed, a.output) [ { "source": "samples/commons-6.litematic", "seed": 6, "label": "front", "image": "previews/commons-6/front.png", "azimuth": 210, "elevation": 28 }, { "source": "samples/commons-6.litematic", "seed": 6, "label": "rear", "image": "previews/commons-6/rear.png", "azimuth": 30, "elevation": 26 }, { "source": "samples/commons-6.litematic", "seed": 6, "label": "floor-cut", "axis": "y", "export_local_cut": 13, "image": "previews/commons-6/floor-cut.png", "geometry_preview_only": true }, { "source": "samples/commons-6.litematic", "seed": 6, "label": "stair-cut", "axis": "x", "export_local_cut": 15, "image": "previews/commons-6/stair-cut.png", "geometry_preview_only": true } ][ { "source": "samples/adaptation-00.litematic", "seed": 0, "label": "front", "image": "previews/adaptation-00/front.png", "azimuth": 210, "elevation": 28 }, { "source": "samples/adaptation-00.litematic", "seed": 0, "label": "rear", "image": "previews/adaptation-00/rear.png", "azimuth": 30, "elevation": 26 }, { "source": "samples/adaptation-00.litematic", "seed": 0, "label": "floor-cut", "axis": "y", "export_local_cut": 14, "image": "previews/adaptation-00/floor-cut.png", "geometry_preview_only": true }, { "source": "samples/adaptation-00.litematic", "seed": 0, "label": "stair-cut", "axis": "x", "export_local_cut": 15, "image": "previews/adaptation-00/stair-cut.png", "geometry_preview_only": true } ]
9200
python - <<'PY' import json from pathlib import Path for name in ('commons-6','adaptation-00','courtyard-0'): rows=json.loads((Path('previews')/name/
python - <<'PY' import json from pathlib import Path for name in ('commons-6','adaptation-00','courtyard-0'): rows=json.loads((Path('previews')/name/'views.json').read_text()) print(name,[(r['label'],r.get('axis'),r.get('export_local_cut')) for r in rows]) PY
commons-6 [('front', None, None), ('rear', None, None), ('floor-cut', 'y', 13), ('stair-cut', 'x', 15)] adaptation-00 [('front', None, None), ('rear', None, None), ('floor-cut', 'y', 14), ('stair-cut', 'x', 15)] courtyard-0 [('front', None, None), ('rear', None, None), ('floor-cut', 'y', 13), ('stair-cut', 'x', 33)]
9300
cat generate.py cat pyproject.toml cat reports/replay.json cat reports/reference-integrity.json
cat generate.py cat pyproject.toml cat reports/replay.json cat reports/reference-integrity.json
enerate.py", "matches": true }, { "path": "reference_exp8_sandstone_cottage.jpg", "matches": true }, { "path": "references/exp8/stilt-water-cabin/generate.py", "matches": true }, { "path": "reference_exp8_stilt_water_cabin.jpg", "matches": true }, { "path": "references/exp8/stilted-manor/generate.py", "matches": true }, { "path": "reference_exp8_stilted_manor.jpg", "matches": true }, { "path": "references/exp8/stone-cottage/generate.py", "matches": true }, { "path": "reference_exp8_stone_cottage.jpg", "matches": true }, { "path": "references/lodge/ref-1/generate.py", "matches": true }, { "path": "reference_lodge_ref-1.png", "matches": true }, { "path": "references/lodge/ref-2/generate.py", "matches": true }, { "path": "reference_lodge_ref-2.png", "matches": true }, { "path": "references/lodge/ref-3/generate.py", "matches": true }, { "path": "reference_lodge_ref-3.png", "matches": true }, { "path": "references/lodge/ref-4/generate.py", "matches": true }, { "path": "reference_lodge_ref-4.png", "matches": true }, { "path": "references/lodge/ref-5/generate.py", "matches": true }, { "path": "reference_lodge_ref-5.png", "matches": true }, { "path": "references/lodge/ref-6/generate.py", "matches": true }, { "path": "reference_lodge_ref-6.png", "matches": true }, { "path": "references/lodge/ref-7/generate.py", "matches": true }, { "path": "reference_lodge_ref-7.png", "matches": true }, { "path": "references/lodge/ref-8/generate.py", "matches": true }, { "path": "reference_lodge_ref-8.png", "matches": true } ] }
9400
rg -n 'TODO|FIXME|NotImplemented|pass$|placeholder|/opt/|/work/' hearth examples test extension_demo ARCHITECTURE.md GENERATOR.md -g '*.py' -g '*.md'
rg -n 'TODO|FIXME|NotImplemented|pass$|placeholder|/opt/|/work/' hearth examples test extension_demo ARCHITECTURE.md GENERATOR.md -g '*.py' -g '*.md' wc -l hearth/kernel/*.py hearth/components/*.py hearth/adapters/*.py hearth/environment/*.py test/test_*.py
examples/preview.py:10:RENDER = Path('/opt/tools/render_schematic.mjs') examples/preview.py:11:CUTAWAY = Path('/opt/tools/cutaway.py') examples/preview.py:12:VITE = Path('/work/generator/MCRender/node_modules/.bin/vite-node') GENERATOR.md:24:from `/work/generator/MCIO` in this environment. On another host, install MCIO from its source before GENERATOR.md:251:| R01 | `kernel/*`, initial design, seven foundation tests before content; thin CLI | Executable foundation, not placeholder interfaces | hearth/persistence.py:62: sys.path.insert(0, '/work/generator/MCIO') hearth/kernel/errors.py:32: pass 5 hearth/kernel/__init__.py 150 hearth/kernel/contracts.py 32 hearth/kernel/errors.py 535 hearth/kernel/scene.py 220 hearth/kernel/validation.py 166 hearth/kernel/view.py 4 hearth/components/__init__.py 158 hearth/components/building.py 19 hearth/components/constraints.py 210 hearth/components/interior.py 253 hearth/components/landscape.py 191 hearth/components/primitives.py 125 hearth/components/roofs.py 2 hearth/adapters/__init__.py 137 hearth/adapters/site.py 3 hearth/environment/__init__.py 79 hearth/environment/fields.py 42 hearth/environment/terrain.py 279 test/test_contracts_provenance.py 243 test/test_geometry_environment.py 122 test/test_kernel.py 2975 total
9500
python - <<'PY' from pathlib import Path import re files=[Path(p) for p in ('ARCHITECTURE.md','GENERATOR.md','reports/ASSESSMENT.md','reports/developm
python - <<'PY' from pathlib import Path import re files=[Path(p) for p in ('ARCHITECTURE.md','GENERATOR.md','reports/ASSESSMENT.md','reports/development-findings.md','samples/README.md','previews/README.md')] missing=[] for p in files: for raw in re.findall(r'\]\(([^)]+)\)',p.read_text()): if '://' in raw or raw.startswith('#'): continue target=p.parent/raw.split('#')[0] if not target.exists(): missing.append((str(p),raw)) ledger=set(re.findall(r'\| (R\d{2}) \|',Path('GENERATOR.md').read_text())) assert ledger=={f'R{i:02}' for i in range(1,31)},ledger assert not missing,missing print('All 30 requirement ledger entries and documentation links checked.') PY
All 30 requirement ledger entries and documentation links checked.
9600
python - <<'PY' from pathlib import Path import shutil paths=['.pytest_cache','hearth/__pycache__','hearth/kernel/__pycache__','hearth/environment/__p
python - <<'PY' from pathlib import Path import shutil paths=['.pytest_cache','hearth/__pycache__','hearth/kernel/__pycache__','hearth/environment/__pycache__','hearth/components/__pycache__','hearth/adapters/__pycache__','examples/__pycache__','extension_demo/__pycache__','test/__pycache__'] for name in paths: p=Path(name) if p.is_dir(): shutil.rmtree(p) for name in ('output.litematic','output.litematic.structure.json','ARCHITECTURE.md','GENERATOR.md','reports/ASSESSMENT.md','previews/README.md'): p=Path(name) assert p.is_file() and p.stat().st_size>0,name print('Delivery files present; generated caches cleaned.') PY
Delivery files present; generated caches cleaned.

原始运行配置:gpt-6-astra,reasoning effort max,4 CPU / 8 GiB / 512 PID,生成 CLI 无总超时。镜像摘要:sha256:b8a7738b1854ef200794229cb1209180c9fd6cc585745e68b23bb07e6faf49bc。使用量 JSON · 命令 JSONL

05 · 架构与公共接口

库的低层协议统一处理叶组件与复合组件:capability() 宣告可提供的接口、可行域和限制;negotiate(context, parameters) 根据环境协商契约;realize(context, contract) 返回包含写入、子组件、候选选择和关系的 Plan。CLI 和参考源码都不是内核依赖。

flowchart LR
 A["Client"] --> B["Capability"]
 B --> C["Contract"]
 C --> D["Plan"]
 D --> E["Children"]
 E --> B
 D --> F["Validate"]
 F -->|"pass"| G["Commit"]
 F -->|"fail"| H["Rollback"]
 G --> I["Export + Query"]
拖动平移 · 滚轮缩放
同一协议可以嵌套;验证发生在候选提交前,失败不留下半成品。
层关键模块负责什么
值与几何space / blocks / randomness包围盒、局部坐标与旋转、方块属性、稳定分支随机数
内核kernel/contracts / scene / view / validation协商、权限、事务、阶段规则、实例图、查询
环境environment/fields / terrain可组合场、域、冻结地层、水体与环境观测
建筑知识components/* / adapters/site窗墙、房间、屋顶、家具、地基和入口适配
高阶组合composition / programs重复、排列、散布、封装、房间图与聚落意图
持久化与证据persistence / assessment / examples成对导出、读回验证、结构统计、可复现批次
外部扩展extension_demo替代吊灯及嵌套阅读空间,不修改内核 dispatch

薄客户端实际有多薄

from hearth.components.building import Blueprint, RoomSpec from hearth.programs import building_scene from hearth.environment import gradient, wave plan = Blueprint(( RoomSpec(0, 0, 0, 'living'), RoomSpec(0, 0, 1, 'bedroom'), RoomSpec(1, 0, 0, 'workshop'), ), bay=BAY, porch=PORCH, roof_axis=ROOF_AXIS) field = gradient(x=SLOPE, base=4) + wave(amplitude=0.7) scene = building_scene(plan, seed=SEED, field=field, water=WATER)

上例直接指定房间图,不手写方块、不打所有权标签、不修补几何。库可很大;判断接口是否成功,关键在客户端是否仍表达“我要什么”,以及新组件能否在既有契约下替换。

原始 generate.py 全文
# Generate, validate and export the default complete Hearth settlement. import argparse from pathlib import Path from hearth.programs import settlement_scene from hearth.persistence import export_scene, semantic_digest def main(): parser = argparse.ArgumentParser(description='Generate a contract-composed Minecraft Java 1.21.1 settlement.') parser.add_argument('--seed', type=int, default=0, help='Explicit integer seed, default 0') parser.add_argument('--output', type=Path, default=Path('output.litematic')) parser.add_argument('--count', type=int, choices=range(3, 7), help='Optional explicit building count, 3 through 6') args = parser.parse_args() scene = settlement_scene(args.seed, args.count) export_scene(scene, args.output) print(f'Validated {sum(n.type=="building.rooms" for n in scene.nodes.values())} buildings, {len(scene.blocks)} blocks, {len(scene.nodes)} components.') print(f'{args.output} | semantic SHA256 {semantic_digest(scene)}') if __name__ == '__main__': main()

源码统计包含新写的库、示例、独立扩展和测试:42 个 Python 文件,4,120 行,排除全部参考源码。文件长度只用于说明工程规模,不作质量分数。

06 · 权限、事务、阶段和替换

系统没有“树的优先级高于草”这种全局覆盖表。宿主以 Grant 授予具体区域、动词、消费者类别、改动限额和是否允许整物替换;Binding 使用且可以缩小这份授权。相同材质也不能自动当成可共享或可覆盖。

组合所需规则验证重点
草 → 树草公开完整植株替换授权;树仍需土壤支撑不会留下半株高草,反向覆盖不能套用授权
土地 → 水池土壤在有界区域授权挖掘和写入池壁/池底封闭,禁止挖空既有树的支撑
墙 → 窗户兼容的端口方向、锚点、区域、厚度和容量窗洞、玻璃与边框按墙厚适配,保留结构宿主
共享支撑显式 shared-support 端口及容量记录多个参与者,不能靠“方块一样”绕过权限
后期装饰/属性修改保留先前有效的支撑、净空、成对方块和原始语义所有者修改历史与结构归属分开记录

每次放置在临时状态上运行:先检查可行域与契约,再施加 effects 和递归子组件,最后检查真实几何与既有消费者的约束。失败时几何、端口使用、结构图、历史、依赖及随机分支一起回滚。Python 组件仍是受信任代码,这个设计不是敌对代码隔离沙箱。

构建中的 scope 可以暂时欠缺将由后续子组件履行的义务;complete scope 必须验证。这解决“父接口已宣告,但子接口还没造出来”的时序问题。延迟检查只适用于进行中的结构,不能成为跳过最终验证的理由。

07 · 方块归属、依赖与再生成

结构身份由内核在执行组件写入时记录。Cell 保存 owner、operation 和共享参与者,Node 保存真实实例路径、类型、父关系和契约。查询玻璃得到的是实际窗户实例,而不是根据材质猜出的“窗户”标签。两个窗户即使用相同玻璃,也有不同身份。

图的职责被分开:结构关系回答“属于谁/装在谁上”;依赖图回答“读取过什么/改动会使谁失效”;operation 回答“谁做了这次修改”。跨层级安装的窗户仍可计入宿主墙的语义后代。点击上方结构链,可看到当前真实成员集合,避免把包围盒当成精确所有权。

持久化写出几何与结构 JSON,保存版本、offset、语义摘要、实例与关系,读回恢复世界坐标并校验匹配。缺失或不匹配的 companion 会拒绝;配对校验保障一致性,不是签名认证。

再生成采用显式依赖范围:例如替换 /land 时指定受影响的房屋,先恢复旧分支置换过的宿主内容,再原子重放。接口/空间读取会被追踪,过时分支不能作为已完成建筑导出。它没有承诺任意变化都自动重新规划,也不会把保存的元数据当成 Python 执行。

08 · 通用地形与接触适配

环境由 gradient、wave、radial、clamp、blend、transform 等表达式组成,再采样为有已知域的地层和水体。平地或湿地是这些参数与操作的结果,不是内核枚举的固定环境家族。当前交付确实使用了场表达式,但不能据此宣称已实现通用 spline 城市系统。

地形先冻结,再放建筑。建筑的房间图、用途、模数、水平位置和主要朝向被锁定;接触策略在这些约束下比较台阶式周边支撑与桩基。每个候选包含完整建筑及适配几何,先满足硬约束,再按实际 sitework 成本和暴露支撑等偏好打分。

默认策略边界数值/行为
可接受起伏最多 5 格
支撑高度床层至地板最多 8 格
床层检查至少两个连续实体单元,不能只有表面高度
入口接近长度最多 12 格
地基填充默认最多 1,600 格
编辑限额Terrain grant 默认每个绑定 2,500 格;聚落可显式增加

这些是可配置的 SiteLimits/授权边界,不是理论上的全部建筑能力。默认建筑不挖掘地形,水池另测授权挖掘;因此不能把“零挖掘”写成“对场地零扰动”。单体只保证出口到自己的外部 landing,公共道路由上层组合负责。湿地样本不会凭空提供去往远处陆地的完整栈道。

09 · 结构多样性与有限分布

原始有限 corpus:去除颜色、命名和整体变换后的主结构签名。
按输入计数。候选接受率是另一分母,不能混为成功率。

三份单体程序各跑 seed 0–7,共 24 个有效样本,出现 18 个主结构签名:dwelling 5/8、atelier 8/8、commons 5/8。聚落的八个 seed 加数量边界共 10 个样本有 10 个签名。有限样本存在重复,且“10/10 不同”不等于程序可生成无限种有意义结构。

主结构指标包含实际房间范围、用途与连接、楼层/楼梯、屋顶几何和路径组织,排除材料颜色、名字与整体变换。接触适配另计:环境配对 44/64 个接触签名,不能拿地基差异冒充建筑主体变化。64 个环境配对中的四个建筑 seed 只有三种主设计。

随机数按显式 seed、稳定实例路径和用途通过 SHA-256 派生。给独立分支加盆栽不应改变远处房屋;存在真实空间或全局依赖的改动则可以触发下游变化。有限的房间语汇、沿街布局和屋顶策略仍限制了输出风格,与 16 张参考展示的全部造型跨度存在距离。

10 · 130 个输入:逐条检查

原始 final corpus 保留 64 个适配配对、24 个单体、10 个聚落和 32 个压力输入。适配中的 16 个冻结环境 × 4 个独立建筑 seed,与按建筑需要偷改地形不同;后八个环境采用留出的 blend/transform 组合。所有压力输入都保留,没有失败后换输入直到成功。

批次有效输入通过候选不兼容观察秒数
冻结环境 × 建筑64/6484/128032.777
三份单体24/2448/48022.288
聚落10/1080/80065.221
压力输入9/3211/642313.515

压力拒绝为 21 个 relief-limit、2 个 support-height-limit;这说明输入超出当前策略,不证明任何方法都不能建。候选统计的分母包含每栋建筑的两种接触方案;聚落包含多个建筑,所以不能直接拿候选数量当聚落数量。计时来自原实验机器,部分工作并发,不是可移植性能基准。

输入状态参数摘要方块组件候选通过候选秒主结构签名完整证据
adaptation-00validated{"environment_seed": 0, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 32487186211.43896f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-00", "inputs": { "environment_seed": 0, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 3.734703416353409 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "906464dc2079927d90ed3b6156a39a63117bebd4d87987d7aa34776fb4dba49c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "40a333945b1d5fe7d45496e060a142adef153c31f210395e419dd8604c61ca36", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 98, "excavation": 0, "sitework_occupied_cells": 104, "replaced_cells": 101, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "7c3be60431ad54e5bb4b9032459e47976535f3fc2692781305949f0d572af3e0" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.06 ] ], "chosen": 1 } ], "artifact": "samples/adaptation-00.litematic", "seconds": 1.4389 }
adaptation-01validated{"environment_seed": 0, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 32378146210.288994234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-01", "inputs": { "environment_seed": 0, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 3.734703416353409 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "906464dc2079927d90ed3b6156a39a63117bebd4d87987d7aa34776fb4dba49c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 23781, "components": 46, "digest": "c338d086048c7976d5a13a55870c6f3664770f2b0209d259def243b617517327", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 35, "excavation": 0, "sitework_occupied_cells": 41, "replaced_cells": 38, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "1b4b7b0d79d57428a022e8a517d1fcddf115fd45952a800c6fdf917086dc70c7" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.17 ] ], "chosen": 1 } ], "seconds": 0.2889 }
adaptation-02validated{"environment_seed": 0, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 32487186210.52246f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-02", "inputs": { "environment_seed": 0, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 3.734703416353409 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "906464dc2079927d90ed3b6156a39a63117bebd4d87987d7aa34776fb4dba49c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "40a333945b1d5fe7d45496e060a142adef153c31f210395e419dd8604c61ca36", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 98, "excavation": 0, "sitework_occupied_cells": 104, "replaced_cells": 101, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "7c3be60431ad54e5bb4b9032459e47976535f3fc2692781305949f0d572af3e0" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.06 ] ], "chosen": 1 } ], "seconds": 0.5224 }
adaptation-03validated{"environment_seed": 0, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 32431864210.39547742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-03", "inputs": { "environment_seed": 0, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 3.734703416353409 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "906464dc2079927d90ed3b6156a39a63117bebd4d87987d7aa34776fb4dba49c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24318, "components": 64, "digest": "10ab35d41b4a1dd79ea171f1ac2ea683f491cb0d0a3a0c0134fd06af7c2c0f1f", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 68, "excavation": 0, "sitework_occupied_cells": 74, "replaced_cells": 71, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "8fbaddd009f6bd26aea6dee40303a76c8706137de7708652769def5041fe603c" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.16 ] ], "chosen": 1 } ], "seconds": 0.3954 }
adaptation-04validated{"environment_seed": 1, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.11, 5.0442202282188286220.63586f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-04", "inputs": { "environment_seed": 1, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 5.044220228402418 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.7 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "daca1e74cadbc8a20e59b9354c07f046998aa77b231dc343cf190b4169a847a9", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21882, "components": 86, "digest": "7e297b3b0e13cd2a55c87dfac1dc28d7cef4d3adafd26bf13d03426dde887007", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 78, "excavation": 0, "sitework_occupied_cells": 90, "replaced_cells": 3, "new_sitework_cells": 87, "strategies": [ "piers" ], "signature": "5305cba7edc3f009e379e293f517dfbe52879d0bedd964e0bd13ac976a1a2fae" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 1, 0.96 ], [ 0, 1.19 ] ], "chosen": 1 } ], "seconds": 0.6358 }
adaptation-05validated{"environment_seed": 1, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.11, 5.0442202282071646220.335894234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-05", "inputs": { "environment_seed": 1, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 5.044220228402418 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.7 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "daca1e74cadbc8a20e59b9354c07f046998aa77b231dc343cf190b4169a847a9", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 20716, "components": 46, "digest": "7d68d8787c0ebdfdbf6c3de2ce49b244c50282326d9b85db754e318f7573ae22", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 8, "excavation": 0, "sitework_occupied_cells": 14, "replaced_cells": 3, "new_sitework_cells": 11, "strategies": [ "stepped" ], "signature": "d780400b9dfa3d901d5f136c76face86ea7085fca11c044ed9e43176755b4c1b" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.2 ], [ 1, 0.58 ] ], "chosen": 0 } ], "seconds": 0.3358 }
adaptation-06validated{"environment_seed": 1, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.11, 5.0442202282188286220.6346f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-06", "inputs": { "environment_seed": 1, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 5.044220228402418 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.7 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "daca1e74cadbc8a20e59b9354c07f046998aa77b231dc343cf190b4169a847a9", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21882, "components": 86, "digest": "7e297b3b0e13cd2a55c87dfac1dc28d7cef4d3adafd26bf13d03426dde887007", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 78, "excavation": 0, "sitework_occupied_cells": 90, "replaced_cells": 3, "new_sitework_cells": 87, "strategies": [ "piers" ], "signature": "5305cba7edc3f009e379e293f517dfbe52879d0bedd964e0bd13ac976a1a2fae" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 1, 0.96 ], [ 0, 1.19 ] ], "chosen": 1 } ], "seconds": 0.634 }
adaptation-07validated{"environment_seed": 1, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.11, 5.0442202282126564220.47087742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-07", "inputs": { "environment_seed": 1, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 5.044220228402418 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.7 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "daca1e74cadbc8a20e59b9354c07f046998aa77b231dc343cf190b4169a847a9", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21265, "components": 64, "digest": "e3b893bd31b384aa13d82a42c685d4b766fedd719b9853b34f36500b05071b08", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 20, "excavation": 0, "sitework_occupied_cells": 26, "replaced_cells": 3, "new_sitework_cells": 23, "strategies": [ "stepped" ], "signature": "e8392ce44836ce928c89ed91fdb5e57333465937d3c447f32cc088e6c99cc1f0" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.32 ], [ 1, 0.69 ] ], "chosen": 0 } ], "seconds": 0.4708 }
adaptation-08validated{"environment_seed": 2, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 4.92715086211.30846f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-08", "inputs": { "environment_seed": 2, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 4.998757701772476 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "7b7ca5bf28161c97f88cc0791bea9144ad70124394aff4c325c894a61cb9e277", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "6e6adddbde239500caccc5c25158787acff8a6df6be946174e7cb08ab340bfc7", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 110, "excavation": 0, "sitework_occupied_cells": 119, "replaced_cells": 116, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "2a6dbe97ac90ea6eda0d3ff7078aaf2188223bd164b16507665dde9082338dda" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.51 ] ], "chosen": 1 } ], "artifact": "samples/adaptation-08.litematic", "seconds": 1.3084 }
adaptation-09validated{"environment_seed": 2, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 4.92606046210.295194234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-09", "inputs": { "environment_seed": 2, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 4.998757701772476 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "7b7ca5bf28161c97f88cc0791bea9144ad70124394aff4c325c894a61cb9e277", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26060, "components": 46, "digest": "e917131b5f79386b8c5de98904d43c40ff022a2a08182b2e03d0d1a58ce06711", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 60, "excavation": 0, "sitework_occupied_cells": 69, "replaced_cells": 66, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "a396c90fb993143e934cc95ccddcd49c77df55b413a73fcf63d0fe10a1fe779f" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.01 ] ], "chosen": 1 } ], "seconds": 0.2951 }
adaptation-10validated{"environment_seed": 2, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 4.92715086210.53076f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-10", "inputs": { "environment_seed": 2, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 4.998757701772476 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "7b7ca5bf28161c97f88cc0791bea9144ad70124394aff4c325c894a61cb9e277", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "6e6adddbde239500caccc5c25158787acff8a6df6be946174e7cb08ab340bfc7", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 110, "excavation": 0, "sitework_occupied_cells": 119, "replaced_cells": 116, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "2a6dbe97ac90ea6eda0d3ff7078aaf2188223bd164b16507665dde9082338dda" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.51 ] ], "chosen": 1 } ], "seconds": 0.5307 }
adaptation-11validated{"environment_seed": 2, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 4.92659764210.4097742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-11", "inputs": { "environment_seed": 2, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 4.998757701772476 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "7b7ca5bf28161c97f88cc0791bea9144ad70124394aff4c325c894a61cb9e277", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26597, "components": 64, "digest": "cbf98db0ebdec6a35e839f022a6a7d4a2e06245ba0a705349016fbd1147d84b3", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 88, "excavation": 0, "sitework_occupied_cells": 97, "replaced_cells": 94, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "8f114f6e577ac72f1c0a5b5e782dca5780a07d950370bdabd7d798ca7f2dff2b" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.85 ] ], "chosen": 1 } ], "seconds": 0.409 }
adaptation-12validated{"environment_seed": 3, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 0.814364809862259286220.63346f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-12", "inputs": { "environment_seed": 3, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 0.814364809860294 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "18e01061ffa3861e458a5585972b1dccb5e3b4b6b657e0b4e26df947c2a36f1c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 22592, "components": 86, "digest": "84a7d16a3e21e3b888149e9ee1b0219a8c465e4673b4da42004da32cfc62a130", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "36cebeea96a6dfa0684e96ff304ff814e80a2700814c869914658edea2fd8113" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.6334 }
adaptation-13validated{"environment_seed": 3, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 0.814364809862150246220.341794234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-13", "inputs": { "environment_seed": 3, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 0.814364809860294 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "18e01061ffa3861e458a5585972b1dccb5e3b4b6b657e0b4e26df947c2a36f1c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21502, "components": 46, "digest": "c24a126a8488198f9205bf9b84679197d867acba9461bf9d2d57a6300d012540", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "3c7ffb6a56f17204b971a96b6a54701f96f8ad65b81ad5061742fc80570d3154" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.3417 }
adaptation-14validated{"environment_seed": 3, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 0.814364809862259286220.64076f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-14", "inputs": { "environment_seed": 3, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 0.814364809860294 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "18e01061ffa3861e458a5585972b1dccb5e3b4b6b657e0b4e26df947c2a36f1c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 22592, "components": 86, "digest": "84a7d16a3e21e3b888149e9ee1b0219a8c465e4673b4da42004da32cfc62a130", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "36cebeea96a6dfa0684e96ff304ff814e80a2700814c869914658edea2fd8113" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.6407 }
adaptation-15validated{"environment_seed": 3, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 0.814364809862203964220.47017742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-15", "inputs": { "environment_seed": 3, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 0.814364809860294 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "18e01061ffa3861e458a5585972b1dccb5e3b4b6b657e0b4e26df947c2a36f1c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 22039, "components": 64, "digest": "237f2d39812f6ba33e772914fa057597227cbee1eac6ffdeb3d1e7c39d32c92c", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "531d3dabce074082622786ea416e51f3410f2c34a82f81f2536b5d1299958c1b" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.4701 }
adaptation-16validated{"environment_seed": 4, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 0.2487186210.51936f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-16", "inputs": { "environment_seed": 4, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 0.5187285716175347 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "f5d14c3f45eb4a655213a24525ba55b86cc85225c02ea29d5cc0b15e34d7f3d8", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "ec7ea241b137860c1aa8f34ed863f6a02b7f56b7d3d6b1f7ae89093624f8f6c4", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 89, "excavation": 0, "sitework_occupied_cells": 95, "replaced_cells": 92, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "29ea76797d30fdaae2c8c27e72a67a3d4264b6dba36efb88b3d06848c708b648" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.79 ] ], "chosen": 1 } ], "seconds": 0.5193 }
adaptation-17validated{"environment_seed": 4, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 0.2378146210.290994234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-17", "inputs": { "environment_seed": 4, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 0.5187285716175347 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "f5d14c3f45eb4a655213a24525ba55b86cc85225c02ea29d5cc0b15e34d7f3d8", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 23781, "components": 46, "digest": "b6805a850c4e5af6d7b21930599f41ada5abf7da7c139901702f408922dae60a", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 34, "excavation": 0, "sitework_occupied_cells": 40, "replaced_cells": 37, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "5bc5b53d0e99c1e02a55cb82e99fac7a0894d53f0df1d8f48d91062bb311ba04" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.14 ] ], "chosen": 1 } ], "seconds": 0.2909 }
adaptation-18validated{"environment_seed": 4, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 0.2487186210.52226f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-18", "inputs": { "environment_seed": 4, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 0.5187285716175347 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "f5d14c3f45eb4a655213a24525ba55b86cc85225c02ea29d5cc0b15e34d7f3d8", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "ec7ea241b137860c1aa8f34ed863f6a02b7f56b7d3d6b1f7ae89093624f8f6c4", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 89, "excavation": 0, "sitework_occupied_cells": 95, "replaced_cells": 92, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "29ea76797d30fdaae2c8c27e72a67a3d4264b6dba36efb88b3d06848c708b648" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.79 ] ], "chosen": 1 } ], "seconds": 0.5222 }
adaptation-19validated{"environment_seed": 4, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 0.2431864210.39677742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-19", "inputs": { "environment_seed": 4, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 0.5187285716175347 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "f5d14c3f45eb4a655213a24525ba55b86cc85225c02ea29d5cc0b15e34d7f3d8", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24318, "components": 64, "digest": "ef120ef3bd6e919c3cb847c5f8e6374a09a47af620880aa3a0460a5b651ba9de", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 55, "excavation": 0, "sitework_occupied_cells": 61, "replaced_cells": 58, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "30dc3fe1bcf21c76efd58bf5a0081f8a45a39ccae0e0a7ca95e525134d8daedb" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.77 ] ], "chosen": 1 } ], "seconds": 0.3967 }
adaptation-20validated{"environment_seed": 5, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 4.832715086210.52996f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-20", "inputs": { "environment_seed": 5, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 4.831610348091849 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "c0250ac153f895da33f04c694ab89c2fc128250b2aabcc248bfd0291b3ed26ca", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "cd115969109befe64f3d2fce3f53e20ce3cd10921f11c45bafc916538935eddc", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 159, "excavation": 0, "sitework_occupied_cells": 171, "replaced_cells": 168, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "8a7fca3a5592a996023823abfd8f8edf542738c15208ffeb019b187b24dabd0e" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 5.07 ] ], "chosen": 1 } ], "seconds": 0.5299 }
adaptation-21validated{"environment_seed": 5, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 4.832606046210.29794234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-21", "inputs": { "environment_seed": 5, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 4.831610348091849 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "c0250ac153f895da33f04c694ab89c2fc128250b2aabcc248bfd0291b3ed26ca", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26060, "components": 46, "digest": "91be98f66950392436d70472a9b63f588f58262af6a88ebaea779aedea80ace9", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 78, "excavation": 0, "sitework_occupied_cells": 90, "replaced_cells": 87, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "b947c64158812fb5f7ac6c2bc4ef68043fb63b080ec3444911aea8e03900c02e" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.64 ] ], "chosen": 1 } ], "seconds": 0.297 }
adaptation-22validated{"environment_seed": 5, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 4.832715086210.53956f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-22", "inputs": { "environment_seed": 5, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 4.831610348091849 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "c0250ac153f895da33f04c694ab89c2fc128250b2aabcc248bfd0291b3ed26ca", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "cd115969109befe64f3d2fce3f53e20ce3cd10921f11c45bafc916538935eddc", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 159, "excavation": 0, "sitework_occupied_cells": 171, "replaced_cells": 168, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "8a7fca3a5592a996023823abfd8f8edf542738c15208ffeb019b187b24dabd0e" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 5.07 ] ], "chosen": 1 } ], "seconds": 0.5395 }
adaptation-23validated{"environment_seed": 5, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 4.832659764210.41397742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-23", "inputs": { "environment_seed": 5, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 4.831610348091849 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "c0250ac153f895da33f04c694ab89c2fc128250b2aabcc248bfd0291b3ed26ca", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26597, "components": 64, "digest": "5acfdb03121f25b7a50b6993013db6031a887a05b26e37650ba9ae7c9fd98756", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 111, "excavation": 0, "sitework_occupied_cells": 123, "replaced_cells": 120, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "fcc02fb751213329b1a511f8f8142e9254860e7a9a6baa43043b3468e3fdb6ca" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.63 ] ], "chosen": 1 } ], "seconds": 0.4139 }
adaptation-24validated{"environment_seed": 6, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 0.65422487186210.52066f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-24", "inputs": { "environment_seed": 6, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 0.6542444831229557 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "3f0903661734cc9214274958b2fc715c12c4739f764ac72d1130d62a6746348b", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "536b2c6891a5ad9a739f35b7ce2d3965472948f42876dab60d78ab6f4d34ad4e", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 87, "excavation": 0, "sitework_occupied_cells": 93, "replaced_cells": 90, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "18fa41808f08d395d02a8b9c18982b9dae553d6209ebcabfac45537399862208" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.73 ] ], "chosen": 1 } ], "seconds": 0.5206 }
adaptation-25validated{"environment_seed": 6, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 0.65422378146210.283494234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-25", "inputs": { "environment_seed": 6, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 0.6542444831229557 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "3f0903661734cc9214274958b2fc715c12c4739f764ac72d1130d62a6746348b", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 23781, "components": 46, "digest": "1541bbe934d1177173863418a14ebb4d4f01c8a11eca372fe1996e168cf0b1a4", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 30, "excavation": 0, "sitework_occupied_cells": 36, "replaced_cells": 33, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "88afb9b56e7670c8376fb6fc2d38a0d455fcf3759020f60922c9dbe02ce23bb0" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.02 ] ], "chosen": 1 } ], "seconds": 0.2834 }
adaptation-26validated{"environment_seed": 6, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 0.65422487186210.51876f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-26", "inputs": { "environment_seed": 6, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 0.6542444831229557 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "3f0903661734cc9214274958b2fc715c12c4739f764ac72d1130d62a6746348b", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "536b2c6891a5ad9a739f35b7ce2d3965472948f42876dab60d78ab6f4d34ad4e", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 87, "excavation": 0, "sitework_occupied_cells": 93, "replaced_cells": 90, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "18fa41808f08d395d02a8b9c18982b9dae553d6209ebcabfac45537399862208" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.73 ] ], "chosen": 1 } ], "seconds": 0.5187 }
adaptation-27validated{"environment_seed": 6, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, 0, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 0.65422431864210.40917742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-27", "inputs": { "environment_seed": 6, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, 0, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 0.6542444831229557 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0.4 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "3f0903661734cc9214274958b2fc715c12c4739f764ac72d1130d62a6746348b", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24318, "components": 64, "digest": "f36759e4590382433d82abe0abe9df3f87be424157606df893d6097f296ae1ca", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 56, "excavation": 0, "sitework_occupied_cells": 62, "replaced_cells": 59, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "ce655a77c0e8be2007749ac5ed2a269a708687d4e0549f19a8675ba223c02948" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.8 ] ], "chosen": 1 } ], "seconds": 0.4091 }
adaptation-28validated{"environment_seed": 7, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 0.49438722715086210.52966f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-28", "inputs": { "environment_seed": 7, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 0.4943872051732314 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "42e46282cb95081c1887d56efdff1266c913be170433d59bc16edcd43216cf33", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "e8592bab12ea02f107436636bee249449f7966ae8007b004615b47f1f2ed92ac", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 135, "excavation": 0, "sitework_occupied_cells": 147, "replaced_cells": 144, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "6eb43e9651cf557bf04173438dce25898d160fa3fe87129e1ac462583ef6296b" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 4.35 ] ], "chosen": 1 } ], "seconds": 0.5296 }
adaptation-29validated{"environment_seed": 7, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 0.49438722606046210.304394234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-29", "inputs": { "environment_seed": 7, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 0.4943872051732314 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "42e46282cb95081c1887d56efdff1266c913be170433d59bc16edcd43216cf33", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26060, "components": 46, "digest": "4d6a588ab2dc159a7b5287b5d77ce16477651c505525b4bf0360959b40d3bd8b", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 71, "excavation": 0, "sitework_occupied_cells": 83, "replaced_cells": 80, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "bf13f88a8f5b5cf5925f5bb73ac50f1218b0ede0a3c4ae8e080c169a7b9b6683" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.43 ] ], "chosen": 1 } ], "seconds": 0.3043 }
adaptation-30validated{"environment_seed": 7, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 0.49438722715086210.546f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-30", "inputs": { "environment_seed": 7, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 0.4943872051732314 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "42e46282cb95081c1887d56efdff1266c913be170433d59bc16edcd43216cf33", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "e8592bab12ea02f107436636bee249449f7966ae8007b004615b47f1f2ed92ac", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 135, "excavation": 0, "sitework_occupied_cells": 147, "replaced_cells": 144, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "6eb43e9651cf557bf04173438dce25898d160fa3fe87129e1ac462583ef6296b" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 4.35 ] ], "chosen": 1 } ], "seconds": 0.54 }
adaptation-31validated{"environment_seed": 7, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 0.49438722659764210.41637742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-31", "inputs": { "environment_seed": 7, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 0.4943872051732314 ] } ] }, { "op": "radial", "args": [ 7, 8, 22, 0 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "42e46282cb95081c1887d56efdff1266c913be170433d59bc16edcd43216cf33", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": false }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26597, "components": 64, "digest": "c096c71f2fa9c3b1d33d4c2e779a69e8694dd6fbee9c24c0e71b48289d2696c2", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 103, "excavation": 0, "sitework_occupied_cells": 115, "replaced_cells": 112, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "496ed20fe1aaa5ca435aca00bf65b9cb3fd842ae875da7ee5a3cde0ff00696d9" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.39 ] ], "chosen": 1 } ], "seconds": 0.4163 }
adaptation-32validated{"environment_seed": 8, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 1.49067932158986220.62916f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-32", "inputs": { "environment_seed": 8, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 1.4906793537687184 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "ffbbf6a968541c5d3bb22a89abb40e3a8a38c9c8902eb10ea56cf5b035942597", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21589, "components": 86, "digest": "ca4dccae1f4a67d287d6d29c3b51d7ace481ec82244967a0a7ed80c1c8baf886", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 41, "excavation": 0, "sitework_occupied_cells": 47, "replaced_cells": 3, "new_sitework_cells": 44, "strategies": [ "stepped" ], "signature": "883eaa50115447b307a549127672336e8e50b4576e5749912f4dc602040a6080" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.53 ], [ 1, 0.82 ] ], "chosen": 0 } ], "seconds": 0.6291 }
adaptation-33validated{"environment_seed": 8, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 1.49067932047646220.331594234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-33", "inputs": { "environment_seed": 8, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 1.4906793537687184 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "ffbbf6a968541c5d3bb22a89abb40e3a8a38c9c8902eb10ea56cf5b035942597", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 20476, "components": 46, "digest": "50ec6cc7b0bd760a7900ced6d2b51bdee595fab66895731baed081fcac6b9485", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 18, "excavation": 0, "sitework_occupied_cells": 24, "replaced_cells": 3, "new_sitework_cells": 21, "strategies": [ "stepped" ], "signature": "f614d65d5e65f901661938db60f669a706c96dfc6813ef5f6494874d033e99bd" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.3 ], [ 1, 0.65 ] ], "chosen": 0 } ], "seconds": 0.3315 }
adaptation-34validated{"environment_seed": 8, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 1.49067932158986220.68116f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-34", "inputs": { "environment_seed": 8, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 1.4906793537687184 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "ffbbf6a968541c5d3bb22a89abb40e3a8a38c9c8902eb10ea56cf5b035942597", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21589, "components": 86, "digest": "ca4dccae1f4a67d287d6d29c3b51d7ace481ec82244967a0a7ed80c1c8baf886", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 41, "excavation": 0, "sitework_occupied_cells": 47, "replaced_cells": 3, "new_sitework_cells": 44, "strategies": [ "stepped" ], "signature": "883eaa50115447b307a549127672336e8e50b4576e5749912f4dc602040a6080" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.53 ], [ 1, 0.82 ] ], "chosen": 0 } ], "seconds": 0.6811 }
adaptation-35validated{"environment_seed": 8, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 1.49067932103464221.03957742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-35", "inputs": { "environment_seed": 8, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 1.4906793537687184 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "ffbbf6a968541c5d3bb22a89abb40e3a8a38c9c8902eb10ea56cf5b035942597", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21034, "components": 64, "digest": "ef3f1717232eb1062612345336146404d2c56cdf61d820402f51d975e687b727", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 39, "excavation": 0, "sitework_occupied_cells": 45, "replaced_cells": 3, "new_sitework_cells": 42, "strategies": [ "stepped" ], "signature": "ce1db2f5cbb1b080fc2fa3ca9935435789268932b44dbbcf5d39386323086a15" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.51 ], [ 1, 0.81 ] ], "chosen": 0 } ], "artifact": "samples/adaptation-35.litematic", "seconds": 1.0395 }
adaptation-36validated{"environment_seed": 9, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, -0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 5.12982715086210.54016f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-36", "inputs": { "environment_seed": 9, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, -0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 5.129876042788569 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "93e5ae350cc8bf37aa6b7a0fc4f004359e77884c8cab1eb68df4f250d0704685", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "faaeb788c1919bfb049b03c074088d48bd7a102d8fc91d08b5283364d095aa8f", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 150, "excavation": 0, "sitework_occupied_cells": 159, "replaced_cells": 156, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "5a8dd500b0d3060ebd8a6ae1ec8030c2d8c8fa502446be0fced0013e0750323d" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 4.71 ] ], "chosen": 1 } ], "seconds": 0.5401 }
adaptation-37validated{"environment_seed": 9, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, -0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 5.12982606046210.30194234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-37", "inputs": { "environment_seed": 9, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, -0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 5.129876042788569 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "93e5ae350cc8bf37aa6b7a0fc4f004359e77884c8cab1eb68df4f250d0704685", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26060, "components": 46, "digest": "52441969234316921104ee834c06918eaa1ff8a5a71f0d211631fb5119c7c5d0", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 70, "excavation": 0, "sitework_occupied_cells": 79, "replaced_cells": 76, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "342614c02f3a134c26155f0498803da54a6111c2629ebabe23227209e3a060fb" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.31 ] ], "chosen": 1 } ], "seconds": 0.301 }
adaptation-38validated{"environment_seed": 9, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, -0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 5.12982715086210.53536f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-38", "inputs": { "environment_seed": 9, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, -0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 5.129876042788569 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "93e5ae350cc8bf37aa6b7a0fc4f004359e77884c8cab1eb68df4f250d0704685", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "faaeb788c1919bfb049b03c074088d48bd7a102d8fc91d08b5283364d095aa8f", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 150, "excavation": 0, "sitework_occupied_cells": 159, "replaced_cells": 156, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "5a8dd500b0d3060ebd8a6ae1ec8030c2d8c8fa502446be0fced0013e0750323d" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 4.71 ] ], "chosen": 1 } ], "seconds": 0.5353 }
adaptation-39validated{"environment_seed": 9, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, -0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 5.12982659764210.41187742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-39", "inputs": { "environment_seed": 9, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, -0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 5.129876042788569 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "93e5ae350cc8bf37aa6b7a0fc4f004359e77884c8cab1eb68df4f250d0704685", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26597, "components": 64, "digest": "ccb813a17ee996144bc995850786c48c95e9caaf126f93c2c1ae9c2e822b56e7", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 118, "excavation": 0, "sitework_occupied_cells": 127, "replaced_cells": 124, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "550133221787a50fcb484c8bc17342cb30e84e9cbdb5256770ee6f2fe62b3439" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.75 ] ], "chosen": 1 } ], "seconds": 0.4118 }
adaptation-40validated{"environment_seed": 10, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 4.542153886220.63216f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-40", "inputs": { "environment_seed": 10, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 4.544802917156937 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ -0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "463615be4e129e360e9b9479e15eac9dc55aa99eb79d2b012aa8fdd198b0134c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21538, "components": 86, "digest": "0772e886ef878d6921c21a296e0ff93e48ea800a4bc6ae7fa22bcbfd456ad980", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 37, "excavation": 0, "sitework_occupied_cells": 43, "replaced_cells": 3, "new_sitework_cells": 40, "strategies": [ "stepped" ], "signature": "3f03aa7e9ebbc08fbd6ffb58406b4a283a6ca1e633e8ca71bf205c4e95c664a7" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.49 ], [ 1, 0.74 ] ], "chosen": 0 } ], "seconds": 0.6321 }
adaptation-41validated{"environment_seed": 10, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 4.542042246220.329194234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-41", "inputs": { "environment_seed": 10, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 4.544802917156937 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ -0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "463615be4e129e360e9b9479e15eac9dc55aa99eb79d2b012aa8fdd198b0134c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 20422, "components": 46, "digest": "67c84ffd22005e35a1d04cf11779cefffa7982733d2246c3ced8a726e8c90c28", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 11, "excavation": 0, "sitework_occupied_cells": 17, "replaced_cells": 3, "new_sitework_cells": 14, "strategies": [ "stepped" ], "signature": "f45140d56aed2d3ce51c562f5326d70f269cf5b1ad572c4468e8043b90ef8db0" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.23 ], [ 1, 0.57 ] ], "chosen": 0 } ], "seconds": 0.3291 }
adaptation-42validated{"environment_seed": 10, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 4.542153886220.63236f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-42", "inputs": { "environment_seed": 10, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 4.544802917156937 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ -0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "463615be4e129e360e9b9479e15eac9dc55aa99eb79d2b012aa8fdd198b0134c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21538, "components": 86, "digest": "0772e886ef878d6921c21a296e0ff93e48ea800a4bc6ae7fa22bcbfd456ad980", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 37, "excavation": 0, "sitework_occupied_cells": 43, "replaced_cells": 3, "new_sitework_cells": 40, "strategies": [ "stepped" ], "signature": "3f03aa7e9ebbc08fbd6ffb58406b4a283a6ca1e633e8ca71bf205c4e95c664a7" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.49 ], [ 1, 0.74 ] ], "chosen": 0 } ], "seconds": 0.6323 }
adaptation-43validated{"environment_seed": 10, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 4.542096864220.46997742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-43", "inputs": { "environment_seed": 10, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 4.544802917156937 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ -0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "463615be4e129e360e9b9479e15eac9dc55aa99eb79d2b012aa8fdd198b0134c", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 20968, "components": 64, "digest": "e49a44ab559f97fd873c533170c02f453aba87ab99b96cc329cf56dcc8491aff", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 20, "excavation": 0, "sitework_occupied_cells": 26, "replaced_cells": 3, "new_sitework_cells": 23, "strategies": [ "stepped" ], "signature": "eef00916958ae76537b085a395097f5f02a4554248af35078d6ee64e8f5fa9e7" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.32 ], [ 1, 0.63 ] ], "chosen": 0 } ], "seconds": 0.4699 }
adaptation-44validated{"environment_seed": 11, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.112487186210.52386f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-44", "inputs": { "environment_seed": 11, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 2.1696793309977784 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, -0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "e312f891b7303218338c1769d64f2d98b9f0f35936a48b9268d9412912b422a5", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "8787dd0441779cfdc3972b6a8b25b3735fd47f4b98508d0e877f69accf61bb6a", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 99, "excavation": 0, "sitework_occupied_cells": 105, "replaced_cells": 102, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "e909625834e23412b1a12434a3820774c81bb4de3800fdb6c200ed2f7a17b6a9" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.09 ] ], "chosen": 1 } ], "seconds": 0.5238 }
adaptation-45validated{"environment_seed": 11, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.112378146210.282894234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-45", "inputs": { "environment_seed": 11, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 2.1696793309977784 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, -0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "e312f891b7303218338c1769d64f2d98b9f0f35936a48b9268d9412912b422a5", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 23781, "components": 46, "digest": "7e9a0b7e1d06a90f0ff48903c33ae36671359a6a733d93c4a1314730c7ad65c2", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 50, "excavation": 0, "sitework_occupied_cells": 56, "replaced_cells": 53, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "564423144e7352dc1ecd989234c5ef01c84d19b437c61f92b7780eff21a5a470" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.62 ] ], "chosen": 1 } ], "seconds": 0.2828 }
adaptation-46validated{"environment_seed": 11, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.112487186210.52066f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-46", "inputs": { "environment_seed": 11, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 2.1696793309977784 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, -0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "e312f891b7303218338c1769d64f2d98b9f0f35936a48b9268d9412912b422a5", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "8787dd0441779cfdc3972b6a8b25b3735fd47f4b98508d0e877f69accf61bb6a", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 99, "excavation": 0, "sitework_occupied_cells": 105, "replaced_cells": 102, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "e909625834e23412b1a12434a3820774c81bb4de3800fdb6c200ed2f7a17b6a9" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.09 ] ], "chosen": 1 } ], "seconds": 0.5206 }
adaptation-47validated{"environment_seed": 11, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.112431864210.39777742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-47", "inputs": { "environment_seed": 11, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 2.1696793309977784 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, -0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "e312f891b7303218338c1769d64f2d98b9f0f35936a48b9268d9412912b422a5", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24318, "components": 64, "digest": "4479c00a7a977093450803ac1c35bfc0652cf94a62d48363eef9ee94748476e6", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 82, "excavation": 0, "sitework_occupied_cells": 88, "replaced_cells": 85, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "4255ab465605a915de1af436918705081ccfd83752d4452ec437e81e329f5f24" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.58 ] ], "chosen": 1 } ], "seconds": 0.3977 }
adaptation-48validated{"environment_seed": 12, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 1.332487186210.51836f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-48", "inputs": { "environment_seed": 12, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 1.3321687906112092 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ -0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "0e546aa355b0fd2d833c0a9c4f666deab2afcdaf850d1ae628107f52aa47f120", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "57219198282c001363bb5fc38d46d4fb210ba88674e6cc4005ac0e5d033fe061", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 85, "excavation": 0, "sitework_occupied_cells": 91, "replaced_cells": 88, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "d3ad868c479bbf77b9f8830491b6ea116f1be13497b8d044801c2a409eacddc8" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.67 ] ], "chosen": 1 } ], "seconds": 0.5183 }
adaptation-49validated{"environment_seed": 12, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 1.332378146210.282794234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-49", "inputs": { "environment_seed": 12, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 1.3321687906112092 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ -0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "0e546aa355b0fd2d833c0a9c4f666deab2afcdaf850d1ae628107f52aa47f120", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 23781, "components": 46, "digest": "2cfdac891588d1d93c67c77b6f47784334388cd66321a10d54a75aa324e2fb10", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 35, "excavation": 0, "sitework_occupied_cells": 41, "replaced_cells": 38, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "1b4b7b0d79d57428a022e8a517d1fcddf115fd45952a800c6fdf917086dc70c7" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.17 ] ], "chosen": 1 } ], "seconds": 0.2827 }
adaptation-50validated{"environment_seed": 12, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 1.332487186210.56936f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-50", "inputs": { "environment_seed": 12, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 1.3321687906112092 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ -0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "0e546aa355b0fd2d833c0a9c4f666deab2afcdaf850d1ae628107f52aa47f120", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "57219198282c001363bb5fc38d46d4fb210ba88674e6cc4005ac0e5d033fe061", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 85, "excavation": 0, "sitework_occupied_cells": 91, "replaced_cells": 88, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "d3ad868c479bbf77b9f8830491b6ea116f1be13497b8d044801c2a409eacddc8" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.67 ] ], "chosen": 1 } ], "seconds": 0.5693 }
adaptation-51validated{"environment_seed": 12, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.035, 4]}, {"op": "wave", "args": [0.4, 0.13, 0.11, 1.332431864210.39717742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-51", "inputs": { "environment_seed": 12, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.035, 4 ] }, { "op": "wave", "args": [ 0.4, 0.13, 0.11, 1.3321687906112092 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ -0.035, 0, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "0e546aa355b0fd2d833c0a9c4f666deab2afcdaf850d1ae628107f52aa47f120", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24318, "components": 64, "digest": "e67704ef85d72083a597912ea9d966e8e608eee54bb6ce853992ef56aaf52076", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 58, "excavation": 0, "sitework_occupied_cells": 64, "replaced_cells": 61, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "6a6a133591eda1808b478261c979e3b33c1fd6416c6a2cb54a347ff8708a0a74" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.86 ] ], "chosen": 1 } ], "seconds": 0.3971 }
adaptation-52validated{"environment_seed": 13, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.11, 3.352268286220.64036f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-52", "inputs": { "environment_seed": 13, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 3.358718313814367 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "a888cc5f7af133dfc16886ca95bdd664349c34048f1f782e87935e744686a2bc", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 22682, "components": 86, "digest": "4824049b59a63780e8db6a541f49194c0bd371424ffb2f88407a4344d013148f", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "36cebeea96a6dfa0684e96ff304ff814e80a2700814c869914658edea2fd8113" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.6403 }
adaptation-53validated{"environment_seed": 13, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.11, 3.352159246220.334294234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-53", "inputs": { "environment_seed": 13, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 3.358718313814367 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "a888cc5f7af133dfc16886ca95bdd664349c34048f1f782e87935e744686a2bc", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 21592, "components": 46, "digest": "08cfdedf10ca3820c3254a762babfeb12cf0d96a7ee53a89a18e76a68165c62b", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "3c7ffb6a56f17204b971a96b6a54701f96f8ad65b81ad5061742fc80570d3154" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.3342 }
adaptation-54validated{"environment_seed": 13, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.11, 3.352268286220.63356f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-54", "inputs": { "environment_seed": 13, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 3.358718313814367 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "a888cc5f7af133dfc16886ca95bdd664349c34048f1f782e87935e744686a2bc", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 22682, "components": 86, "digest": "4824049b59a63780e8db6a541f49194c0bd371424ffb2f88407a4344d013148f", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "36cebeea96a6dfa0684e96ff304ff814e80a2700814c869914658edea2fd8113" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.6335 }
adaptation-55validated{"environment_seed": 13, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0, 4]}, {"op": "wave", "args": [0.8, 0.13, 0.11, 3.352212964220.47817742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-55", "inputs": { "environment_seed": 13, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0, 4 ] }, { "op": "wave", "args": [ 0.8, 0.13, 0.11, 3.358718313814367 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": null, "frozen_environment_digest": "a888cc5f7af133dfc16886ca95bdd664349c34048f1f782e87935e744686a2bc", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 22129, "components": 64, "digest": "d39a67e3b1df57e53c01ff8c9887cc929afe0472c3074706f0f630b84ed99dba", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "531d3dabce074082622786ea416e51f3410f2c34a82f81f2536b5d1299958c1b" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.4781 }
adaptation-56validated{"environment_seed": 14, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 2487186210.52656f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-56", "inputs": { "environment_seed": 14, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 2.046650951809069 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, -0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "62e474d9abdf20bf1d3d7bd59031496afc1918628aa3f953f889657a6ca2ac28", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "4865a57ec82272e01dbcdc78805cf8347e9e4d7243112d4068d789ee4e3f0479", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 98, "excavation": 0, "sitework_occupied_cells": 104, "replaced_cells": 101, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "1fb43fcd9f417e80652a115b8fe803d764d8cbc808731a17cd19c566e8a3e84a" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.06 ] ], "chosen": 1 } ], "seconds": 0.5265 }
adaptation-57validated{"environment_seed": 14, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 2378146210.285394234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-57", "inputs": { "environment_seed": 14, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 2.046650951809069 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, -0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "62e474d9abdf20bf1d3d7bd59031496afc1918628aa3f953f889657a6ca2ac28", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 23781, "components": 46, "digest": "60a31622d0a118f37ef4a07b0047b071a9cf9eb15d5bdf849a114feb88265f8a", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 45, "excavation": 0, "sitework_occupied_cells": 51, "replaced_cells": 48, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "fd86e72ae6e6377e5f0f2ba2730985cdefab576982d8a315e9a1598c2c0dfb9a" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.47 ] ], "chosen": 1 } ], "seconds": 0.2853 }
adaptation-58validated{"environment_seed": 14, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 2487186210.5236f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-58", "inputs": { "environment_seed": 14, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 2.046650951809069 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, -0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "62e474d9abdf20bf1d3d7bd59031496afc1918628aa3f953f889657a6ca2ac28", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24871, "components": 86, "digest": "4865a57ec82272e01dbcdc78805cf8347e9e4d7243112d4068d789ee4e3f0479", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 98, "excavation": 0, "sitework_occupied_cells": 104, "replaced_cells": 101, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "1fb43fcd9f417e80652a115b8fe803d764d8cbc808731a17cd19c566e8a3e84a" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.06 ] ], "chosen": 1 } ], "seconds": 0.523 }
adaptation-59validated{"environment_seed": 14, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [-0.045, -0.035, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 2431864210.40787742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-59", "inputs": { "environment_seed": 14, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ -0.045, -0.035, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 2.046650951809069 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0.035, -0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 5, "frozen_environment_digest": "62e474d9abdf20bf1d3d7bd59031496afc1918628aa3f953f889657a6ca2ac28", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 24318, "components": 64, "digest": "e1750f4beb1fece4bda56ee83a9d5abf5f278a295d66e0ddb33624d1702bf558", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 77, "excavation": 0, "sitework_occupied_cells": 83, "replaced_cells": 80, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "a15fb07bd90ccea889ff654bfefb068ab213e4ba0cfa6b638cc2afb8a6121ca5" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.43 ] ], "chosen": 1 } ], "seconds": 0.4078 }
adaptation-60validated{"environment_seed": 15, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 1.71002715086211.29956f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-60", "inputs": { "environment_seed": 15, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 1.7100020316024998 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "4196c15bbca4e1c9e1c635298fccbf29eeb438273c00d38681a993d3e5d2bca1", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "2f31b86e6c79b6080fc1b2e3f8ab8116bcb5ff56cf159a77fca2db4b29bf66e0", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 128, "excavation": 0, "sitework_occupied_cells": 137, "replaced_cells": 134, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "d72b32e4c7658848eb1ca6d72a34183fc5f3504e3865e48da632734c7808af76" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 4.05 ] ], "chosen": 1 } ], "artifact": "samples/adaptation-60.litematic", "seconds": 1.2995 }
adaptation-61validated{"environment_seed": 15, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 1.71002606046210.302294234e5ecf3559f7
记录 / 诊断
{ "label": "adaptation-61", "inputs": { "environment_seed": 15, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 1.7100020316024998 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "4196c15bbca4e1c9e1c635298fccbf29eeb438273c00d38681a993d3e5d2bca1", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26060, "components": 46, "digest": "dfc403350fef4bc053bbec7e80a33b452ccecbcc50fd09b45bca594a3520bdd4", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 64, "excavation": 0, "sitework_occupied_cells": 73, "replaced_cells": 70, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "d37676140506bd9efd2668bf30d314d20c8be9411cff12f088d4ce8a53b1b4ff" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.13 ] ], "chosen": 1 } ], "seconds": 0.3022 }
adaptation-62validated{"environment_seed": 15, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 1.71002715086210.53256f82a660419c68dc
记录 / 诊断
{ "label": "adaptation-62", "inputs": { "environment_seed": 15, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 1.7100020316024998 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "4196c15bbca4e1c9e1c635298fccbf29eeb438273c00d38681a993d3e5d2bca1", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 27150, "components": 86, "digest": "2f31b86e6c79b6080fc1b2e3f8ab8116bcb5ff56cf159a77fca2db4b29bf66e0", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 128, "excavation": 0, "sitework_occupied_cells": 137, "replaced_cells": 134, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "d72b32e4c7658848eb1ca6d72a34183fc5f3504e3865e48da632734c7808af76" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 4.05 ] ], "chosen": 1 } ], "seconds": 0.5325 }
adaptation-63validated{"environment_seed": 15, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "blend", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.045, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.11, 1.71002659764210.40667742cfa30b736aa0
记录 / 诊断
{ "label": "adaptation-63", "inputs": { "environment_seed": 15, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "blend", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.045, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.11, 1.7100020316024998 ] } ] }, { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.045, 4 ] }, { "op": "wave", "args": [ 0.6, 0.07, 0.19, 0 ] } ] }, { "op": "transform", "args": [ { "op": "radial", "args": [ 8, 9, 28, 0.7 ] }, 2, -1, 1.2 ] } ] }, 2, 7 ] }, "water": 6, "frozen_environment_digest": "4196c15bbca4e1c9e1c635298fccbf29eeb438273c00d38681a993d3e5d2bca1", "environment_domain": [ [ -8, -4, -18 ], [ 34, 64, 34 ] ], "held_out": true }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 26597, "components": 64, "digest": "bee5bf5d0c3ae86638a76f0f595e6a4d4fe9982087a4364fce5a2daa233467f9", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 96, "excavation": 0, "sitework_occupied_cells": 105, "replaced_cells": 102, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "ba5e8498b3ec2236586b04fbccc4c604e7b1350249de5bc493a4d9394a48882e" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 3.09 ] ], "chosen": 1 } ], "seconds": 0.4066 }
dwelling-0validated{"program": "dwelling", "seed": 0}1548186221.12726f82a660419c68dc
记录 / 诊断
{ "label": "dwelling-0", "inputs": { "program": "dwelling", "seed": 0 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 15481, "components": 86, "digest": "2977b81e46cae5bfb9dd7fc5c4b7d5428b7abeaaf168bc9b92a71a86b41aa0bd", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 50, "excavation": 0, "sitework_occupied_cells": 56, "replaced_cells": 3, "new_sitework_cells": 53, "strategies": [ "stepped" ], "signature": "95b2ce5c5923fc6490c42c491e3e86ab582ee9c21f4ef505ad158c8b4142395d" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.62 ], [ 1, 0.88 ] ], "chosen": 0 } ], "artifact": "samples/dwelling-0.litematic", "seconds": 1.1272 }
dwelling-1validated{"program": "dwelling", "seed": 1}914046220.570394234e5ecf3559f7
记录 / 诊断
{ "label": "dwelling-1", "inputs": { "program": "dwelling", "seed": 1 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 9140, "components": 46, "digest": "c4835f328ec6ae87c8b4754e7526b355fb4820b4400de8845d7061468af57d4c", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 11, "excavation": 0, "sitework_occupied_cells": 17, "replaced_cells": 3, "new_sitework_cells": 14, "strategies": [ "stepped" ], "signature": "9da6d4b3680216a47afb618754afcbc65977c551639cbb92a81ce298c9e0e885" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.23 ], [ 1, 0.58 ] ], "chosen": 0 } ], "artifact": "samples/dwelling-1.litematic", "seconds": 0.5703 }
dwelling-2validated{"program": "dwelling", "seed": 2}1555686220.65376f82a660419c68dc
记录 / 诊断
{ "label": "dwelling-2", "inputs": { "program": "dwelling", "seed": 2 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 15556, "components": 86, "digest": "2f2e2efcc857641bf3af87ce50400d8da7119887036fcd8e5b4043d51804dc4c", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 34, "excavation": 0, "sitework_occupied_cells": 42, "replaced_cells": 1, "new_sitework_cells": 41, "strategies": [ "stepped" ], "signature": "dedcb18d92acb8b747e7d9b86622b9d505f557e80f259d6e2a0335b2686894a6" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.44 ], [ 1, 0.81 ] ], "chosen": 0 } ], "seconds": 0.6537 }
dwelling-3validated{"program": "dwelling", "seed": 3}1139564220.45937742cfa30b736aa0
记录 / 诊断
{ "label": "dwelling-3", "inputs": { "program": "dwelling", "seed": 3 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 11395, "components": 64, "digest": "3f4f4e52cb8ef41fd1cc28f225809e272a88d3a883477c98dd8151ed56bfb564", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 6, "replaced_cells": 3, "new_sitework_cells": 3, "strategies": [ "stepped" ], "signature": "dfdaec8dfeef4b2504bb79fb3cb37b656aa25ea0b5493a9692696ded695dfbba" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 0.4593 }
dwelling-4validated{"program": "dwelling", "seed": 4}1911592220.91119f3c0d02902e928c
记录 / 诊断
{ "label": "dwelling-4", "inputs": { "program": "dwelling", "seed": 4 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 19115, "components": 92, "digest": "386d30923299173c67eed7ff484697911489f548b833405fd5c729898c9d2f29", "principal_signature": "9f3c0d02902e928c0d5603178d47a3ad4494c7ab06e4f1dd966d4d9cfebaa7f7", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ], [ 11, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 255 ], [ "z", 11, true, 256 ], [ "z", 11, true, 277 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 34, "excavation": 0, "sitework_occupied_cells": 40, "replaced_cells": 3, "new_sitework_cells": 37, "strategies": [ "piers" ], "signature": "739d5ced77f4e14a92963dca4394344731ad474954d22435ae865fd7fe0df226" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.48 ], [ 1, 0.86 ] ], "chosen": 1 } ], "seconds": 0.9111 }
dwelling-5validated{"program": "dwelling", "seed": 5}1912392220.96549f3c0d02902e928c
记录 / 诊断
{ "label": "dwelling-5", "inputs": { "program": "dwelling", "seed": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 19123, "components": 92, "digest": "9081236c4bd6a9df2eec4e6a173d5446a859a839b69be8f59488538581dc44ac", "principal_signature": "9f3c0d02902e928c0d5603178d47a3ad4494c7ab06e4f1dd966d4d9cfebaa7f7", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ], [ 11, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 255 ], [ "z", 11, true, 256 ], [ "z", 11, true, 277 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 37, "excavation": 0, "sitework_occupied_cells": 43, "replaced_cells": 3, "new_sitework_cells": 40, "strategies": [ "piers" ], "signature": "6d8460315b0f9f75a89ed2e4456641e390f497a8f44659105ddf028e297e26c1" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.63 ], [ 1, 0.89 ] ], "chosen": 1 } ], "seconds": 0.9654 }
dwelling-6validated{"program": "dwelling", "seed": 6}1029650220.70157676b0a0ab7b4410
记录 / 诊断
{ "label": "dwelling-6", "inputs": { "program": "dwelling", "seed": 6 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 10296, "components": 50, "digest": "8728a1b81f9e96129c32393dfba09119dcb3596623024a5780ef7d3cb418fafe", "principal_signature": "7676b0a0ab7b441021fd8a6f7034b32d0602402e654f33bc1be65f62fb413691", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 0, "excavation": 0, "sitework_occupied_cells": 3, "replaced_cells": 3, "new_sitework_cells": 0, "strategies": [ "stepped" ], "signature": "e04ba2832711857ce8c1504c0a1df3993961b6c7e603cef4687b07cfef839d22" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.09 ], [ 1, 0.49 ] ], "chosen": 0 } ], "artifact": "samples/dwelling-6.litematic", "seconds": 0.7015 }
dwelling-7validated{"program": "dwelling", "seed": 7}1140864220.46517742cfa30b736aa0
记录 / 诊断
{ "label": "dwelling-7", "inputs": { "program": "dwelling", "seed": 7 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 11408, "components": 64, "digest": "427eedc8707fb3b2d8a80989cfcfdad20037b85bcb84369979a6ce8316e05226", "principal_signature": "7742cfa30b736aa0fcc59f5ede4f21c26aabdb7eaa5b8cb80852f4886a5322a2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 52, "excavation": 0, "sitework_occupied_cells": 58, "replaced_cells": 3, "new_sitework_cells": 55, "strategies": [ "stepped" ], "signature": "0df6efb5f68fd1736918df205dca8bd3c0d7a4f536c57a08d5b8fb653b4fa927" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.64 ], [ 1, 0.89 ] ], "chosen": 0 } ], "seconds": 0.4651 }
atelier-0validated{"program": "atelier", "seed": 0}1407846220.9555cccfe23c55bfa493
记录 / 诊断
{ "label": "atelier-0", "inputs": { "program": "atelier", "seed": 0 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 14078, "components": 46, "digest": "3311b96b11aedb81e17cdd07dcf58a8fc58b481fe9beb389f4889f3e467e9d2f", "principal_signature": "cccfe23c55bfa49368fb86c1b1c5ccc535b0aedfe423d30daee6e9f5f37ca3ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "east" ], false, [ -1, 0, -1, 10, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 458 ] ], "porch": false, "bay": 11 } ], "organization": [] }, "contact": { "fill": 39, "excavation": 0, "sitework_occupied_cells": 45, "replaced_cells": 3, "new_sitework_cells": 42, "strategies": [ "stepped" ], "signature": "ec68c37a351051eeec6ce625041e17d6c017d564c7b1c1763f6036269eb56680" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.51 ], [ 1, 0.8 ] ], "chosen": 0 } ], "artifact": "samples/atelier-0.litematic", "seconds": 0.9555 }
atelier-1validated{"program": "atelier", "seed": 1}1427948221.0141890465482154ae55
记录 / 诊断
{ "label": "atelier-1", "inputs": { "program": "atelier", "seed": 1 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 14279, "components": 48, "digest": "2c618298e44b80076d55170f85bf4ce5e868c3c5ad8a2561b39586449752edbf", "principal_signature": "890465482154ae55365761a8ff7bddeca47f9aef339a24f2424dd702153587ff", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "east" ], false, [ -1, 0, -1, 10, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 458 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 33, "excavation": 0, "sitework_occupied_cells": 39, "replaced_cells": 3, "new_sitework_cells": 36, "strategies": [ "stepped" ], "signature": "50641dbdbc620389572b5a232e0247f39153adf5be057b56c726e8c4b9dafa7a" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.45 ], [ 1, 0.71 ] ], "chosen": 0 } ], "artifact": "samples/atelier-1.litematic", "seconds": 1.0141 }
atelier-2validated{"program": "atelier", "seed": 2}1895691220.86782183bdaa015a453a
记录 / 诊断
{ "label": "atelier-2", "inputs": { "program": "atelier", "seed": 2 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 18956, "components": 91, "digest": "fa0aa904fa3a67712e4877a5c19840b6d5cae7338067d9a621a1e09465496d23", "principal_signature": "2183bdaa015a453a1ae5ef7e55dc2c9c83cf57641dc49ce40a8fc392ccd13011", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], true, [ 0, 0, -1, 11, 6, 11 ] ], [ 11, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 254 ], [ "x", 11, true, 266 ], [ "x", 11, true, 277 ] ], "porch": false, "bay": 11 } ], "organization": [] }, "contact": { "fill": 36, "excavation": 0, "sitework_occupied_cells": 43, "replaced_cells": 2, "new_sitework_cells": 41, "strategies": [ "stepped" ], "signature": "068ea5f58f529b573241baf74f45a39434341ea9687e79c00a346df30c26aa37" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.47 ], [ 1, 0.85 ] ], "chosen": 0 } ], "seconds": 0.8678 }
atelier-3validated{"program": "atelier", "seed": 3}1412846220.5825fcb0539969a632f6
记录 / 诊断
{ "label": "atelier-3", "inputs": { "program": "atelier", "seed": 3 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 14128, "components": 46, "digest": "591aea04788353fbeeddbc13034e99f9a32c1f10b6a125fb35765e1995ac3ad5", "principal_signature": "fcb0539969a632f621e72fade63ec6354241f24b641a63cc8c57ad0f701abf91", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "east" ], false, [ -1, 0, -1, 10, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, false, 424 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 42, "excavation": 0, "sitework_occupied_cells": 54, "replaced_cells": 3, "new_sitework_cells": 51, "strategies": [ "stepped" ], "signature": "f7cf30e58fc7c90a4875df300c087539c70b236642b753e53b849cddad140cdd" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.6 ], [ 1, 0.91 ] ], "chosen": 0 } ], "seconds": 0.5825 }
atelier-4validated{"program": "atelier", "seed": 4}1196546220.47999f4c83f7404661ae
记录 / 诊断
{ "label": "atelier-4", "inputs": { "program": "atelier", "seed": 4 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 11965, "components": 46, "digest": "92c0a3bd4b66eea1426abc2c47e85d3eb3f52c838a26f57cc448d8452e96ee7d", "principal_signature": "9f4c83f7404661ae87524e0704372c66d149d825ea1a486a67515ef82688aa1b", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "east" ], false, [ -1, 0, -1, 8, 6, 9 ] ], [ 9, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 332 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 16, "excavation": 0, "sitework_occupied_cells": 23, "replaced_cells": 2, "new_sitework_cells": 21, "strategies": [ "piers" ], "signature": "13eebbe941c91aad6c6841a084e36763ad3aae0c2c6d9b1e78a2394f2c6e5292" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.29 ], [ 1, 0.67 ] ], "chosen": 1 } ], "seconds": 0.4799 }
atelier-5validated{"program": "atelier", "seed": 5}1512564220.59195abc5190315525b4
记录 / 诊断
{ "label": "atelier-5", "inputs": { "program": "atelier", "seed": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 15125, "components": 64, "digest": "df80ce8ff088c7d9f0970a8e55e92d3d5eaeba62d0a323bde80adf2b408ce83f", "principal_signature": "5abc5190315525b41e14852d76d554c49bfbe1987c9f742b19d66f3e7adc5ef2", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 323 ], [ "x", 9, true, 194 ] ], "porch": false, "bay": 9 } ], "organization": [] }, "contact": { "fill": 18, "excavation": 0, "sitework_occupied_cells": 24, "replaced_cells": 3, "new_sitework_cells": 21, "strategies": [ "piers" ], "signature": "ca084e03076eb7cd78beb200a46917abd3ca86002a24b4abb1559aacbb13bac6" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.39 ], [ 1, 0.7 ] ], "chosen": 1 } ], "seconds": 0.5919 }
atelier-6validated{"program": "atelier", "seed": 6}1543787221.13918043cef60f958182
记录 / 诊断
{ "label": "atelier-6", "inputs": { "program": "atelier", "seed": 6 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 15437, "components": 87, "digest": "5abd655c4bcb521f626a049cf7194a7de48f7bd0564cef9c09d0d774ff7c1771", "principal_signature": "8043cef60f9581829e6448fc4a226995c47e95359b3a55e02ac14b85d6b16830", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.storage", [ "west" ], true, [ 0, 0, -1, 9, 6, 9 ] ], [ 9, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 183 ], [ "x", 9, true, 192 ], [ "x", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 61, "excavation": 0, "sitework_occupied_cells": 67, "replaced_cells": 3, "new_sitework_cells": 64, "strategies": [ "stepped" ], "signature": "3b9693daa6bb1a537e9719a6eb9710422c00215e191b99a7cfdeda9f4b3cd77a" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.73 ], [ 1, 1.0 ] ], "chosen": 0 } ], "artifact": "samples/atelier-6.litematic", "seconds": 1.1391 }
atelier-7validated{"program": "atelier", "seed": 7}1846366220.82059def921f7bc69875
记录 / 诊断
{ "label": "atelier-7", "inputs": { "program": "atelier", "seed": 7 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 18463, "components": 66, "digest": "6d04d30e81180a08837e50ebb10fe4e11041b930fa3071afef750e6bc05f79e2", "principal_signature": "9def921f7bc69875f6605a7da8b48b9ddab8709a3e4bd23ffb3b37fb8b4b92c6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, false, 413 ], [ "x", 11, false, 234 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 66, "excavation": 0, "sitework_occupied_cells": 72, "replaced_cells": 3, "new_sitework_cells": 69, "strategies": [ "stepped" ], "signature": "f91bbe3926cffd82cb4261fcb1681accf9d56bdb9d131b7b2835764778723f12" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.78 ], [ 1, 1.07 ] ], "chosen": 0 } ], "seconds": 0.8205 }
commons-0validated{"program": "commons", "seed": 0}1905993221.4927408aac550183d223
记录 / 诊断
{ "label": "commons-0", "inputs": { "program": "commons", "seed": 0 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 19059, "components": 93, "digest": "bc4f40fb526850968efd7da87830b5483e8f908c740c5c8dd9ee4532fc053b36", "principal_signature": "408aac550183d22300d54cddcf8df8f931c6895396ba93412a374b7d722774c1", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], false, [ -1, 0, -1, 11, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north", "east" ], true, [ -1, 0, 0, 10, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 11, "room.kitchen", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 260 ], [ "z", 11, true, 253 ], [ "z", 11, true, 277 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 67, "excavation": 0, "sitework_occupied_cells": 73, "replaced_cells": 3, "new_sitework_cells": 70, "strategies": [ "stepped" ], "signature": "8849fd2e7cbfc14e33b2265650b6e88ff7763a72c3af482fdb23d7c6eabbabdc" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.79 ], [ 1, 1.09 ] ], "chosen": 0 } ], "artifact": "samples/commons-0.litematic", "seconds": 1.4927 }
commons-1validated{"program": "commons", "seed": 1}20143128221.9167a83f8846c358d48c
记录 / 诊断
{ "label": "commons-1", "inputs": { "program": "commons", "seed": 1 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 20143, "components": 128, "digest": "8822663aa5b6881c5d3abeb63cde45a698ee2ae5eec1bb32bc9682eac592e939", "principal_signature": "a83f8846c358d48c84548c13dbe92ddf4e1f4a5890b0f29c1ebb645eaa1bea0f", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north", "east" ], true, [ -1, 0, 0, 10, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 12, 11, "room.library", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "south", "west" ], false, [ 0, 0, -1, 11, 6, 10 ] ], [ 11, 0, 11, "room.kitchen", [ "north", "west" ], false, [ 0, 0, 0, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 246 ], [ "z", 11, true, 417 ], [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 70, "excavation": 0, "sitework_occupied_cells": 76, "replaced_cells": 3, "new_sitework_cells": 73, "strategies": [ "stepped" ], "signature": "8c120697b34c7fb2f401694143994f5e538e0321a9ffdc137ac9001eafdc90dc" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.82 ], [ 1, 1.22 ] ], "chosen": 0 } ], "artifact": "samples/commons-1.litematic", "seconds": 1.9167 }
commons-2validated{"program": "commons", "seed": 2}19553113221.03043bc4b1fcf0ff742c
记录 / 诊断
{ "label": "commons-2", "inputs": { "program": "commons", "seed": 2 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 19553, "components": 113, "digest": "c1b164806ab287554fbd7bd4268a82173d94bbb5af7f6806de8ce39130400573", "principal_signature": "3bc4b1fcf0ff742c6777fe44a9f58a00b259e35d303a12a8d442cfb1ace47f6b", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], false, [ -1, 0, -1, 11, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north", "east" ], true, [ -1, 0, 0, 10, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 12, 11, "room.library", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 11, "room.kitchen", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 257 ], [ "z", 11, true, 253 ], [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 54, "excavation": 0, "sitework_occupied_cells": 61, "replaced_cells": 2, "new_sitework_cells": 59, "strategies": [ "stepped" ], "signature": "38e63d3c879e82337ca9911597736d084f00dc4f3d7d57d889e4678cb8ee52ae" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.65 ], [ 1, 1.05 ] ], "chosen": 0 } ], "seconds": 1.0304 }
commons-3validated{"program": "commons", "seed": 3}19710108221.1199f4aa0d06e791c7ed
记录 / 诊断
{ "label": "commons-3", "inputs": { "program": "commons", "seed": 3 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 19710, "components": 108, "digest": "4a1472bb4cdb93f555c4bfac529899383d5499c87da1d77a07c239c77b0f2c9b", "principal_signature": "f4aa0d06e791c7ed9d1d07f54eb2ff2698a18e4bdb7622f9220a15281da5275a", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north", "east" ], true, [ -1, 0, 0, 10, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "south", "west" ], false, [ 0, 0, -1, 11, 6, 10 ] ], [ 11, 0, 11, "room.kitchen", [ "north", "west" ], false, [ 0, 0, 0, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 249 ], [ "z", 11, true, 417 ], [ "z", 11, true, 277 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 59, "excavation": 0, "sitework_occupied_cells": 71, "replaced_cells": 3, "new_sitework_cells": 68, "strategies": [ "stepped" ], "signature": "911b2c5f01aa9c85b805e166d71fd7f463d7375089c7673a4f26aed21e89040f" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.77 ], [ 1, 1.15 ] ], "chosen": 0 } ], "seconds": 1.1199 }
commons-4validated{"program": "commons", "seed": 4}1913393220.9768408aac550183d223
记录 / 诊断
{ "label": "commons-4", "inputs": { "program": "commons", "seed": 4 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 19133, "components": 93, "digest": "2d10de15a6c94f3c9b61f335419cf21571c1fa3b0d9fe6422b172825842d5b5f", "principal_signature": "408aac550183d22300d54cddcf8df8f931c6895396ba93412a374b7d722774c1", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], false, [ -1, 0, -1, 11, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north", "east" ], true, [ -1, 0, 0, 10, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 11, "room.kitchen", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 260 ], [ "z", 11, true, 253 ], [ "z", 11, true, 277 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 50, "excavation": 0, "sitework_occupied_cells": 56, "replaced_cells": 3, "new_sitework_cells": 53, "strategies": [ "piers" ], "signature": "ca638d4b5814384bb53959e869ce9ea8c986dffba2a86a8044afc58b8b3ad4a0" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.62 ], [ 1, 1.02 ] ], "chosen": 1 } ], "seconds": 0.9768 }
commons-5validated{"program": "commons", "seed": 5}1915193220.9298408aac550183d223
记录 / 诊断
{ "label": "commons-5", "inputs": { "program": "commons", "seed": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 19151, "components": 93, "digest": "045c403a2f42996967c72526cdd2da4b4ce4afe4ed32cf5c864fb2ac18c6bc7e", "principal_signature": "408aac550183d22300d54cddcf8df8f931c6895396ba93412a374b7d722774c1", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], false, [ -1, 0, -1, 11, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north", "east" ], true, [ -1, 0, 0, 10, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 11, "room.kitchen", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 260 ], [ "z", 11, true, 253 ], [ "z", 11, true, 277 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 63, "excavation": 0, "sitework_occupied_cells": 69, "replaced_cells": 3, "new_sitework_cells": 66, "strategies": [ "piers" ], "signature": "e927f546579996432ddff3d7f79c597088d0e6c15d5068048be41b9edba52b51" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.83 ], [ 1, 1.15 ] ], "chosen": 1 } ], "seconds": 0.9298 }
commons-6validated{"program": "commons", "seed": 6}15828105221.2213c15c3d27647f2b6e
记录 / 诊断
{ "label": "commons-6", "inputs": { "program": "commons", "seed": 6 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 15828, "components": 105, "digest": "8c5eefc70effe4a689bc5d027bb64885f1cb85cf45ae955e91e4390034654898", "principal_signature": "c15c3d27647f2b6e11d4652ab976088ad27e01603b2c7c0754a50bc589c75e77", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], false, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 0, 9, "room.living", [ "north", "east" ], true, [ -1, 0, 0, 8, 6, 9 ] ], [ 0, 6, 9, "room.bedroom", [], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 12, 9, "room.library", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 9, 0, 9, "room.kitchen", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 61, "excavation": 0, "sitework_occupied_cells": 67, "replaced_cells": 3, "new_sitework_cells": 64, "strategies": [ "stepped" ], "signature": "a8a35d6d5ba068b4d06b8b124b9f196449ce61435e95f26714631fbb8346bc30" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.73 ], [ 1, 0.99 ] ], "chosen": 0 } ], "artifact": "samples/commons-6.litematic", "seconds": 1.2213 }
commons-7validated{"program": "commons", "seed": 7}20098128221.2951a83f8846c358d48c
记录 / 诊断
{ "label": "commons-7", "inputs": { "program": "commons", "seed": 7 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 20098, "components": 128, "digest": "075bfab04f7afb6bca401744f8053d6e14a25f42d84eb7eca9567ea78d44c921", "principal_signature": "a83f8846c358d48c84548c13dbe92ddf4e1f4a5890b0f29c1ebb645eaa1bea0f", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north", "east" ], true, [ -1, 0, 0, 10, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 12, 11, "room.library", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "south", "west" ], false, [ 0, 0, -1, 11, 6, 10 ] ], [ 11, 0, 11, "room.kitchen", [ "north", "west" ], false, [ 0, 0, 0, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 246 ], [ "z", 11, true, 417 ], [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 59, "excavation": 0, "sitework_occupied_cells": 65, "replaced_cells": 3, "new_sitework_cells": 62, "strategies": [ "stepped" ], "signature": "b428fbceb5984bec22075e620dfa2d01e0cf5182875c9b08a50d546bec2df0b4" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.71 ], [ 1, 1.09 ] ], "chosen": 0 } ], "seconds": 1.2951 }
settlement-0-seededvalidated{"program": "settlement", "seed": 0, "count": null}12547578210107.485a5e69d2105108e2a
记录 / 诊断
{ "label": "settlement-0-seeded", "inputs": { "program": "settlement", "seed": 0, "count": null }, "attempts": 10, "retries": 0, "status": "validated", "blocks": 125475, "components": 782, "digest": "e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9", "principal_signature": "a5e69d2105108e2af50f7c163efd47a3e398765881fed1bd11ac7f95d20cacd6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north" ], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, false, 248 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north" ], true, [ -1, 0, 0, 11, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 12, 11, "room.library", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, false, 214 ], [ "z", 11, false, 232 ], [ "z", 11, false, 248 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 12, 0, "room.library", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": false, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south" ], true, [ -1, 0, -1, 11, 6, 10 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 255 ], [ "x", 11, true, 282 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.living", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 323 ], [ "z", 9, true, 190 ] ], "porch": false, "bay": 9 } ], "organization": [ { "points": [ [ -11, 0 ], [ -3, 0 ], [ 11, -2 ], [ 3, -2 ], [ -13, 36 ], [ -3, 36 ], [ 10, 38 ], [ 3, 38 ], [ -13, 76 ], [ -3, 76 ], [ -3, -2 ], [ -3, 76 ], [ 3, 76 ], [ 3, -2 ], [ 5, 15 ], [ 3, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7 ], [ 8, 9 ], [ 10, 11 ], [ 11, 12 ], [ 12, 13 ], [ 13, 10 ], [ 14, 15 ], [ 1, 16 ] ] } ] }, "contact": { "fill": 149, "excavation": 0, "sitework_occupied_cells": 930, "replaced_cells": 766, "new_sitework_cells": 164, "strategies": [ "piers", "stepped", "stepped", "piers", "stepped" ], "signature": "40ce9601174e3616d4b941a8165ab596d421e92f596c4c00453514bf6129e854" }, "accepted_candidates": 10, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.21 ], [ 1, 0.59 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.43 ], [ 1, 0.77 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-3", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.87 ], [ 1, 1.14 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-4", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.77 ], [ 1, 1.07 ] ], "chosen": 0 } ], "seconds": 7.485 }
settlement-1-seededvalidated{"program": "settlement", "seed": 1, "count": null}90100527666.99fe9e340c528ebe64
记录 / 诊断
{ "label": "settlement-1-seeded", "inputs": { "program": "settlement", "seed": 1, "count": null }, "attempts": 6, "retries": 0, "status": "validated", "blocks": 90100, "components": 527, "digest": "59aa67be3d333173651d8f3af577d2a0e9f24ca4db341ecc424a2f2be830b2d3", "principal_signature": "fe9e340c528ebe64424687d71610fb3a12c07d79fae867c5f27c0f5cd170fcc5", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, false, 413 ], [ "x", 11, false, 234 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.kitchen", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 186 ], [ "x", 9, true, 182 ], [ "x", 9, true, 202 ] ], "porch": true, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], false, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 0, 9, "room.living", [ "north" ], true, [ -1, 0, 0, 9, 6, 9 ] ], [ 0, 6, 9, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 187 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [ { "points": [ [ -10, 0 ], [ -3, 0 ], [ 11, 2 ], [ 3, 2 ], [ -10, 40 ], [ -3, 40 ], [ -3, 0 ], [ -3, 40 ], [ 3, 40 ], [ 3, 0 ], [ 5, 15 ], [ 3, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7 ], [ 7, 8 ], [ 8, 9 ], [ 9, 6 ], [ 10, 11 ], [ 1, 12 ] ] } ] }, "contact": { "fill": 160, "excavation": 0, "sitework_occupied_cells": 742, "replaced_cells": 476, "new_sitework_cells": 266, "strategies": [ "stepped", "stepped", "piers" ], "signature": "de5d605395a519fbdf3c5a302c3f107106197889c5c9bf9de901c182bb39dcbc" }, "accepted_candidates": 6, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 1, 1.31 ], [ 0, 1.46 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.63 ], [ 1, 0.9 ] ], "chosen": 1 } ], "artifact": "samples/settlement-1-seeded.litematic", "seconds": 6.99 }
settlement-2-seededvalidated{"program": "settlement", "seed": 2, "count": null}92451614885.68234ede2e33be272666
记录 / 诊断
{ "label": "settlement-2-seeded", "inputs": { "program": "settlement", "seed": 2, "count": null }, "attempts": 8, "retries": 0, "status": "validated", "blocks": 92451, "components": 614, "digest": "09149f3e7b613ad7fb392e1528ca66dbc79dac74879f4da23e95b481d4184d96", "principal_signature": "4ede2e33be272666188dfe6694bafbe76d853db44026fca2ce188af8ef6f1cca", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.living", [ "north" ], true, [ -1, 0, 0, 9, 6, 9 ] ], [ 0, 6, 9, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 9, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 310 ], [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], true, [ -1, 0, 0, 11, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 431 ], [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "east" ], false, [ -1, 0, -1, 10, 6, 11 ] ], [ 11, 0, 0, "room.living", [ "west" ], true, [ 0, 0, -1, 11, 6, 11 ] ], [ 11, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 260 ], [ "x", 11, true, 277 ] ], "porch": false, "bay": 11 } ], "organization": [ { "points": [ [ -11, -2 ], [ 0, -2 ], [ 11, 2 ], [ 0, 2 ], [ -10, 38 ], [ 0, 38 ], [ 14, 40 ], [ 0, 40 ], [ 5, 15 ], [ 0, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 1, 3 ], [ 4, 5 ], [ 3, 5 ], [ 6, 7 ], [ 5, 7 ], [ 8, 9 ], [ 1, 9 ], [ 1, 10 ] ] } ] }, "contact": { "fill": 77, "excavation": 0, "sitework_occupied_cells": 561, "replaced_cells": 411, "new_sitework_cells": 150, "strategies": [ "piers", "piers", "piers", "stepped" ], "signature": "332f5c3e65ae1c51f5d52e70e92531996c3ce7ca6ef4e9846fffe5084f470a50" }, "accepted_candidates": 8, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.35 ], [ 1, 0.65 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.98 ], [ 1, 1.22 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-3", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 5.6823 }
settlement-3-seededvalidated{"program": "settlement", "seed": 3, "count": null}89484516663.94840e6e9036e034cb63
记录 / 诊断
{ "label": "settlement-3-seeded", "inputs": { "program": "settlement", "seed": 3, "count": null }, "attempts": 6, "retries": 0, "status": "validated", "blocks": 89484, "components": 516, "digest": "a9256f86658c94632a469d3535d9d08b1252a44418c5dfbbb23b99fdb4a7999a", "principal_signature": "0e6e9036e034cb63d646b3cd2a0cad66cdb96733b28dfe2cf3c8885138545a2e", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.living", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 323 ], [ "x", 9, true, 194 ] ], "porch": true, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.living", [ "west" ], true, [ 0, 0, -1, 9, 6, 9 ] ], [ 9, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 311 ], [ "z", 9, true, 206 ] ], "porch": false, "bay": 9 } ], "organization": [ { "points": [ [ -11, 0 ], [ 0, 0 ], [ 11, -2 ], [ 0, -2 ], [ -13, 40 ], [ 0, 40 ], [ 5, 15 ], [ 0, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 1, 3 ], [ 4, 5 ], [ 3, 5 ], [ 6, 7 ], [ 1, 7 ], [ 1, 8 ] ] } ] }, "contact": { "fill": 83, "excavation": 0, "sitework_occupied_cells": 550, "replaced_cells": 378, "new_sitework_cells": 172, "strategies": [ "piers", "piers", "stepped" ], "signature": "9d3037bd15ef4888b1c0363fd6a28a0fa6ac1d7355af03fae751a5b1ac4b4c7c" }, "accepted_candidates": 6, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.32 ], [ 1, 0.66 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 1, 0.66 ], [ 0, 0.87 ] ], "chosen": 0 } ], "seconds": 3.9484 }
settlement-4-seededvalidated{"program": "settlement", "seed": 4, "count": null}12553777710107.7168c5918ebf660465d1
记录 / 诊断
{ "label": "settlement-4-seeded", "inputs": { "program": "settlement", "seed": 4, "count": null }, "attempts": 10, "retries": 0, "status": "validated", "blocks": 125537, "components": 777, "digest": "163de26bc61999252ff940e7bf37b78f3cc336bdc72a3d3c8b8bbf8f1367c06a", "principal_signature": "c5918ebf660465d1f273f7e69fffa76dc6078c443387d7cbca83b9f740bebfec", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 6, 0, "room.bedroom", [], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 12, 0, "room.library", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 282 ] ], "porch": false, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.storage", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ], [ 11, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 447 ], [ "z", 11, true, 268 ] ], "porch": false, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 12, 0, "room.library", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.living", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 181 ], [ "z", 9, true, 206 ] ], "porch": false, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], true, [ -1, 0, -1, 9, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.living", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 184 ], [ "x", 9, true, 206 ] ], "porch": false, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], false, [ -1, 0, -1, 11, 6, 10 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 458 ] ], "porch": true, "bay": 11 } ], "organization": [ { "points": [ [ -14, 0 ], [ -3, 0 ], [ 13, 2 ], [ 3, 2 ], [ -14, 40 ], [ -3, 40 ], [ 14, 38 ], [ 3, 38 ], [ -10, 78 ], [ -3, 78 ], [ -3, 0 ], [ -3, 78 ], [ 3, 78 ], [ 3, 0 ], [ 5, 15 ], [ 3, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7 ], [ 8, 9 ], [ 10, 11 ], [ 11, 12 ], [ 12, 13 ], [ 13, 10 ], [ 14, 15 ], [ 1, 16 ] ] } ] }, "contact": { "fill": 80, "excavation": 0, "sitework_occupied_cells": 877, "replaced_cells": 788, "new_sitework_cells": 89, "strategies": [ "piers", "stepped", "stepped", "piers", "stepped" ], "signature": "2ea35557b0b79663ab89f320fc98604932e9f66e5acf11ec2cfa5881def12c44" }, "accepted_candidates": 10, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.39 ], [ 1, 0.75 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-3", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-4", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.77 ], [ 1, 1.07 ] ], "chosen": 0 } ], "seconds": 7.7168 }
settlement-5-seededvalidated{"program": "settlement", "seed": 5, "count": null}88440529663.8181379f7223a5e476d4
记录 / 诊断
{ "label": "settlement-5-seeded", "inputs": { "program": "settlement", "seed": 5, "count": null }, "attempts": 6, "retries": 0, "status": "validated", "blocks": 88440, "components": 529, "digest": "62a76688210e7170cb121988c560d9980c831696085a9f4e552280b56bb1e6e2", "principal_signature": "379f7223a5e476d420a29059fcd055390b3ca8c094e141df0765e1318952c31e", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 206 ] ], "porch": true, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 206 ] ], "porch": true, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north" ], true, [ -1, 0, 0, 11, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, false, 214 ], [ "z", 11, false, 232 ], [ "z", 11, false, 248 ] ], "porch": true, "bay": 11 } ], "organization": [ { "points": [ [ -11, 0 ], [ 0, 0 ], [ 10, 2 ], [ 0, 2 ], [ -11, 40 ], [ 0, 40 ], [ 5, 15 ], [ 0, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 1, 3 ], [ 4, 5 ], [ 3, 5 ], [ 6, 7 ], [ 1, 7 ], [ 1, 8 ] ] } ] }, "contact": { "fill": 16, "excavation": 0, "sitework_occupied_cells": 388, "replaced_cells": 369, "new_sitework_cells": 19, "strategies": [ "stepped", "stepped", "piers" ], "signature": "5bcc85ceb63d8485e67d70a3c2df8461504a85801d34e2722953ea1bac6cec89" }, "accepted_candidates": 6, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.28 ], [ 1, 0.68 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.21 ], [ 1, 0.58 ] ], "chosen": 1 } ], "seconds": 3.8181 }
settlement-6-seededvalidated{"program": "settlement", "seed": 6, "count": null}89904554884.5757da4eacdc4081043b
记录 / 诊断
{ "label": "settlement-6-seeded", "inputs": { "program": "settlement", "seed": 6, "count": null }, "attempts": 8, "retries": 0, "status": "validated", "blocks": 89904, "components": 554, "digest": "707abf7ec7c851ab83e9588f3fb073843cac320d5032099bd6ff37d0a43b052e", "principal_signature": "da4eacdc4081043b105d062c11d795f2bfd088e563d55cf803fda923e8459e50", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "east" ], false, [ -1, 0, -1, 8, 6, 9 ] ], [ 9, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 197 ], [ "z", 9, true, 193 ] ], "porch": false, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], true, [ -1, 0, 0, 11, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 431 ], [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, false, 182 ] ], "porch": true, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.storage", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, false, 299 ], [ "x", 9, false, 170 ] ], "porch": false, "bay": 9 } ], "organization": [ { "points": [ [ -14, -2 ], [ 0, -2 ], [ 10, -2 ], [ 0, -2 ], [ -11, 40 ], [ 0, 40 ], [ 14, 40 ], [ 0, 40 ], [ 5, 15 ], [ 0, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 1, 3 ], [ 4, 5 ], [ 3, 5 ], [ 6, 7 ], [ 5, 7 ], [ 8, 9 ], [ 1, 9 ], [ 1, 10 ] ] } ] }, "contact": { "fill": 22, "excavation": 0, "sitework_occupied_cells": 446, "replaced_cells": 421, "new_sitework_cells": 25, "strategies": [ "piers", "piers", "stepped", "stepped" ], "signature": "fc8d186b53d15d9da21fb799ef0e6cedf2cd66e81e6f16c4ce74194ef1317172" }, "accepted_candidates": 8, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.47 ], [ 1, 0.8 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-3", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 } ], "seconds": 4.5757 }
settlement-7-seededvalidated{"program": "settlement", "seed": 7, "count": null}91837596885.44357fb4145212538af6
记录 / 诊断
{ "label": "settlement-7-seeded", "inputs": { "program": "settlement", "seed": 7, "count": null }, "attempts": 8, "retries": 0, "status": "validated", "blocks": 91837, "components": 596, "digest": "dc9b2f4174495ed9ab92b8faad276557c922d5fed7a9280885c7a39b19cf8c66", "principal_signature": "7fb4145212538af6d9145705a56dcb25edfeb8a79b56839aecd3ad47d88b2360", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 12, 0, "room.library", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, false, 182 ] ], "porch": true, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south" ], false, [ -1, 0, -1, 11, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north" ], true, [ -1, 0, 0, 11, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 12, 11, "room.library", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 255 ], [ "x", 11, true, 282 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "east" ], true, [ -1, 0, -1, 10, 6, 11 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 258 ], [ "x", 11, true, 277 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], true, [ -1, 0, 0, 9, 6, 9 ] ], [ 0, 6, 9, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 9, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, false, 286 ], [ "x", 9, false, 182 ] ], "porch": true, "bay": 9 } ], "organization": [ { "points": [ [ -11, -2 ], [ -3, -2 ], [ 10, 2 ], [ 3, 2 ], [ -11, 36 ], [ -3, 36 ], [ 10, 36 ], [ 3, 36 ], [ -3, -2 ], [ -3, 36 ], [ 3, 36 ], [ 3, -2 ], [ 5, 15 ], [ 3, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7 ], [ 8, 9 ], [ 9, 10 ], [ 10, 11 ], [ 11, 8 ], [ 12, 13 ], [ 1, 14 ] ] } ] }, "contact": { "fill": 92, "excavation": 0, "sitework_occupied_cells": 584, "replaced_cells": 483, "new_sitework_cells": 101, "strategies": [ "piers", "stepped", "stepped", "piers" ], "signature": "ea91a8d8f6bd0c2d076abe5fe49bc94a1b21d4282b864fb8665b7faaa5a8a312" }, "accepted_candidates": 8, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.36 ], [ 1, 0.76 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.27 ], [ 1, 0.62 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-3", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.95 ], [ 1, 1.17 ] ], "chosen": 1 } ], "seconds": 5.4435 }
settlement-0-3validated{"program": "settlement", "seed": 0, "count": 3}89670541666.77b1ec7523b2d93e22
记录 / 诊断
{ "label": "settlement-0-3", "inputs": { "program": "settlement", "seed": 0, "count": 3 }, "attempts": 6, "retries": 0, "status": "validated", "blocks": 89670, "components": 541, "digest": "dac1f641e1ef26ddef201176065c7016b1cda048616feb4cb5774d9a97b3eb9d", "principal_signature": "b1ec7523b2d93e2255e002abee664cbce8101c8e65229a3687c06628b9aa2cec", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north" ], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, false, 248 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north" ], true, [ -1, 0, 0, 11, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 12, 11, "room.library", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, false, 214 ], [ "z", 11, false, 232 ], [ "z", 11, false, 248 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 12, 0, "room.library", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": false, "bay": 9 } ], "organization": [ { "points": [ [ -11, 0 ], [ -3, 0 ], [ 11, -2 ], [ 3, -2 ], [ -13, 36 ], [ -3, 36 ], [ -3, -2 ], [ -3, 36 ], [ 3, 36 ], [ 3, -2 ], [ 5, 15 ], [ 3, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7 ], [ 7, 8 ], [ 8, 9 ], [ 9, 6 ], [ 10, 11 ], [ 1, 12 ] ] } ] }, "contact": { "fill": 29, "excavation": 0, "sitework_occupied_cells": 606, "replaced_cells": 475, "new_sitework_cells": 131, "strategies": [ "piers", "stepped", "stepped" ], "signature": "e4bfee70edc065a40a4e6f96fb00b63ef58754e97bd0ad67ef38614a5c300c33" }, "accepted_candidates": 6, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.26 ], [ 1, 0.61 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.38 ], [ 1, 0.73 ] ], "chosen": 0 } ], "artifact": "samples/settlement-0-3.litematic", "seconds": 6.77 }
settlement-0-6validated{"program": "settlement", "seed": 0, "count": 6}127411821121212.7913a43297708b82025d
记录 / 诊断
{ "label": "settlement-0-6", "inputs": { "program": "settlement", "seed": 0, "count": 6 }, "attempts": 12, "retries": 0, "status": "validated", "blocks": 127411, "components": 821, "digest": "570364443fe2cb60745267ef0dfe24feb1c8ccb8f2bdbbe8f69e173b79354cd1", "principal_signature": "a43297708b82025d6c4dc83950a2bb63cb4f60726679f074210ba3b6fe9ce3cc", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.library", [ "north" ], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, false, 248 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], false, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 0, 11, "room.living", [ "north" ], true, [ -1, 0, 0, 11, 6, 11 ] ], [ 0, 6, 11, "room.bedroom", [], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 12, 11, "room.library", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 11, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, false, 214 ], [ "z", 11, false, 232 ], [ "z", 11, false, 248 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 12, 0, "room.library", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": false, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.workshop", [ "north", "south" ], true, [ -1, 0, -1, 11, 6, 10 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ] ], "roofs": [ [ "x", 11, true, 255 ], [ "x", 11, true, 282 ] ], "porch": true, "bay": 11 }, { "rooms": [ [ 0, 0, 0, "room.library", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.living", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.living", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 323 ], [ "z", 9, true, 190 ] ], "porch": false, "bay": 9 }, { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], false, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 0, 9, "room.living", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.storage", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "x", 9, true, 323 ], [ "x", 9, true, 194 ] ], "porch": false, "bay": 9 } ], "organization": [ { "points": [ [ -11, 0 ], [ -3, 0 ], [ 11, -2 ], [ 3, -2 ], [ -13, 36 ], [ -3, 36 ], [ 10, 38 ], [ 3, 38 ], [ -13, 76 ], [ -3, 76 ], [ 13, 76 ], [ 3, 76 ], [ -3, -2 ], [ -3, 76 ], [ 3, 76 ], [ 3, -2 ], [ 5, 15 ], [ 3, 15 ], [ 0, -12 ] ], "links": [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7 ], [ 8, 9 ], [ 10, 11 ], [ 12, 13 ], [ 13, 14 ], [ 14, 15 ], [ 15, 12 ], [ 16, 17 ], [ 1, 18 ] ] } ] }, "contact": { "fill": 216, "excavation": 0, "sitework_occupied_cells": 1133, "replaced_cells": 797, "new_sitework_cells": 336, "strategies": [ "piers", "stepped", "stepped", "stepped", "stepped", "stepped" ], "signature": "64eb4ef3ce439002e805d7f79b26f5d3275bb18599cd42412ec65da4a886d249" }, "accepted_candidates": 12, "candidates": [ { "kind": "candidate-selection", "component": "/village/plot-0", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.29 ], [ 1, 0.63 ] ], "chosen": 1 }, { "kind": "candidate-selection", "component": "/village/plot-1", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.12 ], [ 1, 0.52 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-2", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.31 ], [ 1, 0.68 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-3", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 1, 0.8 ], [ 0, 0.96 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-4", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.78 ], [ 1, 1.05 ] ], "chosen": 0 }, { "kind": "candidate-selection", "component": "/village/plot-5", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 0, 0.72 ], [ 1, 1.01 ] ], "chosen": 0 } ], "artifact": "samples/settlement-0-6.litematic", "seconds": 12.7913 }
stress-00incompatible{"environment_seed": 1000, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 5.8776240408547995]}]}, -2, 20——200.4137
记录 / 诊断
{ "label": "stress-00", "inputs": { "environment_seed": 1000, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 5.8776240408547995 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "support-height: /building at None: All declared alternatives violate the same condition: support-height: /building at (0, 0, 0): Bounded support depth exceeded", "accepted_candidates": 0, "candidates": [ { "rule": "support-height", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Bounded support depth exceeded" }, { "rule": "support-height", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Bounded support depth exceeded" } ], "seconds": 0.4137 }
stress-01incompatible{"environment_seed": 1001, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.12, -0.15, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 4.869440025058124]}]}, -2,——200.21
记录 / 诊断
{ "label": "stress-01", "inputs": { "environment_seed": 1001, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.12, -0.15, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 4.869440025058124 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 8, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 8, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 8, permitted 5" } ], "seconds": 0.21 }
stress-02validated{"environment_seed": 1002, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.2, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 0.9415489861398427]}]}, -2, 20]1708286210.59686f82a660419c68dc
记录 / 诊断
{ "label": "stress-02", "inputs": { "environment_seed": 1002, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.2, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 0.9415489861398427 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 17082, "components": 86, "digest": "2256f65432569c1480ab1537b68a18a16c44edaa2965ef93872a88ab176b65f1", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 142, "excavation": 0, "sitework_occupied_cells": 202, "replaced_cells": 3, "new_sitework_cells": 199, "strategies": [ "piers" ], "signature": "c407e9baeeae57e53b478d66e6c045e20c358c5e744217f95ab860041134a89d" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.08 ] ], "chosen": 1 } ], "seconds": 0.5968 }
stress-03incompatible{"environment_seed": 1003, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, -0.15, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 0.6430527137448017]}]}, -2——200.3582
记录 / 诊断
{ "label": "stress-03", "inputs": { "environment_seed": 1003, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, -0.15, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 0.6430527137448017 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 14, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 14, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 14, permitted 5" } ], "seconds": 0.3582 }
stress-04incompatible{"environment_seed": 1004, "building_seed": 4, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, 0, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 2.4423526236572934]}]}, -2, 20——200.5711
记录 / 诊断
{ "label": "stress-04", "inputs": { "environment_seed": 1004, "building_seed": 4, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, 0, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 2.4423526236572934 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 14, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 14, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 14, permitted 5" } ], "seconds": 0.5711 }
stress-05incompatible{"environment_seed": 1005, "building_seed": 5, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.12, -0.15, 4]}, {"op": "wave", "args": [2, 0.13, 0.17, 5.270595124458504]}]}, -2,——200.6381
记录 / 诊断
{ "label": "stress-05", "inputs": { "environment_seed": 1005, "building_seed": 5, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.12, -0.15, 4 ] }, { "op": "wave", "args": [ 2, 0.13, 0.17, 5.270595124458504 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 6, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" } ], "seconds": 0.6381 }
stress-06incompatible{"environment_seed": 1006, "building_seed": 6, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, 0.2, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 1.1992991960704655]}]}, -2, ——200.2108
记录 / 诊断
{ "label": "stress-06", "inputs": { "environment_seed": 1006, "building_seed": 6, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, 0.2, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 1.1992991960704655 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 7, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" } ], "seconds": 0.2108 }
stress-07incompatible{"environment_seed": 1007, "building_seed": 7, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, 0, 4]}, {"op": "wave", "args": [2, 0.13, 0.17, 1.3461702922938386]}]}, -2, 20——200.3015
记录 / 诊断
{ "label": "stress-07", "inputs": { "environment_seed": 1007, "building_seed": 7, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, 0, 4 ] }, { "op": "wave", "args": [ 2, 0.13, 0.17, 1.3461702922938386 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 6, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" } ], "seconds": 0.3015 }
stress-08incompatible{"environment_seed": 1008, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, -0.15, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 2.4349438092044364]}]}, -2——200.4188
记录 / 诊断
{ "label": "stress-08", "inputs": { "environment_seed": 1008, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, -0.15, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 2.4349438092044364 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 16, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 16, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 16, permitted 5" } ], "seconds": 0.4188 }
stress-09validated{"environment_seed": 1009, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 2.572000955340234]}]}, -2, 20]1202246210.289894234e5ecf3559f7
记录 / 诊断
{ "label": "stress-09", "inputs": { "environment_seed": 1009, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 2.572000955340234 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 12022, "components": 46, "digest": "6284e169ebbecca1558b136eb03a3be45b31fbbc0c397c57c1f1e153db5411cc", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 57, "excavation": 0, "sitework_occupied_cells": 73, "replaced_cells": 15, "new_sitework_cells": 58, "strategies": [ "piers" ], "signature": "cfe14a1257676650f1e80d27c76a50fe4bc00d382d597de8fdfc2abdee01842d" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.03 ] ], "chosen": 1 } ], "seconds": 0.2898 }
stress-10incompatible{"environment_seed": 1010, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, -0.15, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 0.3247868788871646]}]}, -2——200.4139
记录 / 诊断
{ "label": "stress-10", "inputs": { "environment_seed": 1010, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, -0.15, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 0.3247868788871646 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 7, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" } ], "seconds": 0.4139 }
stress-11incompatible{"environment_seed": 1011, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, 0.2, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 2.50908774252244]}]}, -2, 20——200.2639
记录 / 诊断
{ "label": "stress-11", "inputs": { "environment_seed": 1011, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, 0.2, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 2.50908774252244 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 8, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 8, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 8, permitted 5" } ], "seconds": 0.2639 }
stress-12incompatible{"environment_seed": 1012, "building_seed": 4, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.12, 0.2, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 3.125355622776525]}]}, -2, 2——200.6105
记录 / 诊断
{ "label": "stress-12", "inputs": { "environment_seed": 1012, "building_seed": 4, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.12, 0.2, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 3.125355622776525 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 7, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" } ], "seconds": 0.6105 }
stress-13incompatible{"environment_seed": 1013, "building_seed": 5, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, -0.15, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 4.2527528075184815]}]}, -2——200.5171
记录 / 诊断
{ "label": "stress-13", "inputs": { "environment_seed": 1013, "building_seed": 5, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, -0.15, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 4.2527528075184815 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 13, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 13, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 13, permitted 5" } ], "seconds": 0.5171 }
stress-14validated{"environment_seed": 1014, "building_seed": 6, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, -0.15, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 2.872862854045616]}]}, -2,1322150210.42457676b0a0ab7b4410
记录 / 诊断
{ "label": "stress-14", "inputs": { "environment_seed": 1014, "building_seed": 6, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, -0.15, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 2.872862854045616 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 13221, "components": 50, "digest": "8df700242ce31d4dfe86722e571fa58c074447a001f5374b7ab5f8b90980d22b", "principal_signature": "7676b0a0ab7b441021fd8a6f7034b32d0602402e654f33bc1be65f62fb413691", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 102, "excavation": 0, "sitework_occupied_cells": 116, "replaced_cells": 38, "new_sitework_cells": 78, "strategies": [ "piers" ], "signature": "cde6580f3b7d5170ae89abe637bc34fedcbc610fb45803194a1e7c98e3d7c653" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.92 ] ], "chosen": 1 } ], "seconds": 0.4245 }
stress-15incompatible{"environment_seed": 1015, "building_seed": 7, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, -0.15, 4]}, {"op": "wave", "args": [2, 0.13, 0.17, 1.4027952417076066]}]}, -2——200.2597
记录 / 诊断
{ "label": "stress-15", "inputs": { "environment_seed": 1015, "building_seed": 7, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, -0.15, 4 ] }, { "op": "wave", "args": [ 2, 0.13, 0.17, 1.4027952417076066 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 8, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 8, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 8, permitted 5" } ], "seconds": 0.2597 }
stress-16incompatible{"environment_seed": 1016, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, -0.15, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 4.869990979956712]}]}, -2,——200.3889
记录 / 诊断
{ "label": "stress-16", "inputs": { "environment_seed": 1016, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, -0.15, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 4.869990979956712 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 10, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 10, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 10, permitted 5" } ], "seconds": 0.3889 }
stress-17validated{"environment_seed": 1017, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, -0.15, 4]}, {"op": "wave", "args": [2, 0.13, 0.17, 1.377146611027384]}]}, -2, 201071246210.28394234e5ecf3559f7
记录 / 诊断
{ "label": "stress-17", "inputs": { "environment_seed": 1017, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, -0.15, 4 ] }, { "op": "wave", "args": [ 2, 0.13, 0.17, 1.377146611027384 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 10712, "components": 46, "digest": "4a9ebf16499afc9052736a48800bec974122ffbb9a9eacaeda7c797d313df562", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 58, "excavation": 0, "sitework_occupied_cells": 61, "replaced_cells": 60, "new_sitework_cells": 1, "strategies": [ "piers" ], "signature": "50ff5b781552297437bb8173e1010edfd33613645c27b206b6e28eb38f21e68d" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 1.81 ] ], "chosen": 1 } ], "seconds": 0.283 }
stress-18validated{"environment_seed": 1018, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, -0.15, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 1.1866050012955982]}]}, -2, 21800686210.61856f82a660419c68dc
记录 / 诊断
{ "label": "stress-18", "inputs": { "environment_seed": 1018, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, -0.15, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 1.1866050012955982 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 18006, "components": 86, "digest": "ee516d164fc176d842140b76b869773cc86fa752b5b6a359a94a57b174836e0d", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 138, "excavation": 0, "sitework_occupied_cells": 144, "replaced_cells": 141, "new_sitework_cells": 3, "strategies": [ "piers" ], "signature": "26f4932c88734cebc60c534d5d0455742d658ff22bf27258dd9a668241875e94" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 4.26 ] ], "chosen": 1 } ], "seconds": 0.6185 }
stress-19incompatible{"environment_seed": 1019, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.45, -0.15, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 1.738292017810577]}]}, -2,——200.3012
记录 / 诊断
{ "label": "stress-19", "inputs": { "environment_seed": 1019, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.45, -0.15, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 1.738292017810577 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 10, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 10, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 10, permitted 5" } ], "seconds": 0.3012 }
stress-20validated{"environment_seed": 1020, "building_seed": 4, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.12, 0.2, 4]}, {"op": "wave", "args": [2, 0.13, 0.17, 3.5238514916028416]}]}, -2, 2558992210.87549f3c0d02902e928c
记录 / 诊断
{ "label": "stress-20", "inputs": { "environment_seed": 1020, "building_seed": 4, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.12, 0.2, 4 ] }, { "op": "wave", "args": [ 2, 0.13, 0.17, 3.5238514916028416 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 25589, "components": 92, "digest": "90282ddec4c2cef6531a621e71eac18cf8574d9ea02d794d8f0bb68347d78b4a", "principal_signature": "9f3c0d02902e928c0d5603178d47a3ad4494c7ab06e4f1dd966d4d9cfebaa7f7", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 10, 6, 10 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 0, 11, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 11, 6, 11 ] ], [ 11, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 255 ], [ "z", 11, true, 256 ], [ "z", 11, true, 277 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 174, "excavation": 0, "sitework_occupied_cells": 211, "replaced_cells": 15, "new_sitework_cells": 196, "strategies": [ "piers" ], "signature": "38fb6277938a54dae106581b55a13e2aef4327b83c0df61c07df4b7a28a69b35" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 2.41 ] ], "chosen": 1 } ], "seconds": 0.8754 }
stress-21incompatible{"environment_seed": 1021, "building_seed": 5, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.12, 0.2, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 4.846768228469619]}]}, -2, 2——200.498
记录 / 诊断
{ "label": "stress-21", "inputs": { "environment_seed": 1021, "building_seed": 5, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.12, 0.2, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 4.846768228469619 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 6, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" } ], "seconds": 0.498 }
stress-22validated{"environment_seed": 1022, "building_seed": 6, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 3.9935517102207383]}]}, -2, 201206550220.43647676b0a0ab7b4410
记录 / 诊断
{ "label": "stress-22", "inputs": { "environment_seed": 1022, "building_seed": 6, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 3.9935517102207383 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 12065, "components": 50, "digest": "5956479ec218ea883425076b95a48b29d4d23abb0ba5bd3e5fe294242190aaa4", "principal_signature": "7676b0a0ab7b441021fd8a6f7034b32d0602402e654f33bc1be65f62fb413691", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 11, 6, 11 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 11, 6, 11 ] ] ], "roofs": [ [ "z", 11, true, 282 ] ], "porch": true, "bay": 11 } ], "organization": [] }, "contact": { "fill": 44, "excavation": 0, "sitework_occupied_cells": 56, "replaced_cells": 3, "new_sitework_cells": 53, "strategies": [ "piers" ], "signature": "6f833602274b6b480f0f22ccfbecbccd11da557d62b8602a4da67524b42e0536" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 1, 0.62 ], [ 0, 0.69 ] ], "chosen": 1 } ], "seconds": 0.4364 }
stress-23incompatible{"environment_seed": 1023, "building_seed": 7, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0.2, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 4.1259430264716]}]}, -2, 20]}, ——200.2431
记录 / 诊断
{ "label": "stress-23", "inputs": { "environment_seed": 1023, "building_seed": 7, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0.2, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 4.1259430264716 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 6, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" } ], "seconds": 0.2431 }
stress-24incompatible{"environment_seed": 1024, "building_seed": 0, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, 0.2, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 2.4634439128036343]}]}, -2, ——200.4628
记录 / 诊断
{ "label": "stress-24", "inputs": { "environment_seed": 1024, "building_seed": 0, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, 0.2, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 2.4634439128036343 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 7, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" } ], "seconds": 0.4628 }
stress-25validated{"environment_seed": 1025, "building_seed": 1, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 4.183745447323284]}]}, -2, 20]1110146210.293494234e5ecf3559f7
记录 / 诊断
{ "label": "stress-25", "inputs": { "environment_seed": 1025, "building_seed": 1, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 4.183745447323284 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 11101, "components": 46, "digest": "fb495615ce245bb5c437fab12afe7d36cd1567d7c61b84916cb50277dbe87529", "principal_signature": "94234e5ecf3559f793dc56abaa39cde7ba5d63e0f40ec3d795dc142c392248ef", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north" ], true, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 206 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 40, "excavation": 0, "sitework_occupied_cells": 51, "replaced_cells": 18, "new_sitework_cells": 33, "strategies": [ "piers" ], "signature": "7d0296e7edf7afeba69140e5631b9dae6732d41c229020e636f0b9ab8fb7b6aa" }, "accepted_candidates": 1, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 1, "rejected": [ { "rule": "contact-strategy", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Requested strategy incompatible with measured water/relief" } ], "scores": [ [ 1, 0.87 ] ], "chosen": 1 } ], "seconds": 0.2934 }
stress-26validated{"environment_seed": 1026, "building_seed": 2, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.12, 0, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 4.600693066246155]}]}, -2, 20]1736386220.69336f82a660419c68dc
记录 / 诊断
{ "label": "stress-26", "inputs": { "environment_seed": 1026, "building_seed": 2, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.12, 0, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 4.600693066246155 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "validated", "blocks": 17363, "components": 86, "digest": "8363316c9dfdabaa98a2c010d402b99cf67068d824d45b62600561ee4733fbbd", "principal_signature": "6f82a660419c68dc401d0ed37f9917b3ac01f366855130f14bbbfec2067d03a6", "structure": { "buildings": [ { "rooms": [ [ 0, 0, 0, "room.living", [ "north", "south", "east" ], true, [ -1, 0, -1, 8, 6, 8 ] ], [ 0, 6, 0, "room.bedroom", [], false, [ -1, 0, -1, 9, 6, 9 ] ], [ 0, 0, 9, "room.kitchen", [ "north" ], false, [ -1, 0, 0, 9, 6, 9 ] ], [ 9, 0, 0, "room.library", [ "west" ], false, [ 0, 0, -1, 9, 6, 9 ] ] ], "roofs": [ [ "z", 9, true, 185 ], [ "z", 9, true, 183 ], [ "z", 9, true, 202 ] ], "porch": true, "bay": 9 } ], "organization": [] }, "contact": { "fill": 102, "excavation": 0, "sitework_occupied_cells": 123, "replaced_cells": 3, "new_sitework_cells": 120, "strategies": [ "piers" ], "signature": "bd96dbd58eb4b985bb142e255b4bfa71148356e8fe1fede7eb304b4d63b96835" }, "accepted_candidates": 2, "candidates": [ { "kind": "candidate-selection", "component": "/building", "attempts": 2, "accepted": 2, "rejected": [], "scores": [ [ 1, 1.29 ], [ 0, 1.55 ] ], "chosen": 1 } ], "seconds": 0.6933 }
stress-27incompatible{"environment_seed": 1027, "building_seed": 3, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0, 0, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 1.4491939601754085]}]}, -2, 20]},——200.3596
记录 / 诊断
{ "label": "stress-27", "inputs": { "environment_seed": 1027, "building_seed": 3, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0, 0, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 1.4491939601754085 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 7, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 7, permitted 5" } ], "seconds": 0.3596 }
stress-28incompatible{"environment_seed": 1028, "building_seed": 4, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.12, -0.15, 4]}, {"op": "wave", "args": [2, 0.13, 0.17, 5.299298916064824]}]}, -2,——200.4881
记录 / 诊断
{ "label": "stress-28", "inputs": { "environment_seed": 1028, "building_seed": 4, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.12, -0.15, 4 ] }, { "op": "wave", "args": [ 2, 0.13, 0.17, 5.299298916064824 ] } ] }, -2, 20 ] }, "water": null }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 6, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" } ], "seconds": 0.4881 }
stress-29incompatible{"environment_seed": 1029, "building_seed": 5, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.12, 0.2, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 0.5466118690031094]}]}, -2, ——200.5053
记录 / 诊断
{ "label": "stress-29", "inputs": { "environment_seed": 1029, "building_seed": 5, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.12, 0.2, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 0.5466118690031094 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 6, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 6, permitted 5" } ], "seconds": 0.5053 }
stress-30incompatible{"environment_seed": 1030, "building_seed": 6, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, 0.2, 4]}, {"op": "wave", "args": [0, 0.13, 0.17, 2.0815379390398503]}]}, -2, ——200.3057
记录 / 诊断
{ "label": "stress-30", "inputs": { "environment_seed": 1030, "building_seed": 6, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, 0.2, 4 ] }, { "op": "wave", "args": [ 0, 0.13, 0.17, 2.0815379390398503 ] } ] }, -2, 20 ] }, "water": 12 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "support-height: /building at None: All declared alternatives violate the same condition: support-height: /building at (0, 0, 0): Bounded support depth exceeded", "accepted_candidates": 0, "candidates": [ { "rule": "support-height", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Bounded support depth exceeded" }, { "rule": "support-height", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Bounded support depth exceeded" } ], "seconds": 0.3057 }
stress-31incompatible{"environment_seed": 1031, "building_seed": 7, "expression": {"op": "clamp", "args": [{"op": "add", "args": [{"op": "gradient", "args": [0.28, -0.15, 4]}, {"op": "wave", "args": [5, 0.13, 0.17, 5.029230327813721]}]}, -2,——200.2643
记录 / 诊断
{ "label": "stress-31", "inputs": { "environment_seed": 1031, "building_seed": 7, "expression": { "op": "clamp", "args": [ { "op": "add", "args": [ { "op": "gradient", "args": [ 0.28, -0.15, 4 ] }, { "op": "wave", "args": [ 5, 0.13, 0.17, 5.029230327813721 ] } ] }, -2, 20 ] }, "water": 5 }, "attempts": 2, "retries": 0, "status": "incompatible", "diagnostic": "site-relief: /building at None: All declared alternatives violate the same condition: site-relief: /building at (0, 0, 0): Measured 8, permitted 5", "accepted_candidates": 0, "candidates": [ { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 8, permitted 5" }, { "rule": "site-relief", "component": "/building", "position": [ 0, 0, 0 ], "conditions": "Measured 8, permitted 5" } ], "seconds": 0.2643 }
完整原始 assessment(英文)

Finite assessment, root seed 0

This report summarizes the retained final results. The sampling policy was fixed before evaluating the corpus. Every input is kept, including incompatible stress inputs. There is no rejection resampling. Timing is observed on this CPU environment, with some rendering/testing work concurrent; it is not a portable benchmark.

Batch Valid inputs / attempted inputs Feasible candidates / attempted candidates Incompatible inputs Budget exhausted / defects Measured seconds
Independent environment/building pairings 64 / 64 84 / 128 0 0 / 0 32.777
Three building programs, seeds 0–7 24 / 24 48 / 48 0 0 / 0 22.288
Settlement seeds 0–7 and counts 3, 6 10 / 10 80 / 80 0 0 / 0 65.221
Bounded stress sampling 9 / 32 11 / 64 23 0 / 0 13.515

Candidates are complete alternative building placements: stepped perimeter work and piers under the same locked design. The settlement denominator counts alternatives across its forty building placements. The solver compares both permitted strategies; this is not a retry after silently moving a locked building. All batches report zero retries. Stress incompatibilities comprise 21 relief-limit and 2 support-height-limit inputs. Both declared alternatives failed the same measured hard condition for each incompatible input. This establishes incompatibility with the delivered policy, not impossibility under every conceivable building technique. A separate unit test exercises search-budget exhaustion with an unvisited valid candidate.

The 64 pairings use sixteen independently frozen complete environmental scenes and four independent building seeds. The first eight environment expressions use additive fields. The last eight use the held-out blend/transform composition. Expressions, seeds, water levels, known domains and frozen geometry identities are saved in adaptation-inputs.json. Tests also cover degenerate coefficients, local perturbations, a compatible independent environment, protected observations, unchanged cells outside authorized work, and hollow support beds.

Observed principal building signatures are 18 / 24: dwelling 5 / 8, atelier 8 / 8, commons 5 / 8. The settlement corpus has 10 / 10 observed signatures. Signatures use realized room extents, purpose/connection topology, levels/stairs, roof geometry and path organization; they omit names, material color and global transforms. The adaptation-only corpus has three principal designs across its four building seeds. Repeated principal structures are retained and counted honestly.

Contact geometry is measured separately. There are 44 / 64 observed contact signatures in the adaptation corpus, 24 / 24 in the building corpus, 10 / 10 in settlements and 9 / 9 among successful stress inputs. Chosen strategies are 46 piers / 18 stepped in adaptation, 6 / 18 in buildings, 17 / 23 across settlement buildings, and 9 / 0 in successful stress inputs.

Batch, valid inputs only Foundation fill range Excavated solid cells Existing cells replaced by sitework New sitework cells
Adaptation 0–159 0 3–168 3–87
Buildings 0–70 0 1–3 0–73
Settlements 16–216 0 369–797 19–336
Stress successes 40–174 0 3–141 1–199

Fill is the foundation's measured support volume. Replacement and new-cell counts cover sitework components, including approaches and paths. Water-to-post changes are replacements; zero excavated solid cells does not mean zero site disturbance. Authorized pool excavation and rejected excavation under a supported tree are exercised separately in contract and containment tests.

The final test command python -m pytest -q test passed 134 tests in 97.27 seconds. Tests damage actual geometry and NBT to verify support, stairs/headroom, exits, paired doors, lighting, furnishings, enclosure, inventories, pool containment, permissions and transport identity. They also verify substitution, independent extension, phases, transforms, atomic failure, provenance and regeneration. See pytest-final.txt.

replay.json records independent seed-0 runs with PYTHONHASHSEED=3 and 8675309, including output paths containing spaces. Both recover the same content, bounds and semantic digest: e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9. The default is five buildings, 125,475 occupied cells and 782 component instances. Seed 1 produces three buildings and was also exported/reloaded successfully. The output contains one region and Minecraft data version 3955; every explicit blockstate property and relevant inventory NBT is checked.

Representative samples are listed in ../samples/replay-manifest.json. Visual evidence includes both sides of the settlement, distinct building massing, a wet-site adaptation and room/stair cutaways. Cutaways are geometry-only previews; the full originals, not the slices, are used for validation and provenance.

These finite results do not prove universal feasibility or beauty. The documented movement, lighting, support and roof models bound the claims. Historical failures and their generic fixes remain in development-findings.md.

12 · 验收、负例与独立复验

Harness 的五个独立执行

默认入口、两次 seed 0(不同 PYTHONHASHSEED)、seed 1 和 pytest 在独立离线工作副本中执行。每条命令 1,800 秒上限,使用普通用户、无凭证/CLI 会话、只读依赖;比较尺寸、坐标、实际状态与实体/NBT,忽略时间戳、压缩、palette 编号和属性顺序。

命令退出码用时 / s结果
default011.679通过
seed-0-a011.159通过
seed-0-b011.315通过
seed-107.107通过
tests097.577通过

完整原始 harness report.json。这里的 pytest 通过意味着被提交的测试真实执行,不意味着测试已经证明所有 R01–R30 要求。

报告独立重跑原始测试

报告在相同固定镜像、独立可写副本中重新执行原始测试套件,未修改原实验代码。它再次通过全部 134 项,覆盖授权替换、原子失败、实例身份、空间变换、分支随机数、构建阶段、环境适配、成对导出、负例破坏和依赖再生成。

........................................................................ [ 53%] .............................................................. [100%] 134 passed in 98.24s (0:01:38)

浏览器:真实 Python 与原生结果交叉检查

运行时使用 Pyodide 0.27.7,原始 Hearth 和 MCIO 源码按哈希加载;浏览器 bridge 只负责传参、调用公共接口、传输块数据和查询。测试包含实际控件、改写代码、结构探索、同 seed 重放、导出、结构链/成员、错误、停止与恢复、移动端及原生内容比对。下列是实际检查结果,运行时间只代表本机这次测量。

有限复验结论:11 次浏览器运行均与原生 Python 的内容摘要、主结构签名及玻璃查询一致;其中 6 份下载包逐一通过原生加载,并核对全部结构节点。22 项浏览器功能检查通过,包括真实方块点击查询、结构探索、375px 布局和故障恢复。切片前后的下载内容完全一致。

browser-verification.json
{ "samples": [ { "label": "building-0", "seed": "0", "digest": "be299dbd2fc591d6a38a8e6c7378aad3d765cb546de5f6df7c44773325c89dc3", "signature": "ab4f66e2ee4de325134b4a767a1faf1e39b11567c9147953780aceb2059aec00", "blocks": 15288, "components": 72, "rooms": 3, "python_s": 2.7494000000000005, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "building-replay", "seed": "0", "digest": "be299dbd2fc591d6a38a8e6c7378aad3d765cb546de5f6df7c44773325c89dc3", "signature": "ab4f66e2ee4de325134b4a767a1faf1e39b11567c9147953780aceb2059aec00", "blocks": 15288, "components": 72, "rooms": 3, "python_s": 2.603600000000001, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "building-bay13", "seed": "0", "digest": "52e06a1887c2e7ba3d083daf5a2d5706d6ff502f677546f9dc1b4f00102db9c2", "signature": "a42e34bd7bbbd09bec16c5e64dd5c21360cc31e99626ee741d30f05835a5bf6b", "blocks": 17970, "components": 72, "rooms": 3, "python_s": 3.2569, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "building-1", "seed": "1", "digest": "52e06a1887c2e7ba3d083daf5a2d5706d6ff502f677546f9dc1b4f00102db9c2", "signature": "a42e34bd7bbbd09bec16c5e64dd5c21360cc31e99626ee741d30f05835a5bf6b", "blocks": 17970, "components": 72, "rooms": 3, "python_s": 3.2006000000000014, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "terrain-wet", "seed": "0", "digest": "4a270f9f4ef771dcf6e6631da57349bdb6b6f3462e56f0fa2706fb7b2bf59c5c", "signature": "7676b0a0ab7b441021fd8a6f7034b32d0602402e654f33bc1be65f62fb413691", "blocks": 35463, "components": 50, "rooms": 2, "python_s": 3.722900001000003, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "settlement-0", "seed": "0", "digest": "e81b08063278b231b60eaa16e4120973ed688bb3fd7e6a8da439daa4e7f5caf9", "signature": "a5e69d2105108e2af50f7c163efd47a3e398765881fed1bd11ac7f95d20cacd6", "blocks": 125475, "components": 782, "rooms": 15, "python_s": 26.394799999999996, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "explore-17", "seed": "17", "digest": "8d7f4d7fe9906f79e944149b9254f067b8833ca4241d470cfa0ea97fca561fb4", "signature": "f8dc52aa4f4abdf8e57ae8ef6cfaec1c74092b92d2b55724876eea185cbab368", "blocks": 11308, "components": 47, "rooms": 2, "python_s": 1.6206000000000031, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "explore-18", "seed": "18", "digest": "ca008a4f80bb95aef18e2317f30e504468dd77dc8cccc9e5838a03b04f3d3c80", "signature": "abacaaee7de9f87371d9e2417ebca16e8595a99fd732895dcfacab5f2bcc0f75", "blocks": 8776, "components": 27, "rooms": 1, "python_s": 1.0853000000000037, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "large-seed", "seed": "9223372036854775807", "digest": "be299dbd2fc591d6a38a8e6c7378aad3d765cb546de5f6df7c44773325c89dc3", "signature": "ab4f66e2ee4de325134b4a767a1faf1e39b11567c9147953780aceb2059aec00", "blocks": 15288, "components": 72, "rooms": 3, "python_s": 2.5991999989999997, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "custom-python", "seed": "23", "digest": "62377e6641e1356897eb7fb39780222d0b410a32dbb067f8018d6c732167c0c5", "signature": "8ae5e9094521005be3dae105b1f232a36a7738fe6424437fb37948d166b3627e", "blocks": 8756, "components": 27, "rooms": 1, "python_s": 1.1036999999999964, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } }, { "label": "after-cancel", "seed": "0", "digest": "be299dbd2fc591d6a38a8e6c7378aad3d765cb546de5f6df7c44773325c89dc3", "signature": "ab4f66e2ee4de325134b4a767a1faf1e39b11567c9147953780aceb2059aec00", "blocks": 15288, "components": 72, "rooms": 3, "python_s": 2.6779000010000003, "runtime": { "python": "3.12.7", "numpy": "2.0.2", "platform": "Emscripten" } } ], "checks": { "seed_replay": true, "real_glass_ancestry": true, "ancestor_membership": true, "parameter_changes_structure": true, "wet_adaptation": true, "original_default": true, "exploration_changes_structure": true, "exact_integer_seed": true, "edited_python_executed": true, "cutaway_preserves_content": true, "mobile_no_horizontal_overflow": true, "invalid_seed_rejected": true, "error_visible": true, "stale_export_disabled": true, "cancel_stops_worker": true, "recovery_after_cancel": true, "mermaid_rendered": true, "charts_rendered": true, "pointer_queries_real_block": true, "explore_button_runs_sampler": true, "seed_button_preserves_client": true, "incompatible_environment_rejected": true }, "page_errors": [], "reviewed_at": "2026-09-26T21:30:16.601Z" }
native-browser-comparison.json
{ "samples": [ { "label": "building-0", "checks": { "digest": true, "signature": true, "sample_query": true, "download_digest": true, "download_all_nodes": true, "download_query": true }, "native_seconds": 1.303840467997361, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "building-replay", "checks": { "digest": true, "signature": true, "sample_query": true }, "native_seconds": 1.2410594370012404, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "building-bay13", "checks": { "digest": true, "signature": true, "sample_query": true, "download_digest": true, "download_all_nodes": true, "download_query": true }, "native_seconds": 1.5772299230011413, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "building-1", "checks": { "digest": true, "signature": true, "sample_query": true }, "native_seconds": 1.575140447996091, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "terrain-wet", "checks": { "digest": true, "signature": true, "sample_query": true, "download_digest": true, "download_all_nodes": true, "download_query": true }, "native_seconds": 1.8810117620014353, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "settlement-0", "checks": { "digest": true, "signature": true, "sample_query": true, "download_digest": true, "download_all_nodes": true, "download_query": true }, "native_seconds": 13.422170275996905, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "explore-17", "checks": { "digest": true, "signature": true, "sample_query": true, "download_digest": true, "download_all_nodes": true, "download_query": true }, "native_seconds": 0.8272688430006383, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "explore-18", "checks": { "digest": true, "signature": true, "sample_query": true }, "native_seconds": 0.5270251920010196, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "large-seed", "checks": { "digest": true, "signature": true, "sample_query": true }, "native_seconds": 1.280684746991028, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "custom-python", "checks": { "digest": true, "signature": true, "sample_query": true, "download_digest": true, "download_all_nodes": true, "download_query": true }, "native_seconds": 0.532600154998363, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } }, { "label": "after-cancel", "checks": { "digest": true, "signature": true, "sample_query": true }, "native_seconds": 1.2756541090056999, "native_runtime": { "python": "3.12.13", "numpy": "2.5.3", "platform": "Linux" } } ], "cutaway_download_unchanged": true, "passed": true, "scope": "Finite cross-platform content, actual downloaded files, full structural nodes and glass query. No exhaustive seed claim." }

公网复验记录:发布后实际执行 Python、核对内容摘要、查询玻璃结构链并下载 ZIP 均通过,页面没有 JavaScript 错误。

验证模型的边界

支撑、可达性和光源规则是交付库定义的整数几何模型;不是游戏引擎、红石/生物/完整光照传播模拟。一般实体运输、通用屋顶交汇求解、完整城市生成仍不在当前实现内。损坏测试能证明某些错误会被检测,不能证明不存在漏检;交付的负例和 R 台账可在源码附录逐条查阅。

13 · 失败与修复

开发记录不是一路全绿。尤其是转发接口的阶段回归,曾让十个聚落输入全部被拒绝;模型后来修复了进行中与已完成 scope 的验证时序,再运行最终 corpus。本文保留历史证据,不把修复前的数据混进最终通过率。

Development sequence and retained findings

The design in ARCHITECTURE.md was written before extensive scene geometry. The work then followed the requested sequence: executable kernel, small recursive prototype, furnished buildings and independent extension, settlements, and finite assessment. This is a development account, not a claim that a design document or sampled test establishes correctness for every future component.

  1. The initial kernel passed seven foundation tests for composition, binding, replacement, rollback, automatic ownership, transforms and persistence. The first components were terrain, grass, trees, walls and windows. examples.prototype still runs this composition, including a thickness-adapted window and a tree replacing an entire tall grass object through its grant.
  2. Room and building components were added through the same protocol. Actual furnishing, lanterns, paired doors/beds, stair flights, sealed room boundaries, gables and site adapters became child components. Building alternatives validate the complete candidate before selection.
  3. extension_demo added a visibly different pendant light and a composite reading suite, without kernel dispatch changes. The later courtyard and gallery programs use the existing room graph API.
  4. Settlements, the independent terrain/building corpus and bounded stress batch exposed interactions beyond the original prototype. Foundational tests were rerun after kernel changes. The final suite is recorded in pytest-final.txt: 134 passed in 97.27 seconds.

The following generic corrections are in the delivered implementation:

Finding Correction and evidence
A window installed by an external facade program was missing from host-descendant highlighting Membership adjacency now follows both real attachment and containment; the cross-scope provenance test covers exact membership
A later parameter update could obscure the semantic owner Property effects preserve the owner and require the same block type; tests distinguish structural membership from modification history
Compound terrain/building replay risked accumulating earlier cuts or stale nodes Branch removal restores displaced surviving host content, removes reverse references, and explicitly replays affected branches atomically
Forwarded child interfaces were checked before construction reached that child In-progress enclosing scopes now defer interface completion checks; completed scopes still check every delegated interface
Concave courtyard corners gave facade planting overlapping installation margins The shared facade garden rule keeps climbers clear of corner margins; the later courtyard runs without client geometry repair
A wide path extended behind an endpoint into an existing entrance Widening is perpendicular to each path segment, within its own negotiated authority; endpoint regression coverage verifies this
Surface height alone could accept a hollow substrate The survey requires two contiguous actual solid bed cells; the negative test preserves top height but removes the supporting layer
A wall checked its vertical frame but could miss the floor immediately below Corner support rules now include the floor contact cells; the small prototype supplies a real foundation
A maximum-size room could expose different stair/furniture spacing A bay-13 stacked-room test verifies the actual route, headroom and furnishings
Sparse shutters, empty facade panels and dense foliage reduced visual quality Full shutter pairs, sills, bounded facade planters and climbers, a well terrace, and layered foliage were added through components
The well cover needed a physical post connection Posts now meet the cover; its support rule includes the full connection
A fixed cutaway plane missed stairs located in a remote wing The optional preview client now chooses its section from actual stair-instance cells; the courtyard section was rerendered and inspected

The forwarded-interface regression was caught during a late validation pass. Its failing pytest output and ten rejected settlement records are preserved in phase-regression/. Those are historical failures, not removed from the evidence. The final corpus fixes the phase semantics and validates all ten settlement inputs. Earlier complete assessments remain in baseline-corpus/ and corpus/; superseded artifact references are explicitly labeled historical.

Early visual observations are retained in previews/development-house.png and previews/settlement-first.png. Current paired artifacts, final exterior views, cutaways and visual observations are indexed in ../previews/README.md. The reference snapshots were not edited: reference-integrity.json records 32/32 matching original hashes. No supplied reference program was invoked or imported.

Known limits are documented in GENERATOR.md. In particular, the visible modular style, bounded gable vocabulary, integer movement model and explicit regeneration policy remain intentional limits, not claims of a universal Minecraft simulator or an exhaustive architecture solver.

可以直接比对 阶段回归、早期基线 与 最终 summary。局部修复是否足够通用,应以相应测试、接口变化和新组合结果判断,而非仅看文档描述。

14 · R01–R30 需求台账

以下逐条保留模型提交的 implementation/evidence/qualification 台账。这是其自述索引,报告不把每行自动升级为独立认证。可从源码和测试定位实现,再用实际结果与限制交叉核查。

ID Implemented API/module and evidence Qualification
R01 kernel/*, initial design, seven foundation tests before content; thin CLI Executable foundation, not placeholder interfaces
R02 Independent implementation; supplied snapshots unchanged; reference images used as aesthetic goals No reference generator invoked or imported
R03 Blueprint, room graph programs, Choice, roof planner, spine/loop paths; finite signatures Room grid and roof primitives are bounded, openly documented
R04 Module table in architecture; kernel has no component imports; transport separate Browser host adapter not implemented
R05 Capability, executable Domain, Contract, Port, Grant, rules and read-only View Free-form descriptive assumptions complement executable checks
R06 Plan/Child/Choice, registry, composition operations, forwarded ports; extension/nested tests New primitives can extend beyond the shipped grid vocabulary
R07 Scoped authority, whole-object replacement, shared support; tree/grass/pool/window/clearance tests No universal priority or same-state sharing shortcut
R08 Fork/validate/commit kernel, plans and automatic read traces; rollback snapshots Trusted Python components, not a hostile-code sandbox
R09 Open/complete scopes, ancestor-aware obligations, finalization; unfinished/light and late-edit tests Standalone landing-to-public-path is an enclosing obligation
R10 Automatic nodes/operation owners, real window/wall instances; inspection and cross-scope attachment tests No per-voxel client owner maps or post-hoc tagging
R11 Structural graph, dependency graph, operations/displacement records; update/share/removal tests Historic actors may remain in history, never as current owners
R12 inspect, owner/shared reverse indexes, semantic descendant index; regeneration and deletion tests Headless queries delivered; no clickable viewer
R13 Paired JSON/Litematica, version/digest/offset checks, actual reload validation; mismatch/NBT tests Pairing integrity is not cryptographic authenticity
R14 General field algebra, masks, transforms, strata, water and constrained scattering No environment-family dispatch; finite shipped operations are extensible
R15 Domain/version-aware 3D view, elevation cap, support/water/slope/clearance/style/preferences Unknown space errors; no simulation of every Minecraft behavior
R16 Foundation, approach, window-depth and roof-abutment components Universal roof-junction/flashing solver not implemented
R17 Frozen terrain, measured site survey, bounded complete candidates, joint tentative validation Fixed principal intent; failures beyond bounds are retained
R18 Hard checks then actual effect cost/exposure score, seeded near-best choice, rejection records Search-budget negative test; no claim of exhaustive feasibility
R19 Automatic/declared input dependencies, stale flags, explicit atomic co-regeneration Dependency updates are conservative; no implicit arbitrary auto-replan
R20 SHA-256 scope keys/purposes, overrides, copied environments; branch/order/retry and hash-seed replay tests Genuine spatial dependencies may change descendants
R21 Configurable Limits, SiteLimits, effect envelopes and realized export bounds Demonstration count bound is only in the CLI
R22 Initial design, kernel tests, prototype, buildings/extension, corpus/render stages Generic defects and fixes recorded in development findings
R23 test_kernel, test_contracts_provenance: substitution, independent extension, authority, rollback, sharing, transforms, seeds Custom validator registration also tested
R24 Glass chain, two identities, external attachment membership, updates/deletions/regeneration, shared cells, transport mismatch tests Actual structure restored from companion, not inferred from materials
R25 64 frozen pairings, compatible independent field/environment, protected outside cells, perturbation and stress records Finite supported domain; 32 stress inputs retained without resampling
R26 Three short clients x eight seeds; settlement x eight seeds plus counts 3 and 6; later courtyard/gallery Programs use public room/component APIs
R27 Actual blocks/NBT: schema, support, headroom/routes, pair consistency, enclosure, lights, furnishings, pools and path joins; deliberate damage tests Physical/lighting model limitations above apply
R28 Structural/contact signatures, exterior views, circulation/furnishing cutaways, inspection notes Modular aesthetic remains visible; no exhaustive beauty claim
R29 generate.py, importable scene builders, inspection example, verified one-region transport Offline runtime uses bundled schema and installed/provided MCIO
R30 Library, docs, CLI, tests, extension, output pair, manifest, reports and labeled previews Broader simulation, arbitrary entities, browser UI and city planner remain unfinished

15 · 源码、复现与完整文档

下载原始库、示例与测试 下载默认聚落及结构记录 文件统计与哈希

参考源码位于单独的 source/references/,不计入新写代码的统计。浏览器的 bridge/worker/交互客户端是报告层适配,不写回实验、不改动原始源码。原生复现先安装提供的 MCIO 及依赖,再运行下面的命令;完整接口说明见 GENERATOR 文档。

python generate.py --seed 0 --output "output.litematic" python -m pytest -q test python -m examples.assess --seed 0 --output reports/reassessment --artifacts python -m examples.inspection --seed 0
文件表:点击列头排序,或按模块筛选
路径行数SHA-256
generate.py21d0ca8be7fa4af0e1d345130b23e12e509f82d9eccb136131cd77f1d2fc12fc48
hearth/__init__.py5cc633fcd4d42f7417abeb2c75c9b6217649b424d991fdcc215a8ba11fc25243e
hearth/adapters/__init__.py26e2eea2e63bf34d477cc63f4fe9a362572a74709e28dcb2e97053943b7366fcd
hearth/adapters/site.py137a7e96c49d9697b041b9bfc5d646943397ee00cc91068377fa36f3d20b73b4a69
hearth/assessment.py163a6fe7486ff08c1c437af971ca62237424d42af53c392410948dd0b1d83dc9e64
hearth/blocks.py83dd43b62cde7bdce81de699632c14bb1e2d2e3e59f8e67bce383784f2b7a27596
hearth/components/__init__.py47243a6a3e85c60cc69ae7549354ce6e3637b3f13581d388f2ee46d77af08dcce
hearth/components/building.py1583491fdfeb23615a5868dd9cecdac20772dff7835176690ec71753a65a24298d0
hearth/components/constraints.py19aed416b50228cce52fc7eeca409bc8fa3c9cc5f85260f779cff0ad67ecdad631
hearth/components/interior.py210d88ff1187e9f4378a01a7a73365d6d7354951422d16f2ee2e92d6c642487e384
hearth/components/landscape.py253527e59621cad693abbc140acdac96f26f7eab697149809c08e7ea04a24a5a12c
hearth/components/primitives.py191efe13b95273d37da4299f54020b688b138ef3813b0ba8e7b4208b799dfcd04d9
hearth/components/roofs.py1250f8e5978a38dc7fe30b0223434998617dc6e581c257acc2b942f9626a344c8fa
hearth/composition.py610df1a52c9a42534744a86a74e5f75f5deaff5a46d1d1c9990e9c716854c017e5
hearth/environment/__init__.py3effbea4c76ce63a5ffafe37c146ce6d4ee95eed2afa1d30644ed640b7a96521e
hearth/environment/fields.py790dff276c440e3d7b45f5a01934c776354e2b92b48a989bc7c2464deafbbcd5a4
hearth/environment/terrain.py42f65c149259433a59ac81fe7102b4953408664d8ddbfa3141dcb57f9526eb0e7b
hearth/kernel/__init__.py5586df3f13a38e77633d20f7660bbf850c68f6d8b1f8b0bf2131a6ab36f0ecd5a
hearth/kernel/contracts.py15044e4f063d9d194d74295a569eeed8f57474afb201fe7d71d9719a4441d7c125e
hearth/kernel/errors.py32c10cc183e92621cf96ab340f8b22bd846d76f1d4ca5a73e846c6bb23fe4daca5
hearth/kernel/scene.py535acd7e2f8f1bf40fd89d0fe9d3bc2da04a008ec3e29ee138dc4cd09b1e082fbd7
hearth/kernel/validation.py220adafa1997fe4b664dbfe1634ce0c9c99d328306a8e23649d7bc201af0c3b75f7
hearth/kernel/view.py166bdb8856fcdf5b25989835721716cb479acb60c3bafcdb4cb1e7c53debf7e9885
hearth/persistence.py194ffd2d9a5a9f4c7aa1651a38dfdfc33f6c7957c8ea6ccca1bfde56e3e9384022b
hearth/programs.py1750255bb4fc30382706411195083406fd36bc95edb75f578c813e92926f9366179
hearth/randomness.py218523ae185dfbc40a89c7391a4eef8c0c9733435b36c5622c6a2c49b2d1236622
hearth/space.py109a6c1123e38a8b74e88ef116488eeadaec0b5a95edef8ae9f82ee517242ac9a2c
examples/__init__.py12f4de7abf0cbb4b2e630934f9c5e25ce49e6c2faec6e7473ebef685630b39770
examples/assess.py13da568047fda3729a393207c18ff1a7d5f9d9a44e6a0f213af2fa9eeae54720f8
examples/building.py13d61f26e255b040a465f19dac7dfc4d35cae74227208a473ccd3d85918481e25d
examples/courtyard.py255bebd698b6103738cf1aef02a65f7e92e523d29c7d5c05729796ebca55ebd12c
examples/extension.py27710712abce4af003237ef5f9d6ce150d7529fc0757165626fc1adad6a1d12267
examples/gallery.py250f53e6b3eed341aa3386fcc223ca427a36b063ab27d2b5a45b5ac79beb45003d
examples/inspection.py28bc0612174362638dbb1dc22275b3537cd96717d7810fb1b89efdcb0d5eb49a7b
examples/preview.py624e574388487b1e94c164a26f8677edcc911b552f956ea0908bf9131182b4886e
examples/prototype.py339be9027d041fd317cd747eb5fa10e3d7e3de54230fe906f70230bc4d2bee3c85
examples/verify_replay.py354f7562d3978540bd3afbd714e7d90043a2ff6e98cc3591c92771e30ac6e19524
extension_demo/__init__.py3859ca7747843afa7f468ddf6bbfbc5755c6553f7c64edadaf912d53b19edda558
test/conftest.py13ee46bb8f7372a8a96af034dfcf6aa532762226dc4acefdf24b512272e19d313d
test/test_contracts_provenance.py2798680544efe88f9f76ca1d266fb87fb7f19eb811c0c10f34116e4c4e0df192404
test/test_geometry_environment.py243616a57ff81522418e3db15d685bad8325d398eb07faed3cd78413067301e0b40
test/test_kernel.py122c6d7ea542a7c27241baff94b6ad26c7e75a87962cf902a4d2fc7bc4093db7914
完整原始 ARCHITECTURE.md

Hearth architecture, version 1.1.0

The initial design was written before the kernel or extensive scene geometry. The executable foundation passed seven tests before the terrain/grass/tree/wall/window prototype, then furnished rooms and buildings were added, followed by settlements and the finite corpus. The stage sequence and generic fixes are recorded in reports/development-findings.md. This document describes the implemented design; GENERATOR.md contains usage and the R01-R30 evidence ledger.

Module boundaries

Layer Modules Responsibility
Values and geometry space, blocks, randomness Inclusive integer boxes, frames, Java blockstates, stable random scopes
Composition kernel kernel/contracts, scene, view, validation, errors Negotiation, permissions, transactions, instances, graphs, queries and rule scheduling
Environments environment/fields, terrain Composable field expressions, frozen sampled strata and water
Architectural knowledge components/*, adapters/site Windows, walls, furnishings, rooms, roofs, buildings, contact and access strategies
Public composition composition, programs Selection, encapsulation, arrangement, repetition, scattering, room graphs and settlement intent
Transport and assessment persistence, assessment, examples/* Verified Litematica export/reload, inspection, explicit batches
Independent extension extension_demo A different light and a composite reading suite with a forwarded entrance

The kernel imports no concrete architectural implementation and never imports the CLI. The CLI is an ordinary client. A browser adapter could retain the kernel, field expressions, plans and JSON records, replacing the Python host/transport. No browser runtime or UI is included.

One protocol for leaves and composites

A component implements:

capability() -> Capability negotiate(context: Context, parameters: dict) -> Contract realize(context: Context, contract: Contract) -> Plan

Capability separates feasible offers from a placed instance. It includes semantic tags, executable Domain checks for constructor inputs and execution parameters, assumptions, adaptation strategies, guarantees, implementation version and locked decisions. Nested constructor paths such as design.bay, and frame.turn, have executable domains. Constructors carry explicit principal intent; parameters contains only advertised runtime overrides. Unknown overrides fail. Recorded inputs include public constructor fields, execution arguments and negotiated decisions.

Contract contains a conservative local envelope, ports, grants, rules, decisions, input regions and whole-object status. It becomes a world-space contract through the instance frame. Occupied geometry is derived from effects and indexed exactly; an envelope is never substituted for actual membership. Rules express support, protected clearance, preservation, enclosure, lighting, furnishing and access. Effect coordinates must stay within the negotiated envelope, and child envelopes within their parent's envelope. Expansion requires another negotiation.

A Port has a kind, oriented frame, region, capacity, alignment, facts and an optional grant. Wall ports expose thickness, sill and excluded frame margins. A Binding names a host and port, a verb, and an optional further restriction in world coordinates. Installation requires compatible orientation, anchor alignment, available capacity and a compatible grant. Windows negotiate their reveal depth against the public port; parents can substitute shuttered and hooded implementations.

Composite ports may delegate to a named child port. The kernel resolves authority through the chain, while callers bind to the composite. It verifies the realized child's frame, region and kind against the negotiated public interface, including during later validation. Buildings forward their street connection; settlements forward a public gateway through their path composition. The independent reading suite forwards its room entrance. Parents do not name private approach children.

Plans, candidates and transactions

Plan contains writes, children, bounded Choice operations and typed relationships. Component code reads an environmental view and returns effects. It cannot receive the shared mutable store through its context. The view copies contract/port records and exposes styles through a read-only mapping. This is a trusted Python programming protocol, not an arbitrary-code security sandbox.

A placement forks the current state. The kernel:

  1. Allocates a stable instance path and random scope; checks feasible domains.
  2. Negotiates a contract and resolves binding authority.
  3. Applies final per-coordinate effects under the executing component/operation identity.
  4. Instantiates semantic children through the same protocol.
  5. Checks tentative geometry, existing consumers and completed local obligations.
  6. Commits the entire state or discards the entire candidate.

Multiple writes inside one candidate component are coalesced to their final operation. They do not create false collisions with earlier versions of that component's own local plan. Foreign writes still require authority. The kernel never uses a global priority or identical-state overwrite rule. Failed transactions preserve geometry, nodes, ownership, ports, relationships, dependencies, history and sibling random scopes.

Choice evaluates complete candidate child compositions in isolated forks. It first checks hard conditions, then scores actual sitework cost and exposed support proportions. It selects by a scoped seed among alternatives within an explicit quality tolerance. adapted(...) proposes stepped perimeters and piers under the same locked principal design. Water/high relief constrain the feasible strategy set. Candidate scores and all rejection diagnostics are recorded. A bounded search with unvisited alternatives reports SearchExhausted; identical hard failures of every declared contact alternative retain the specific failed constraint. This is not a proof about unimplemented techniques.

Authority, phases and logical objects

A grant identifies an owner, region, allowed verbs, consumer tags, per-binding change limit and whether whole-object replacement is allowed. Binding restrictions can narrow a grant. A high planting preference never grants excavation rights. Soil grants local construction edits, planting consumes substrate support, and grass explicitly grants whole-object replacement to trees. Existing support and clearance rules survive unrelated edits. Pools cannot undermine a supported tree. Paired plants and doors cannot be partially replaced through an ordinary binding.

Property adjustments retain the original semantic owner and require the same block type. Deletions remove current ownership; erasure history is separate from current cells. Displaced cells are retained compactly so branch removal/regeneration can restore surviving host content. Retired grass disappears from current nodes, relationships and ownership, while the operation history can still explain its replacement.

Explicit shared support records a participant, a capacity use, a support obligation and a typed association. It does not transfer the primary owner. Shared writes require consumer rebinding; identical states alone never authorize sharing.

Construction starts with a temporarily open scope. Invariants run throughout; completion rules run when the scope closes. complete=False permits an explicitly unfinished scope, and finish_scope closes it. Unfinished or stale content cannot be finalized or exported. Once a room is complete, subsequent placements must preserve its access, lighting and enclosure. A building provides internal circulation and an external landing. The settlement discharges its connection to public paths.

Environmental observations and adaptation

View uses world coordinates and explicit known bounds. Context.world/local convert positions; Context.elevation/water/state are local-frame convenience queries. Views expose actual 3D states, owners, solid support, bounded elevation search, water, slope, substrate depth, clearance, protected regions, obstacle distance, style roles, preferences and public interfaces. Unknown space raises an error. A roof is not assumed to be the ground surface: path observations are bounded by the offered access elevation.

Field expressions support constants, gradients, waves, radial masks, addition, multiplication, blending, transforms and clamping. They can be nested and supplied by an independent compatible implementation. Water intersects the sampled strata. Adaptation never inspects an environment class, recipe label or particular seed. The 64-case assessment freezes sixteen complete 3D terrain scenes before making four independently seeded building placements on copies of each.

Sitework measures support and water, preserves gravity alignment, and bounds relief, post height, fill, excavation grants and approach length. Foundations produce support columns/perimeters to the actual solid bed. The approach examines its full tread width and water surface. The principal room graph, functions, footprint bays, locked horizontal placement and chosen roof intent remain intact. No algorithm levels the whole site to guarantee success.

Three distinct graphs and exact indexes

An instance ID is its stable parent/key path. The kernel automatically records creation type, constructor inputs, resolved decisions, frame, implementation and random scope. Helper calls do not create semantic ancestors. Windows, walls, floors, furniture, lights and adapters are actual instances.

  • Structural containment and attachment form a graph. Attachment supplies the primary structural chain, while containment remains recorded. Bridges/path networks can relate to many structures.
  • Data/constraint dependencies have a source, consumer, region, input version and reason. An automatic read trace coalesces actual spatial observations and records interface reads, supplementing declared regions and bindings. These are not false structural ancestors.
  • Operations retain generating actor, operation key, write count, displaced identities and restorable old cells. These records do not make a displaced object a current owner.

The sparse coordinate map stores one current owner and operation per occupied cell. Reverse maps provide exact cells by owner and shared participant. A structural adjacency index supports descendant queries through attachment as well as containment: a window created by an external facade program is still included when highlighting its host wall or building. Queries traverse this graph, never scan the full voxel store or copy ancestor strings onto each cell.

Removing a branch updates all indexes. External attached/dependent consumers must be regenerated or removed together; otherwise validation rejects the transaction. regenerate(path, ..., dependents=...) restores displaced host output, removes obsolete nodes and replays affected branches from their original inputs/scopes. It never repeatedly cuts the already modified terrain. Explicit co-regeneration is intentional: there is no hidden oscillating terrain/building update loop.

Persistence, coordinates and replay

Positions are (x,y,z), Y up, north -Z. A positive quarter-turn maps (x,y,z) to (-z,y,x). Frames transform coordinates, boxes, rule cells, ports and directional block properties, including cardinal connection keys, axes, rotation values and supported rail/orientation strings. Custom rule data is uninterpreted; a validator needing directions uses its node frame.

Export bounds are derived from every realized occupied cell. MCIO indexing is converted explicitly to (y,z,x). Export-local coordinates equal world coordinates minus the companion's offset. The original world frame is restored on reload, including negative coordinates.

persistence writes one Java 1.21.1 region (data version 3955) and a versioned structural JSON record. It retains capabilities/contracts, nodes, frames, random scopes, styles, field inputs, dependency and structure graphs, current ownership, operation/displacement records, and relevant inventory NBT. The geometry digest canonicalizes parsed names and explicit property mappings and includes world coordinates and block-entity data. It ignores property order only, not missing/defaulted properties. Reload reads actual schematic blocks and NBT, verifies dimensions/digest/ownership and reruns the validators. Missing/unknown metadata or mismatched geometry is rejected as untrusted.

The companion is not a cryptographic signature, and arbitrary geometry cannot reconstruct a graph. Reload does not execute serialized Python. To regenerate a reloaded branch, explicitly supply its component implementation; inputs and source programs/manifests support replay. Arbitrary entity types and a general block-entity migration system are not implemented; these artifacts export no entities.

Validation model and limits

Validators register through @validator(name); component authors use existing rules or add a named handler without editing dispatch. Missing handlers are errors, including after reload. The physical model uses integer standing positions, two air/passable cells, cardinal moves and elevation changes of at most one block with extra clearance for ascending/descending. Wood doors are considered operable. Stairs are checked as usable flights and declared clearance volumes. This is not a full Minecraft collision/fluid/redstone simulator.

Lighting propagates actual source levels through passable/transparent cells with unit attenuation; closed opaque boundaries block propagation. It checks required room locations, not a claim that all possible mob-spawning cells are spawn-proof. Enclosure checks actual room floors/ceilings and wall surfaces. Roof abutments are bounded voxel joins above sealed ceilings; universal flashing or structural mechanics are not proved. Support checks declared load paths, substrate and support grids, not an engineering stress solver for arbitrary blocks or decorative cantilevers.

Default limits are 512 blocks per axis, 1,000,000 occupied blocks, depth 40, 10,000 instances and 24 search alternatives, with at most 16,000,000 cells in the dense export bounding box. Demo count limits live in the CLI, not the kernel. Costs, bounds and failure conditions are public. Existing tests and finite observations establish only the documented scope.

完整原始 GENERATOR.md

Hearth procedural composition

Hearth generates furnished timber-and-stone buildings and a connected settlement for Minecraft Java 1.21.1. The default seed is 0; it produces five buildings, public paths, a well terrace, lights, planters, trees and grass. Structural choices include room counts/functions/adjacencies, wings, storeys, stair allocation, roof runs/pitches, porches, foundation strategies and street topology. There is no whole-building family selector in the kernel or settlement generator.

Quickstart

python generate.py python generate.py --seed 0 --output example.litematic python generate.py --seed 1 --count 6 --output "samples/six building village.litematic" python -m pytest -q test

A successful command validates the composition, exports a nonempty single region, reloads it and verifies its semantic content. Each schematic has a .litematic.structure.json companion. Keep the pair together. Explicit paths may be relative, absolute or contain spaces.

No downloads, reference generator, previous output or credentials are used. Python 3.12 and numpy are required; transport uses the provided MCIO 0.2.0 public API. It is imported normally, then from /work/generator/MCIO in this environment. On another host, install MCIO from its source before using export/reload. The Java blockstate reference is bundled under hearth/data/. Exact versions observed here are recorded in reports/dependencies.json; no additional packages were installed. Rendering additionally needs the optional supplied MCRender toolset.

Short compositions

These are intent descriptions; clients do not write voxels, repair geometry or assign block owners.

from hearth.components.building import Blueprint, RoomSpec from hearth.programs import building_scene plan = Blueprint(( RoomSpec(0, 0, 0, "living"), RoomSpec(0, 0, 1, "bedroom"), RoomSpec(1, 0, 0, "workshop"), ), bay=11, porch=True, roof_axis="auto") scene = building_scene(plan, seed=17) # No file export required.

Place on a previously generated environment:

from hearth import Scene, Box, Frame from hearth.environment import Terrain, gradient, wave from hearth.components.building import adapted scene = Scene(seed=17, domain=Box((-15, -4, -20), (40, 60, 40))) field = gradient(x=0.025, base=4) + wave(amplitude=0.7) scene.place("land", Terrain(scene.domain, field)) scene.compose_choice(adapted("home", plan, "/land", Frame((3, 0, 4), 1))) scene.finalize()

Discover and substitute implementations:

from hearth.kernel import Registry from hearth.components.interior import Light from extension_demo import Pendant registry = Registry() registry.register(Light()) registry.register(Pendant()) candidates = registry.select("room-light") # Either implementation can be supplied as Blueprint(..., light_component=...). public_ports = scene.view.offers("/home", "access") capability = scene.view.capability("/home")

hearth.composition provides encapsulate, attach, arrange, repeat, scatter and constrain. A composition returns Plan(children=[Child(...), Choice(...)]) and uses the same component protocol as a light or tree. Building, reading-suite and settlement interfaces support recursive port forwarding. ARCHITECTURE.md documents frames, grants and the complete lifecycle.

Runnable examples and batches

python -m examples.prototype --seed 0 python -m examples.building dwelling --seed 3 --output samples/dwelling-demo.litematic python -m examples.building atelier --seed 5 --output samples/atelier-demo.litematic python -m examples.building commons --seed 6 --output samples/commons-demo.litematic python -m examples.courtyard --seed 0 python -m examples.gallery --seed 0 python -m examples.extension --seed 0 python -m examples.inspection --seed 0 python -m examples.assess --seed 0 --output reports/reassessment --artifacts python -m examples.verify_replay --seed 0

The three primary programs are short room-graph recipes in hearth/programs.py. The courtyard and gallery clients were written after the abstractions existed. The independent extension supplies an actual pendant light and a nested reading suite using public components/validators. The gallery uses that extension without geometry repairs. The courtyard exposed a generic concave-corner decoration conflict, corrected by moving facade climbers away from corner installation margins.

The assessment command is an explicit batch output: it writes all inputs, results, rejections, candidate scores, summaries and selected samples. Unit tests create only cleaned temporary files under test/; they do not silently produce corpus artifacts.

Optional rendering, in the supplied proc-tool environment:

python -m examples.preview --seed 0 --input output.litematic --output previews/settlement --size 1500 python -m examples.preview --seed 6 --input samples/commons-6.litematic --output previews/commons-6 --cutaways python -m examples.preview --seed 0 --input samples/adaptation-00.litematic --output previews/adaptation-00 --cutaways python -m examples.preview --seed 1 --input samples/atelier-1.litematic --output previews/atelier-1 python -m examples.preview --seed 0 --input samples/courtyard.litematic --output previews/courtyard-0 --cutaways

The preview command checks the source pair and seed, then uses the supplied MCRender and cutaway utilities. It writes labeled views, camera records and views.json. The stair section is chosen from an actual stair instance's current cells. Geometry-only slices are not exported as completed components and have no structural companion. See previews/README.md for inspected views and observations. Rendering is not needed for generation or tests and must not be invoked on another host without the optional tools/assets.

Seeds, domains and adaptation

Seeds are explicit signed Python integers. SHA-256 derives streams from seed, stable instance keys and purpose; Python hash() and ambient randomness are never used. Planning, adaptation, geometry, materials and decoration use separate purpose keys. Child(..., seed=...), Scene.place(..., seed=...) and regenerate(..., seed=...) override a subtree. Scene.fork(seed=...) preserves existing frozen content and changes only the seed for future placements. Stable independent branches commute; dependent grass/tree replacement intentionally does not.

The delivered building planner supports connected grid rooms with bay sizes 9, 11 or 13, six furnishing purposes, supported stacked levels, shared horizontal circulation and one vertical flight per upper connected group. Ordinary room contracts support the same bay sizes. Walls expose widths 5-64, heights 4-12 and thicknesses 1-3. Other implementations can advertise different feasible domains; the kernel has no room-grid or building-count dispatch.

Site policy defaults: measured relief at most 5, bed-to-floor support height at most 8, at least two contiguous solid bed cells, approach length at most 12, foundation fill at most 1,600 cells and excavation authority bounded by the terrain grant (default 2,500 changes per binding). SiteLimits and grants expose these values. Contact alternatives compare actual effects, permitting local piers, stepped perimeter work and access treads. The default buildings do not excavate; the pool component exercises authorized excavation separately. Small terraces fill bounded local differences. The major terrain surface is not flattened.

Hard constraints include write authority, existing consumers, declared support/headroom, protected regions, locked room functions and placement. Preference fields and style roles are public observations. Preferences do not override constraints. Unknown space is an error. The kernel rejects effects outside accepted envelopes and derives export bounds from realized content, including vegetation and adapters. Limits controls dimensions, block count, instances, recursion, candidate budget and dense export volume.

A completed standalone building offers an exterior landing. Its enclosing composition is responsible for a public path beyond that landing; a wet site can offer a boardwalk landing. The settlement fulfills this obligation and exposes its own public gateway. It can be translated and rotated as a composite.

Inspection, identity and regeneration

from pathlib import Path from hearth.persistence import export_scene, load_scene point = next(p for p, cell in scene.blocks.items() if cell.state == "minecraft:glass") explanation = scene.inspect(point) print(explanation["chain"], explanation["related"], explanation["operation"]) cells = scene.cells(explanation["instance"], descendants=True) export_scene(scene, Path("sample.litematic")) restored = load_scene(Path("sample.litematic")) assert restored.inspect(point) == explanation

The runnable inspection example selects actual room glass and prints its window, host wall, room and building chain, typed relationships and exact cells before and after reload. See reports/inspection.txt. cells(..., descendants=True) follows semantic attachment/containment indexes, including windows installed by a higher-level facade program. shared=True includes explicitly shared supports. Removed/displaced objects are not current owners.

World coordinates are (x,y,z). Export coordinates subtract the JSON offset; reload restores the world coordinates. Quarter-turns transform states, ports, claims and ownership consistently. Explicit property mappings compare regardless of order; omitted properties are never inferred for equality. Inventory NBT is transported and verified. Missing, unknown or mismatched companions are rejected; a bare schematic is not claimed to contain its original semantic graph.

scene.regenerate("/land", new_terrain, dependents=("/house",)) explicitly replaces affected output and replays dependent branches. Old displaced terrain is restored before replay. Dependency records include automatic spatial/interface read traces and input versions. Invalidated branches cannot be exported as completed. After reload, regeneration requires an explicit component implementation; serialized metadata is never executed as Python.

Diagnostics and failure behavior

ContractError.diagnostic contains rule, component, position and conditions. ValidationError.diagnostics reports actual geometry violations. Examples include write-authority, whole-object, edit-limit, protected-region, support, clearance, reachability, lighting, door-pair, pool-containment, forwarded-interface and geometry-mismatch.

Failed candidates leave the entire scene unchanged. SearchExhausted distinguishes a search budget from an established parameter/contact incompatibility. A failed finite search does not prove that no other algorithm or composition can succeed. Tests include a budget-limited rejection where the next, unvisited candidate is valid.

Evidence and limits

The frozen sampling policy is reports/sampling-policy.json. The current results are reports/final-corpus/results.json, summary.json and adaptation-inputs.json. Earlier result records remain under reports/baseline-corpus/ and reports/corpus/; their historical sample paths are labeled as superseded, not current matching artifacts.

reports/ASSESSMENT.md gives denominators, costs and timings: 134 tests passed, 64/64 adaptation inputs, 24/24 building runs and 10/10 settlement runs validated. The stress batch retained 9 valid / 32 inputs, plus 23 explicit limit incompatibilities. There were no budget-exhausted or unexplained-defect cases in the final corpus. Per-candidate acceptance is reported separately. Seed-0 content matches across two Python hash seeds in reports/replay.json. All 24 delivered current artifact pairs passed reload and identity checks in reports/artifact-audit.json.

The assessed finite budget consists of 64 independent environment/building pairings, 24 building runs (three clients, seeds 0-7), ten settlement runs (seeds 0-7 plus both count boundaries), and 32 unresampled stress inputs. Sixteen complete terrain scenes are frozen independently before placing buildings. Half the environment expressions use the held-out blend/transform composition. The same public measured-geometry adapters handle all cases.

The reported successful building corpus has 18 observed principal signatures: dwelling 5/8, atelier 8/8, commons 5/8. The ten settlement runs have 10 observed signatures. Signatures exclude names, surface materials and global placement; they include actual room extents, adjacencies, storeys/stairs, roof geometry and path organization. Foundation/contact signatures are reported separately and never counted as principal architectural variety. This is finite observation only.

Known limits remain explicit:

  • The movement model uses integer standing positions, operable wooden doors, two-cell headroom and bounded one-block elevation changes. It is not the full Minecraft collision or jump simulation.
  • Lighting uses actual source propagation/occlusion at required room locations; it is not a complete skylight, mob-spawning or Minecraft update simulation.
  • Declared support paths and bounded spans are checked. Arbitrary structural stress, every decorative cantilever, and universal watertight flashing for arbitrary roof intersections are not proved. The delivered roof system handles bounded gables, runs and wall abutments over sealed ceilings.
  • General block/entity migration, arbitrary entity generation, a browser viewer, and a full city planner are not implemented. Exported entity lists are empty; barrel inventories are real NBT.
  • Regeneration is explicit and can be coarse. The kernel records affected dependencies and refuses stale completion; it does not invent an unbounded automatic replan or resolve every terrain shape.
  • The provided style is coherent timber/stone architecture, with visible modular bays. The small representative render set supports inspection, not an exhaustive aesthetic judgment or a claim to reproduce all sixteen reference images.
  • The courtyard example's central planted void is an unoccupied lightwell. Its room ring is connected; visitor access to the central garden is not part of that client's contract.

Requirement ledger

ID Implemented API/module and evidence Qualification
R01 kernel/*, initial design, seven foundation tests before content; thin CLI Executable foundation, not placeholder interfaces
R02 Independent implementation; supplied snapshots unchanged; reference images used as aesthetic goals No reference generator invoked or imported
R03 Blueprint, room graph programs, Choice, roof planner, spine/loop paths; finite signatures Room grid and roof primitives are bounded, openly documented
R04 Module table in architecture; kernel has no component imports; transport separate Browser host adapter not implemented
R05 Capability, executable Domain, Contract, Port, Grant, rules and read-only View Free-form descriptive assumptions complement executable checks
R06 Plan/Child/Choice, registry, composition operations, forwarded ports; extension/nested tests New primitives can extend beyond the shipped grid vocabulary
R07 Scoped authority, whole-object replacement, shared support; tree/grass/pool/window/clearance tests No universal priority or same-state sharing shortcut
R08 Fork/validate/commit kernel, plans and automatic read traces; rollback snapshots Trusted Python components, not a hostile-code sandbox
R09 Open/complete scopes, ancestor-aware obligations, finalization; unfinished/light and late-edit tests Standalone landing-to-public-path is an enclosing obligation
R10 Automatic nodes/operation owners, real window/wall instances; inspection and cross-scope attachment tests No per-voxel client owner maps or post-hoc tagging
R11 Structural graph, dependency graph, operations/displacement records; update/share/removal tests Historic actors may remain in history, never as current owners
R12 inspect, owner/shared reverse indexes, semantic descendant index; regeneration and deletion tests Headless queries delivered; no clickable viewer
R13 Paired JSON/Litematica, version/digest/offset checks, actual reload validation; mismatch/NBT tests Pairing integrity is not cryptographic authenticity
R14 General field algebra, masks, transforms, strata, water and constrained scattering No environment-family dispatch; finite shipped operations are extensible
R15 Domain/version-aware 3D view, elevation cap, support/water/slope/clearance/style/preferences Unknown space errors; no simulation of every Minecraft behavior
R16 Foundation, approach, window-depth and roof-abutment components Universal roof-junction/flashing solver not implemented
R17 Frozen terrain, measured site survey, bounded complete candidates, joint tentative validation Fixed principal intent; failures beyond bounds are retained
R18 Hard checks then actual effect cost/exposure score, seeded near-best choice, rejection records Search-budget negative test; no claim of exhaustive feasibility
R19 Automatic/declared input dependencies, stale flags, explicit atomic co-regeneration Dependency updates are conservative; no implicit arbitrary auto-replan
R20 SHA-256 scope keys/purposes, overrides, copied environments; branch/order/retry and hash-seed replay tests Genuine spatial dependencies may change descendants
R21 Configurable Limits, SiteLimits, effect envelopes and realized export bounds Demonstration count bound is only in the CLI
R22 Initial design, kernel tests, prototype, buildings/extension, corpus/render stages Generic defects and fixes recorded in development findings
R23 test_kernel, test_contracts_provenance: substitution, independent extension, authority, rollback, sharing, transforms, seeds Custom validator registration also tested
R24 Glass chain, two identities, external attachment membership, updates/deletions/regeneration, shared cells, transport mismatch tests Actual structure restored from companion, not inferred from materials
R25 64 frozen pairings, compatible independent field/environment, protected outside cells, perturbation and stress records Finite supported domain; 32 stress inputs retained without resampling
R26 Three short clients x eight seeds; settlement x eight seeds plus counts 3 and 6; later courtyard/gallery Programs use public room/component APIs
R27 Actual blocks/NBT: schema, support, headroom/routes, pair consistency, enclosure, lights, furnishings, pools and path joins; deliberate damage tests Physical/lighting model limitations above apply
R28 Structural/contact signatures, exterior views, circulation/furnishing cutaways, inspection notes Modular aesthetic remains visible; no exhaustive beauty claim
R29 generate.py, importable scene builders, inspection example, verified one-region transport Offline runtime uses bundled schema and installed/provided MCIO
R30 Library, docs, CLI, tests, extension, output pair, manifest, reports and labeled previews Broader simulation, arbitrary entities, browser UI and city planner remain unfinished
全部新写 Python 文件(原文、高亮、可复制)
generate.py · 21 行 · 原文件
# Generate, validate and export the default complete Hearth settlement. import argparse from pathlib import Path from hearth.programs import settlement_scene from hearth.persistence import export_scene, semantic_digest def main(): parser = argparse.ArgumentParser(description='Generate a contract-composed Minecraft Java 1.21.1 settlement.') parser.add_argument('--seed', type=int, default=0, help='Explicit integer seed, default 0') parser.add_argument('--output', type=Path, default=Path('output.litematic')) parser.add_argument('--count', type=int, choices=range(3, 7), help='Optional explicit building count, 3 through 6') args = parser.parse_args() scene = settlement_scene(args.seed, args.count) export_scene(scene, args.output) print(f'Validated {sum(n.type=="building.rooms" for n in scene.nodes.values())} buildings, {len(scene.blocks)} blocks, {len(scene.nodes)} components.') print(f'{args.output} | semantic SHA256 {semantic_digest(scene)}') if __name__ == '__main__': main()
hearth/__init__.py · 5 行 · 原文件
# Hearth public library entry points. from .kernel import Binding, Child, ContractError, Limits, Scene from .space import Box, Frame __version__ = '1.1.0'
hearth/adapters/__init__.py · 2 行 · 原文件
# Reusable environmental contact and circulation adapters. from .site import Foundation, Approach, SiteLimits, survey
hearth/adapters/site.py · 137 行 · 原文件
# Measured, bounded support and access strategies independent of terrain recipes. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of, log, stairs, name_of, solid from hearth.kernel import Capability, Contract, Port, Grant, Rule, Plan, ContractError @dataclass(frozen=True) class SiteLimits: relief: int = 5 support_height: int = 8 approach_length: int = 12 fill_volume: int = 1600 excavation_volume: int = 300 bed_thickness: int = 2 def survey(ctx, footprint, limits=SiteLimits()): samples = {} for x, z in sorted(footprint): wx, _, wz = ctx.world((x, 0, z)) obs = ctx.view.sample(wx, wz) if obs.support_depth < limits.bed_thickness: raise ContractError('substrate-depth', ctx.path, (wx, obs.elevation, wz), f'Require {limits.bed_thickness} contiguous solid bed cells, found {obs.support_depth}') samples[(x, z)] = (obs.elevation - ctx.frame.origin[1], None if obs.water is None else obs.water - ctx.frame.origin[1], obs.support_depth) heights = [v[0] for v in samples.values()] relief = max(heights) - min(heights) if relief > limits.relief: raise ContractError('site-relief', ctx.path, ctx.frame.origin, f'Measured {relief}, permitted {limits.relief}') surface = max(max(v[0], v[1] if v[1] is not None else v[0]) for v in samples.values()) floor = surface + 1 if floor - min(heights) > limits.support_height: raise ContractError('support-height', ctx.path, ctx.frame.origin, 'Bounded support depth exceeded') wet = any(v[1] is not None and v[1] >= v[0] for v in samples.values()) strategies = ['piers'] if wet or relief >= 3 else ['stepped', 'piers'] strategy = ctx.scope.choose(strategies, 'adaptation') return {'floor': floor, 'relief': relief, 'wet': wet, 'strategy': strategy, 'samples': samples, 'feasible_strategies': strategies} @dataclass(frozen=True) class Foundation: footprint: tuple[tuple[int, int], ...] floor: int strategy: str limits: SiteLimits = SiteLimits() @classmethod def rectangular(cls, width, depth, floor, strategy='stepped', limits=SiteLimits()): """Create a rectangular contact component without client voxel operations.""" if width < 1 or depth < 1: raise ValueError('Positive footprint dimensions required') return cls(tuple((x, z) for x in range(width) for z in range(depth)), floor, strategy, limits) def capability(self): return Capability('adapter.foundation', ('siteworks', 'support'), offers=('support',), assumptions=('actual bed within bounded depth',), adaptations=('stepped perimeter', 'piers to bed'), guarantees=('grounded support grid',)) def negotiate(self, ctx, parameters): positions = set(self.footprint) supports = [] columns = [] for x, z in sorted(positions): boundary = any((x + dx, z + dz) not in positions for dx, dz in ((1, 0), (-1, 0), (0, 1), (0, -1))) grid = (x % 4 == 0 and z % 4 == 0) # Piers include perimeter every third cell and all corners. edge_pier = boundary and (x % 3 == 0 or z % 3 == 0 or sum((x + dx, z + dz) not in positions for dx, dz in ((1, 0), (-1, 0), (0, 1), (0, -1))) >= 2) if not (grid or (boundary if self.strategy == 'stepped' else edge_pier)): continue wx, _, wz = ctx.world((x, 0, z)) bed = ctx.view.elevation(wx, wz) - ctx.frame.origin[1] if self.floor - bed > self.limits.support_height: raise ContractError('support-height', ctx.path, ctx.world((x, bed, z))) supports.extend((x, bed - k, z) for k in range(self.limits.bed_thickness)) columns.append((x, bed, z, self.floor - 1)) count = sum(max(0, top - bed) for x, bed, z, top in columns) if count > self.limits.fill_volume: raise ContractError('fill-volume', ctx.path, conditions=f'{count} > {self.limits.fill_volume}') for x, bed, z, top in columns: supports.extend((x, y, z) for y in range(bed + 1, top + 1)) box = Box.enclosing([(x, bed - self.limits.bed_thickness + 1, z) for x, bed, z, top in columns] + [(x, self.floor - 1, z) for x, bed, z, top in columns]) return Contract(box, rules=(Rule('support', tuple(supports)),), decisions={'columns': columns, 'strategy': self.strategy, 'fill': count, 'excavation': 0}, reads=(box,)) def realize(self, ctx, contract): p = Plan() for x, bed, z, top in contract.decisions['columns']: for y in range(bed + 1, top + 1): material = log('spruce') if self.strategy == 'piers' and y > bed + 1 else state_of('stone_bricks') p.block((x, y, z), material, 'contact') return p @dataclass(frozen=True) class Approach: center: int floor: int porch: int = 0 limits: SiteLimits = SiteLimits() def capability(self): return Capability('adapter.approach', ('siteworks', 'access'), offers=('street', 'surface'), adaptations=('stairs', 'landing', 'bounded fill'), guarantees=('two-block headroom', 'entrance connection')) def negotiate(self, ctx, parameters): rows = [] for step in range(1, self.limits.approach_length + 1): z = -self.porch - step wx, _, wz = ctx.world((self.center, 0, z)) ground = max(max(ctx.view.elevation(ctx.world((x, 0, z))[0], ctx.world((x, 0, z))[2]), (ctx.view.water(ctx.world((x, 0, z))[0], ctx.world((x, 0, z))[2]) or -10000) + 1) - ctx.frame.origin[1] for x in range(self.center - 1, self.center + 2)) y = max(ground, self.floor - step + 1) rows.append((z, y)) if y == ground: break else: raise ContractError('approach-detour', ctx.path, ctx.frame.origin, 'Cannot meet terrain within length bound') cells = [] support = [] for z, y in rows: cells.extend((x, y + k, z) for x in range(self.center - 1, self.center + 2) for k in (1, 2)) support.extend((x, y, z) for x in range(self.center - 1, self.center + 2)) low = min(ctx.view.elevation(*((lambda p: (p[0], p[2]))(ctx.world((x, 0, z))))) - ctx.frame.origin[1] for z, y in rows for x in range(self.center - 1, self.center + 2)) box = Box((self.center - 1, low, rows[-1][0]), (self.center + 1, max(y for z, y in rows) + 3, -self.porch - 1)) end = (self.center, rows[-1][1] + 1, rows[-1][0]) region = Box((self.center - 1, rows[-1][1], rows[-1][0]), (self.center + 1, self.floor + 2, min(-self.porch - 1, rows[-1][0] + 1))) port = Port('street', 'access', Frame(end), region, 10, 'surface') grant = Grant('surface', region, ('surface',), ('path',), 18) route = tuple((self.center, y + 1, z) for z, y in rows) return Contract(box, (port,), (grant,), (Rule('clear', tuple(cells)), Rule('support', tuple(support)), Rule('route', route, box.expand(1), phase='complete')), decisions={'rows': rows, 'end': end}, reads=(box,)) def realize(self, ctx, contract): p = Plan() rows = contract.decisions['rows'] for index, (z, y) in enumerate(rows): for x in range(self.center - 1, self.center + 2): wx, _, wz = ctx.world((x, 0, z)) bed = ctx.view.elevation(wx, wz) - ctx.frame.origin[1] for yy in range(bed + 1, y): p.block((x, yy, z), state_of('cobblestone'), 'step-footing') p.block((x, y, z), stairs('stone_brick', 'south') if index and rows[index - 1][1] > y else state_of('stone_bricks'), 'treads') return p
hearth/assessment.py · 163 行 · 原文件
# Reproducible corpus inputs, structural measurements and retained diagnostics. import hashlib import json import time from pathlib import Path from hearth.randomness import Scope from hearth.programs import PROGRAMS, building_scene, settlement_scene from hearth import Scene, Box from hearth.environment import Terrain from hearth.components.building import adapted from hearth.environment import gradient, wave, radial, constant from hearth.kernel import ContractError, SearchExhausted from hearth.persistence import semantic_digest, export_scene from hearth.blocks import name_of def adaptation_expression(environment_seed): rng = Scope(environment_seed).stream('frozen-environment') # Degenerate coefficients deliberately include exact flat ground. sx = rng.choice((-.045, 0, .045)) sz = rng.choice((-.035, 0, .035)) amplitude = rng.choice((0, .4, .8)) expression = gradient(sx, sz, 4) + wave(amplitude, .13, .11, rng.random() * 6) if environment_seed >= 8: mask = radial(8, 9, 28, .7).transformed(dx=2, dz=-1, scale=1.2) expression = expression.blend(gradient(-sz, sx, 4) + wave(.6, .07, .19), mask) else: expression = expression + radial(7, 8, 22, rng.choice((0, .4, .7))) expression = expression.clamp(2, 7) water = rng.choice((None, 5, 6)) return expression, water def freeze_environment(seed): expression, water = adaptation_expression(seed) scene = Scene(seed, domain=Box((-8, -4, -18), (34, 64, 34))) scene.place('land', Terrain(scene.domain, expression, water)) return scene.finalize() def adapt_frozen(environment, design, building_seed): scene = environment.fork(seed=building_seed) scene.compose_choice(adapted('building', design, '/land')) return scene.finalize() def principal_signature(scene): buildings = [] for path, node in sorted(scene.nodes.items()): if node.type != 'building.rooms': continue decision = node.contract.decisions # Realized node topology plus occupied envelope per room, normalized to building. rooms = [] roofs = [] for child, part in sorted(scene.nodes.items()): if not child.startswith(path + '/'): continue if part.type.startswith('room.'): origin = node.frame.inverse(part.frame.origin) occupied = scene.cells(child, True) relative = [part.frame.inverse(p) for p in occupied] bounds = [min(p[i] for p in relative) for i in range(3)] + [max(p[i] for p in relative) for i in range(3)] rooms.append([origin[0], origin[1] - decision['floor'], origin[2], part.type, part.contract.decisions['doors'], part.contract.decisions['stair_up'], bounds]) if part.type == 'roof.gable': roofs.append([part.contract.decisions['axis'], part.contract.decisions['span'], part.contract.decisions['steep'], len(scene.cells(child, True))]) buildings.append({'rooms': rooms, 'roofs': roofs, 'porch': decision['porch'], 'bay': decision['bay']}) layout = [] for node in scene.nodes.values(): if node.type == 'landscape.paths': pts = node.contract.decisions['waypoints'] layout.append({'points': [(p[0], p[-1]) for p in pts], 'links': node.contract.decisions['links']}) data = {'buildings': buildings, 'organization': layout} return hashlib.sha256(json.dumps(data, sort_keys=True, default=list).encode()).hexdigest(), data def contact_metrics(scene): foundations = [n for n in scene.nodes.values() if n.type == 'adapter.foundation'] data = [n.contract.decisions for n in foundations] edit_paths = {key for key, n in scene.nodes.items() if n.capability and set(n.capability.tags).intersection(('siteworks', 'path'))} occupied = sum(len(scene.cells(key)) for key in edit_paths) replacements = sum(len(scene.displaced.get(key, {})) for key in edit_paths) from hearth.blocks import solid, AIR excavated = sum(solid(old.state) and not solid(scene.blocks[p].state if p in scene.blocks else AIR) for key in edit_paths for p, old in scene.displaced.get(key, {}).items()) return {'fill': sum(d['fill'] for d in data), 'excavation': excavated, 'sitework_occupied_cells': occupied, 'replaced_cells': replacements, 'new_sitework_cells': occupied - replacements, 'strategies': [d['strategy'] for d in data], 'signature': hashlib.sha256(json.dumps(data, sort_keys=True).encode()).hexdigest()} def measured(label, recipe, inputs, output=None): start = time.perf_counter() result = {'label': label, 'inputs': inputs, 'attempts': 1, 'retries': 0} try: scene = recipe() scene.finalize() signature, structure = principal_signature(scene) choices = [e for e in scene.events if e['kind'] == 'candidate-selection'] if choices: result['attempts'] = sum(e['attempts'] for e in choices) result.update(status='validated', blocks=len(scene.blocks), components=len(scene.nodes), digest=semantic_digest(scene), principal_signature=signature, structure=structure, contact=contact_metrics(scene), accepted_candidates=sum(e['accepted'] for e in choices) if choices else 1, candidates=choices) # Hash independently frozen terrain before placement using persisted field input and current unchanged bed cells. if output: export_scene(scene, output) result['artifact'] = str(output) except SearchExhausted as exc: result.update(status='budget-exhausted', diagnostic=str(exc), accepted_candidates=0, attempts=getattr(exc, 'attempts', 1), candidates=getattr(exc, 'candidates', [])) except (ContractError, ValueError) as exc: result.update(status='incompatible' if isinstance(exc, ContractError) and exc.diagnostic.rule in ('site-relief', 'support-height', 'fill-volume', 'approach-detour') else 'defect', diagnostic=str(exc), accepted_candidates=0, attempts=getattr(exc, 'attempts', 1), candidates=getattr(exc, 'candidates', [])) result['seconds'] = round(time.perf_counter() - start, 4) return result def run_corpus(output: Path, seed=0, artifacts=False): output.mkdir(parents=True, exist_ok=True) rows = [] specs = [] environments = {} for env in range(16): expression, water = adaptation_expression(env + seed * 100) frozen = freeze_environment(env + seed * 100) environments[env + seed * 100] = frozen digest = semantic_digest(frozen) for build in range(4): specs.append({'environment_seed': env + seed * 100, 'building_seed': build, 'expression': expression.expression(), 'water': water, 'frozen_environment_digest': digest, 'environment_domain': [list(frozen.domain.lo), list(frozen.domain.hi)], 'held_out': env >= 8}) (output / 'adaptation-inputs.json').write_text(json.dumps(specs, indent=2)) for i, spec in enumerate(specs): expression, water = adaptation_expression(spec['environment_seed']) bs = spec['building_seed'] recipe = lambda e=environments[spec['environment_seed']], b=bs: adapt_frozen(e, PROGRAMS['dwelling'](b), b) artifact = Path('samples') / f'adaptation-{i:02d}.litematic' if artifacts and i in (0, 8, 35, 60) else None row = measured(f'adaptation-{i:02d}', recipe, spec, artifact) if semantic_digest(environments[spec['environment_seed']]) != spec['frozen_environment_digest']: raise AssertionError('Frozen environment mutated') rows.append(row) print(row['label'], row['status'], flush=True) for name, program in PROGRAMS.items(): for bs in range(8): artifact = Path('samples') / f'{name}-{bs}.litematic' if artifacts and bs in (0, 1, 6) else None row = measured(f'{name}-{bs}', lambda p=program, b=bs: building_scene(p(b), b), {'program': name, 'seed': bs}, artifact) rows.append(row) print(row['label'], row['status'], flush=True) for bs, count in [(s, None) for s in range(8)] + [(0, 3), (0, 6)]: label = f'settlement-{bs}-{count or "seeded"}' artifact = Path('samples') / (label + '.litematic') if artifacts and ((bs == 1 and count is None) or count in (3, 6)) else None row = measured(label, lambda b=bs, c=count: settlement_scene(b, c), {'program': 'settlement', 'seed': bs, 'count': count}, artifact) rows.append(row) print(label, row['status'], flush=True) for i in range(32): es = 1000 + seed * 100 + i rng = Scope(es).stream('stress') expression = (gradient(rng.choice((0, .12, .28, .45)), rng.choice((0, -.15, .2)), 4) + wave(rng.choice((0, 2, 5)), .13, .17, rng.random() * 6)).clamp(-2, 20) water = rng.choice((None, 5, 12)) bs = i % 8 row = measured(f'stress-{i:02d}', lambda e=expression, w=water, b=bs: building_scene(PROGRAMS['dwelling'](b), b, e, w), {'environment_seed': es, 'building_seed': bs, 'expression': expression.expression(), 'water': water}) rows.append(row) print(row['label'], row['status'], flush=True) (output / 'results.json').write_text(json.dumps(rows, indent=2)) summary = {} for name, subset in [('adaptation', rows[:64]), ('buildings', rows[64:88]), ('settlements', rows[88:98]), ('stress', rows[98:])]: good = [r for r in subset if r['status'] == 'validated'] summary[name] = {'inputs': len(subset), 'validated': len(good), 'incompatible': sum(r['status'] == 'incompatible' for r in subset), 'defects': sum(r['status'] == 'defect' for r in subset), 'budget_exhausted': sum(r['status'] == 'budget-exhausted' for r in subset), 'candidate_attempts': sum(r['attempts'] for r in subset), 'accepted_candidates': sum(r['accepted_candidates'] for r in subset), 'retries': sum(r['retries'] for r in subset), 'seconds': round(sum(r['seconds'] for r in subset), 3), 'observed_principal_signatures': len({r['principal_signature'] for r in good}), 'observed_contact_signatures': len({r['contact']['signature'] for r in good}), 'fill_range': [min((r['contact']['fill'] for r in good), default=0), max((r['contact']['fill'] for r in good), default=0)]} (output / 'summary.json').write_text(json.dumps(summary, indent=2)) manifest = [{'artifact': r['artifact'], 'inputs': r['inputs'], 'digest': r['digest'], 'status': r['status']} for r in rows if 'artifact' in r] (Path('samples') / 'replay-manifest.json').write_text(json.dumps(manifest, indent=2)) return summary
hearth/blocks.py · 83 行 · 原文件
# Canonical blockstates and a deliberately conservative physical model. import json import re from functools import lru_cache from pathlib import Path SCHEMA = json.loads((Path(__file__).parent / 'data' / 'blockstates-1.21.1.json').read_text()) AIR = 'minecraft:air' LIGHTS = {'lantern': 15, 'torch': 14, 'wall_torch': 14, 'glowstone': 15, 'sea_lantern': 15, 'shroomlight': 15, 'ochre_froglight': 15, 'pearlescent_froglight': 15, 'verdant_froglight': 15} SOFT = {'air', 'cave_air', 'water', 'short_grass', 'fern', 'dead_bush', 'dandelion', 'poppy', 'cornflower', 'allium', 'azure_bluet', 'oxeye_daisy', 'lily_of_the_valley', 'blue_orchid', 'torch', 'wall_torch', 'vine', 'snow', 'lily_pad', 'tall_grass', 'large_fern', 'sunflower', 'rose_bush', 'peony', 'lilac', 'wheat', 'carrots', 'potatoes'} @lru_cache(maxsize=4096) def parse(state: str): match = re.fullmatch(r'(minecraft:[a-z0-9_]+)(?:\[([^\]]+)\])?', state) if not match: raise ValueError(f'Invalid blockstate syntax: {state}') props = {} if match[2]: for part in match[2].split(','): key, value = part.split('=') if key in props: raise ValueError('Duplicate block property') props[key] = value return match[1], props def state_of(name: str, **properties) -> str: if not name.startswith('minecraft:'): name = 'minecraft:' + name return name + ('[' + ','.join(f'{k}={str(v).lower()}' for k, v in sorted(properties.items())) + ']' if properties else '') def canonical(state: str) -> str: name, props = parse(state) return state_of(name, **props) def blockstates_equivalent(left: str, right: str) -> bool: return parse(left) == parse(right) @lru_cache(maxsize=4096) def validate_state(state: str): name, props = parse(state) short = name.removeprefix('minecraft:') if short not in SCHEMA: raise ValueError(f'Unknown Java 1.21.1 block: {name}') domain = SCHEMA[short][0] for key, value in props.items(): if key not in domain or value not in domain[key]: raise ValueError(f'Invalid property {key}={value} for {name}') @lru_cache(maxsize=4096) def name_of(state: str) -> str: return parse(state)[0].removeprefix('minecraft:') def solid(state: str) -> bool: name = name_of(state) return name not in SOFT and not any(s in name for s in ('leaves', 'fence', 'pane', 'door', 'lantern', 'chain', 'flower_pot', 'potted_', 'carpet', 'bed', 'button')) def passable(state: str) -> bool: name = name_of(state) return name in SOFT - {'water'} or name.endswith('_door') or name.endswith('_carpet') def stairs(material='stone_brick', facing='north', half='bottom'): return state_of(material + '_stairs', facing=facing, half=half, shape='straight', waterlogged='false') def slab(material='stone_brick', half='bottom'): return state_of(material + '_slab', type=half, waterlogged='false') def log(material='spruce', axis='y'): return state_of(material + '_log', axis=axis) def leaves(material='spruce'): return state_of(material + '_leaves', distance='1', persistent='true', waterlogged='false')
hearth/components/__init__.py · 4 行 · 原文件
# Public architectural components and their explicit intent records. from .building import Blueprint, Building, RoomSpec, adapted from .interior import Room, Light, Furniture, Door, Stair from .primitives import Wall, Window, Tree, Grass, Pool, Assembly
hearth/components/building.py · 158 行 · 原文件
# Room-graph building composition and shared facade/roof planning. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.kernel import Capability, Contract, Domain, Port, Plan, Child, Choice, Binding, Rule, ContractError from hearth.adapters.site import survey, Foundation, Approach, SiteLimits from .interior import Room from .roofs import Roof, Porch @dataclass(frozen=True) class RoomSpec: x: int z: int level: int purpose: str @dataclass(frozen=True) class Blueprint: rooms: tuple[RoomSpec, ...] bay: int = 11 porch: bool = True roof_axis: str = 'auto' roof_material: str = 'deepslate_tile' steep: bool = True window_component: object = None light_component: object = None def normalized(self): return tuple(sorted(self.rooms, key=lambda r: (r.level, r.z, r.x, r.purpose))) @property def footprint(self): return tuple(sorted((r.x * self.bay + x, r.z * self.bay + z) for r in self.rooms if r.level == 0 for x in range(self.bay) for z in range(self.bay))) @property def contact_footprint(self): return tuple(sorted(set(self.footprint) | ({(x, z) for x in range(self.bay) for z in range(-3, 0)} if self.porch else set()))) def validate(self): cells = {(r.x, r.z, r.level) for r in self.rooms} if len(cells) != len(self.rooms) or (0, 0, 0) not in cells or min(min(r.x, r.z, r.level) for r in self.rooms) < 0: raise ValueError('Unique nonnegative rooms and entrance room (0,0,0) required') if self.bay not in (9, 11, 13): raise ValueError('Supported room bays: 9, 11, 13') for x, z, level in cells: if level and (x, z, level - 1) not in cells: raise ValueError('Upper rooms require a supporting lower room') reached = {(0, 0, 0)} while True: more = {p for p in cells if any(sum(abs(a - b) for a, b in zip(p, q)) == 1 for q in reached)} if more <= reached: break reached |= more if reached != cells: raise ValueError('Room adjacency graph disconnected') @dataclass(frozen=True) class Building: design: Blueprint terrain: str site_limits: SiteLimits = SiteLimits() support_strategy: str | None = None def capability(self): return Capability('building.rooms', ('building', 'habitable', 'composite'), offers=('entrance', 'street', 'attachment'), assumptions=('known ground', 'bounded relief'), adaptations=('foundation', 'approach', 'roof junction'), guarantees=('locked room graph', 'internal reachability', 'furnishing', 'lighting'), inputs={'design.bay': Domain(choices=(9, 11, 13)), 'room_graph': 'connected integer grid with supported levels', 'relief_limit': self.site_limits.relief, 'support_height_limit': self.site_limits.support_height, 'frame.turn': Domain(choices=(0, 1, 2, 3))}, locked=('design.rooms', 'design.bay', 'design.roof_axis', 'design.porch', 'frame.x', 'frame.z')) def negotiate(self, ctx, parameters): self.design.validate() b = self.design.bay rooms = self.design.normalized() measured = survey(ctx, self.design.contact_footprint, self.site_limits) if self.support_strategy is not None: if self.support_strategy not in measured['feasible_strategies']: raise ContractError('contact-strategy', ctx.path, ctx.frame.origin, 'Requested strategy incompatible with measured water/relief') measured['strategy'] = self.support_strategy floor = measured['floor'] height = max(r.level for r in rooms) * 6 width = (max(r.x for r in rooms) + 1) * b depth = (max(r.z for r in rooms) + 1) * b minimum = min(v[0] for v in measured['samples'].values()) front = self.site_limits.approach_length + (3 if self.design.porch else 0) box = Box((-1, min(minimum - self.site_limits.bed_thickness + 1, 0), -front), (width, floor + height + b + 12, depth)) points = tuple((r.x * b + b // 2, floor + r.level * 6 + 1, r.z * b + b // 2) for r in rooms) entrance = (b // 2, floor + 1, 0) route = Rule('route', (entrance,) + points, box, phase='complete') port = Port('entrance', 'access', Frame(entrance), Box(entrance, (entrance[0], entrance[1] + 1, entrance[2])), 10) decisions = {'floor': floor, 'relief': measured['relief'], 'wet': measured['wet'], 'foundation': measured['strategy'], 'rooms': [(r.x, r.z, r.level, r.purpose) for r in rooms], 'bay': b, 'roof_axis': self.design.roof_axis, 'porch': self.design.porch, 'roof_material': self.design.roof_material, 'steep': self.design.steep} approach = Approach(b // 2, floor, 3 if self.design.porch else 0, self.site_limits).negotiate(ctx, {}) access = approach.ports[0] street = Port('street', access.kind, access.frame, access.region, access.capacity, facts={'external_connection_required': True}, delegate=('approach', 'street')) return Contract(box, ports=(port, street), rules=(route,), decisions=decisions, reads=(Box((0, minimum, 0), (width - 1, floor, depth - 1)),)) def realize(self, ctx, contract): p = Plan() b = self.design.bay floor = contract.decisions['floor'] rooms = self.design.normalized() cells = {(r.x, r.z, r.level) for r in rooms} p.children.append(Child('foundation', Foundation(self.design.contact_footprint, floor, contract.decisions['foundation'], self.site_limits), bindings=(Binding(self.terrain, 'construction', 'fill', ctx.frame.box(contract.envelope)),))) # A spanning tree of vertical access: one flight per upper horizontal component. stair_columns = set() for level in sorted({r.level for r in rooms if r.level}): remaining = {(x, z) for x, z, l in cells if l == level} while remaining: seed = min(remaining) connected = {seed} while True: expanded = {v for v in remaining if any(abs(v[0] - q[0]) + abs(v[1] - q[1]) == 1 for q in connected)} if expanded <= connected: break connected |= expanded root = min(connected) stair_columns.add((root[0], root[1], level - 1)) remaining -= connected for r in rooms: adjacent = {'north': (r.x, r.z - 1, r.level), 'south': (r.x, r.z + 1, r.level), 'west': (r.x - 1, r.z, r.level), 'east': (r.x + 1, r.z, r.level)} doors = tuple(side for side, q in adjacent.items() if q in cells or (side == 'north' and (r.x, r.z, r.level) == (0, 0, 0))) windows = tuple(side for side, q in adjacent.items() if q not in cells) key = f'room-{r.x}-{r.z}-{r.level}' room = Room(r.purpose, b, b, doors, windows, (r.x, r.z, r.level + 1) in cells, (r.x, r.z, r.level) in stair_columns, (r.x, r.z, r.level - 1) in stair_columns, self.design.window_component, self.design.light_component) p.children.append(Child(key, room, frame=Frame((r.x * b, floor + r.level * 6, r.z * b)))) if self.design.porch: p.children.append(Child('porch', Porch(b), frame=Frame((0, floor, 0)))) p.children.append(Child('approach', Approach(b // 2, floor, 3 if self.design.porch else 0, self.site_limits), bindings=(Binding(self.terrain, 'construction', 'surface', ctx.frame.box(contract.envelope)),))) # Rectangular roof runs are derived from exposed top rooms, not a building family. top = {(r.x, r.z, r.level) for r in rooms if (r.x, r.z, r.level + 1) not in cells} groups = [] while top: x, z, l = min(top, key=lambda v: (v[2], v[1], v[0])) axis = self.design.roof_axis if axis == 'auto': axis = 'x' if (x + 1, z, l) in top else 'z' run = [(x, z, l)] while ((run[-1][0] + (axis == 'x'), run[-1][1] + (axis == 'z'), l)) in top: run.append((run[-1][0] + (axis == 'x'), run[-1][1] + (axis == 'z'), l)) top -= set(run) groups.append((x, z, l, axis, len(run))) for i, (x, z, l, axis, length) in enumerate(groups): w = b * (length if axis == 'x' else 1) d = b * (length if axis == 'z' else 1) p.children.append(Child(f'roof-{i}', Roof(w, d, axis, self.design.roof_material, self.design.steep), frame=Frame((x * b, floor + l * 6 + 7, z * b)))) return p def contact_quality(view, path): """Score actual candidate sitework plus exposed-support proportions.""" facts = view.contract(path).decisions cost = view.cost(path, 'siteworks') exposure = 0.4 if facts['foundation'] == 'piers' and not facts['wet'] and facts['relief'] < 2 else 0 return cost['occupied'] / 100 + cost['replaced'] / 50 + exposure def adapted(key, design, terrain, frame=Frame(), limits=SiteLimits()): """Compare complete bounded support alternatives with the principal design locked.""" candidates = tuple(Child(key, Building(design, terrain, limits, strategy), frame=frame) for strategy in ('stepped', 'piers')) return Choice(key, candidates, contact_quality)
hearth/components/constraints.py · 19 行 · 原文件
# Reusable hard preservation and clearance components. from dataclasses import dataclass from hearth.kernel import Capability, Contract, Plan, Rule from hearth.space import Box @dataclass(frozen=True) class Preserve: region: Box def capability(self): return Capability('constraint.preserve', ('constraint', 'protected-region'), guarantees=('immutable existing region',)) def negotiate(self, ctx, parameters): cells = tuple(self.region.cells()) return Contract(self.region, rules=(Rule('protected', cells, self.region, {'states': [ctx.view.state(ctx.world(p)) for p in cells]}),)) def realize(self, ctx, contract): return Plan()
hearth/components/interior.py · 210 行 · 原文件
# Usable doors, lights and furnished rooms assembled as semantic children. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of, stairs, slab, log from hearth.kernel import Capability, Contract, Domain, Grant, Port, Rule, Plan, Child, Binding, ContractError from .primitives import Volume, Wall, Window @dataclass(frozen=True) class Door: material: str = 'spruce' def capability(self): return Capability('opening.door', ('door', 'access'), guarantees=('paired halves', 'support', 'operable exit')) def negotiate(self, ctx, parameters): return Contract(Box((0, 0, 0), (0, 1, 0)), rules=(Rule('support', ((0, -1, 0),)),), atomic_object=True) def realize(self, ctx, contract): p = Plan() for y, half in enumerate(('lower', 'upper')): p.block((0, y, 0), state_of(self.material + '_door', facing='north', half=half, hinge='left', open='false', powered='false')) return p @dataclass(frozen=True) class Light: hanging: bool = True def capability(self): return Capability('light.lantern', ('light', 'room-light'), guarantees=('actual light source',)) def negotiate(self, ctx, parameters): return Contract(Box((0, 0, 0), (0, 1, 0)), rules=(Rule('expected', ((0, 0, 0),), data={'names': ['lantern']}),)) def realize(self, ctx, contract): p = Plan() p.block((0, 0, 0), state_of('lantern', hanging=str(self.hanging).lower(), waterlogged='false')) if self.hanging: p.block((0, 1, 0), state_of('chain', axis='y', waterlogged='false')) return p @dataclass(frozen=True) class Furniture: purpose: str = 'living' width: int = 11 depth: int = 11 def capability(self): return Capability('furniture.' + self.purpose, ('furniture', self.purpose), guarantees=('usable function',)) def negotiate(self, ctx, parameters): if self.purpose not in ('living', 'bedroom', 'workshop', 'library', 'kitchen', 'storage'): raise ContractError('room-function', ctx.path, conditions=self.purpose) return Contract(Box((1, 0, 1), (self.width - 2, 2, self.depth - 2))) def realize(self, ctx, contract): p = Plan() w, d = self.width, self.depth inventory = {'id': 'minecraft:barrel', 'Items': [{'Slot': 0, 'id': 'minecraft:bread', 'count': 6}, {'Slot': 1, 'id': 'minecraft:torch', 'count': 12}]} p.block((1, 0, d - 2), state_of('barrel', facing='north', open='false'), 'supplies', nbt=inventory) if self.purpose == 'bedroom': for z, part in ((2, 'foot'), (3, 'head')): p.block((2, 0, z), state_of('red_bed', facing='south', part=part, occupied='false'), 'bed') p.block((2, 0, d - 3), state_of('bookshelf')) elif self.purpose == 'library': for x in (2, 3, w - 3): for y in range(2): p.block((x, y, d - 2), state_of('bookshelf')) p.block((2, 0, 2), state_of('lectern', facing='south', has_book='false', powered='false')) elif self.purpose == 'workshop': p.block((2, 0, 2), state_of('crafting_table')) p.block((3, 0, 2), state_of('smithing_table')) p.block((2, 0, d - 3), state_of('anvil', facing='north')) elif self.purpose == 'kitchen': p.block((2, 0, 2), state_of('smoker', facing='south', lit='false')) p.block((3, 0, 2), state_of('furnace', facing='south', lit='false')) p.block((2, 0, d - 3), state_of('crafting_table')) else: for z in (2, 3): p.block((2, 0, z), stairs('spruce', 'east'), 'bench') p.block((w - 3, 0, d - 1 - z), stairs('spruce', 'west'), 'bench') p.block((3, 0, 2), state_of('spruce_fence', north='false', south='false', east='false', west='false', waterlogged='false')) p.block((3, 1, 2), state_of('spruce_pressure_plate', powered='false'), 'table') # Rugs avoid the central circulation cross and door landings. for x in (3, 4): for z in (d - 4, d - 3): p.block((x, 0, z), state_of('red_carpet'), 'rug') return p @dataclass(frozen=True) class Stair: rise: int = 6 width: int = 2 def capability(self): return Capability('circulation.stair', ('stairs', 'vertical-access'), guarantees=('walkable flight', 'two-block headroom')) def negotiate(self, ctx, parameters): points = tuple((x, i + 1, i) for i in range(self.rise) for x in range(self.width)) clear = tuple((x, i + k, i) for i in range(self.rise) for x in range(self.width) for k in (1, 2, 3)) support = tuple((x, i, i) for i in range(self.rise) for x in range(self.width)) box = Box((0, 0, -1), (self.width - 1, self.rise + 2, self.rise)) return Contract(box, rules=(Rule('support', support), Rule('clear', clear), Rule('route', points, box, phase='complete'))) def realize(self, ctx, contract): p = Plan() for i in range(self.rise): for x in range(self.width): for y in range(max(0, i - 1), i): p.block((x, y, i), state_of('spruce_planks'), 'stringer') p.block((x, i, i), stairs('spruce', 'south'), 'tread') return p @dataclass(frozen=True) class Room: purpose: str width: int = 11 depth: int = 11 doors: tuple[str, ...] = ('north',) windows: tuple[str, ...] = ('north', 'east', 'south', 'west') upper_open: bool = False stair_up: bool = False stair_down: bool = False window_component: object = None light_component: object = None def capability(self): return Capability('room.' + self.purpose, ('room', 'habitable', 'composite'), offers=('access',), guarantees=('lit', 'furnished', 'reachable', 'enclosed'), adaptations=('facade grid', 'substitutable windows and lights'), inputs={'width': Domain(choices=(9, 11, 13)), 'depth': Domain(choices=(9, 11, 13)), 'purpose': Domain(choices=('living', 'bedroom', 'library', 'workshop', 'kitchen', 'storage'))}, locked=('purpose', 'width', 'depth', 'doors', 'stair_up', 'stair_down')) def negotiate(self, ctx, parameters): w, d = self.width, self.depth if w not in (9, 11, 13) or d not in (9, 11, 13): raise ContractError('room-domain', ctx.path) doors = {'north': (w // 2, 1, 0), 'south': (w // 2, 1, d - 1), 'west': (0, 1, d // 2), 'east': (w - 1, 1, d // 2)} points = [doors[k] for k in self.doors] + [(w // 2, 1, d // 2)] if not self.doors: points = [(w // 2, 1, d // 2)] interior = Box((1, 1, 1), (w - 2, 5, d - 2)) boundary = [] for x in range(w): for z in range(d): # Upper landing leaves only the required stair slot open. if not (self.stair_down and x in (w - 4, w - 3) and 2 <= z <= 7): boundary.append((x, 0, z)) if not (self.stair_up and x in (w - 4, w - 3) and 2 <= z <= 7): boundary.append((x, 6, z)) function = {'bedroom': [['red_bed'], ['barrel']], 'workshop': [['crafting_table'], ['smithing_table']], 'library': [['bookshelf'], ['lectern']], 'kitchen': [['smoker'], ['furnace']], 'living': [['spruce_stairs'], ['barrel']], 'storage': [['barrel']]} rules = (Rule('route', tuple(points), Box((0, 1, 0), (w - 1, 8, d - 1)), phase='complete'), Rule('light', tuple(points), Box((0, 1, 0), (w - 1, 5, d - 1)), {'minimum': 1}, 'complete'), Rule('furnishing', box=interior, data={'groups': function[self.purpose]}, phase='complete'), Rule('sealed', tuple(boundary), phase='complete')) ports = tuple(Port(side, 'access', Frame(p), Box(p, (p[0], p[1] + 1, p[2])), 10) for side, p in doors.items() if side in self.doors) return Contract(Box((-1, 0, -1), (w, 9, d)), ports=ports, rules=rules, decisions={'purpose': self.purpose, 'doors': self.doors, 'windows': self.windows, 'stair_up': self.stair_up, 'stair_down': self.stair_down}) def realize(self, ctx, contract): w, d = self.width, self.depth p = Plan() floor = Plan() for x in range(w): for z in range(d): if not (self.stair_down and x in (w - 4, w - 3) and 2 <= z <= 7): floor.block((x, 0, z), state_of('spruce_planks')) p.children.append(Child('floor', Pattern('floor', Box((0, 0, 0), (w - 1, 0, d - 1)), tuple(floor.writes)))) if not self.upper_open: p.children.append(Child('ceiling', Volume(Box((0, 6, 0), (w - 1, 6, d - 1)), state_of('spruce_planks'), 'ceiling'))) walls = {'north': (Frame((0, 1, 0)), w), 'south': (Frame((w - 1, 1, d - 1), 2), w), 'east': (Frame((w - 1, 1, 1), 1), d - 2), 'west': (Frame((0, 1, d - 2), 3), d - 2)} for side, (frame, length) in walls.items(): wallpath = ctx.path + '/wall-' + side p.children.append(Child('wall-' + side, Wall(length, 5), frame=frame)) if side in self.doors: at = frame.compose(Frame((length // 2, 0, 0))) p.children.append(Child('door-' + side, Door(), frame=at, bindings=(Binding(wallpath, 'infill'),))) if side in self.windows: bays = (2, length - 4) if length >= 11 else ((1, length - 3) if length >= 9 else ((length - 2) // 2,)) for i, bay in enumerate(bays): if side in self.doors and abs(bay - length // 2) < 2: continue at = frame.compose(Frame((bay, 2, 0))) p.children.append(Child(f'window-{side}-{i}', self.window_component or Window(), frame=at, bindings=(Binding(wallpath, 'infill'),))) # Furnish the opposite half to the flight; clipping stays inside the furnishing component's declared domain. furniture = Furniture(self.purpose, w, d) if self.stair_up or self.stair_down: furniture = Furniture(self.purpose, w - 3, d) p.children.append(Child('furniture', furniture, frame=Frame((0, 1, 0)))) for i, (x, z) in enumerate(((2, d - 3), (w - 3, 2))): if self.stair_up and i == 1: x = w // 2 p.children.append(Child(f'light-{i}', self.light_component or Light(), frame=Frame((x, 4, z)))) from .landscape import FacadeGarden p.children.append(Child('facade-garden', FacadeGarden(w, d, tuple(s for s in self.windows if s not in self.doors)))) if self.stair_up: p.children.append(Child('stairs', Stair(), frame=Frame((w - 4, 1, 2)))) return p @dataclass(frozen=True) class Pattern: role: str envelope: Box writes: tuple def capability(self): return Capability('surface.' + self.role, (self.role,)) def negotiate(self, ctx, parameters): return Contract(self.envelope) def realize(self, ctx, contract): return Plan(writes=list(self.writes))
hearth/components/landscape.py · 253 行 · 原文件
# Public paths, planted borders, lamps and constrained landscape compositions. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of, stairs, slab, log, leaves, name_of from hearth.kernel import Capability, Contract, Port, Grant, Rule, Plan, Child, Binding, ContractError from hearth.composition import scatter from .primitives import Tree, Grass from .interior import Light @dataclass(frozen=True) class PathNetwork: waypoints: tuple[tuple[int, int], ...] links: tuple[tuple[int, int], ...] width: int = 3 gateway: tuple | None = None def capability(self): return Capability('landscape.paths', ('path', 'connection'), offers=('public-access',), adaptations=('terrain treads', 'bounded retaining edges'), guarantees=('connected public routes',)) def _points(self): points = set() for a, b in self.links: x, z = self.waypoints[a][0], self.waypoints[a][-1] xx, zz = self.waypoints[b][0], self.waypoints[b][-1] dx = 1 if xx >= x else -1 dz = 1 if zz >= z else -1 offsets = range(-(self.width // 2), self.width // 2 + 1) if x != xx: for px in range(x, xx + dx, dx): for offset in offsets: points.add((px, z + offset)) if z != zz: for pz in range(z, zz + dz, dz): for offset in offsets: points.add((xx + offset, pz)) if x == xx and z == zz: for ox in offsets: for oz in offsets: points.add((x + ox, z + oz)) return sorted(points) def negotiate(self, ctx, parameters): points = [] for x, z in self._points(): hint = min(self.waypoints, key=lambda q: abs(q[0] - x) + abs(q[-1] - z)) maximum = hint[1] + ctx.frame.origin[1] if len(hint) == 3 else None wx, _, wz = ctx.world((x, 0, z)) h = ctx.view.elevation(wx, wz, maximum=maximum) - ctx.frame.origin[1] points.append((x, h, z)) if not points: raise ContractError('empty-path', ctx.path) box = Box.enclosing(points).expand(2) targets = [] surface = {(x, z): y for x, y, z in points} for q in self.waypoints: x, z = q[0], q[-1] targets.append((x, surface[(x, z)] + 1, z)) clears = tuple((x, y + k, z) for x, y, z in points for k in (1, 2)) public = self.gateway or targets[0] interface = Box((public[0] - 1, public[1] - 1, public[2]), (public[0] + 1, public[1] + 1, public[2])) return Contract(box, ports=(Port('public', 'public-access', Frame(public), interface, 10000, 'join'),), grants=(Grant('join', interface, ('surface',), ('path',), 9),), rules=(Rule('support', tuple(points)), Rule('clear', clears), Rule('route', tuple(targets), box, phase='complete')), decisions={'surface': points, 'waypoints': self.waypoints, 'links': self.links}, reads=(box,)) def realize(self, ctx, contract): p = Plan() rng = ctx.rng('materials') heights = {(x, z): y for x, y, z in contract.decisions['surface']} for x, y, z in contract.decisions['surface']: uphill = [] for dx, dz, face in ((1, 0, 'east'), (-1, 0, 'west'), (0, 1, 'south'), (0, -1, 'north')): if heights.get((x + dx, z + dz), y) > y: uphill.append(face) material = stairs('stone_brick', uphill[0]) if uphill else state_of(rng.choice(('stone_bricks', 'stone_bricks', 'andesite', 'cobblestone', 'mossy_stone_bricks'))) p.block((x, y, z), material, 'paving') return p @dataclass(frozen=True) class Planter: width: int = 3 flowers: tuple[str, ...] = ('cornflower', 'azure_bluet', 'allium') def capability(self): return Capability('garden.planter', ('decoration', 'plant'), guarantees=('grounded bed',)) def negotiate(self, ctx, parameters): return Contract(Box((0, 0, 0), (self.width - 1, 1, 1)), rules=(Rule('support', tuple((x, -1, z) for x in range(self.width) for z in range(2))),)) def realize(self, ctx, contract): p = Plan() rng = ctx.rng('flowers') for x in range(self.width): p.block((x, 0, 0), state_of('dirt'), 'soil') p.block((x, 1, 0), state_of(rng.choice(self.flowers)), 'flower') p.block((x, 0, 1), state_of('spruce_trapdoor', facing='south', half='bottom', open='true', powered='false', waterlogged='false'), 'edging') return p @dataclass(frozen=True) class LampPost: def capability(self): return Capability('landscape.lamppost', ('light', 'outdoor-light', 'composite')) def negotiate(self, ctx, parameters): return Contract(Box((0, 0, 0), (1, 4, 0)), rules=(Rule('support', ((0, -1, 0),)),)) def realize(self, ctx, contract): p = Plan() p.block((0, 0, 0), state_of('stone_bricks')) for y in range(1, 4): p.block((0, y, 0), state_of('spruce_fence', north='false', south='false', east='false', west='false', waterlogged='false')) p.block((0, 4, 0), slab('spruce')) p.block((1, 4, 0), slab('spruce')) p.children.append(Child('lantern', Light(), frame=Frame((1, 2, 0)))) return p @dataclass(frozen=True) class Landscape: area: Box terrain: str tree_minimum: int = 6 tree_maximum: int = 14 density: float = 0.08 def capability(self): return Capability('landscape.scatter', ('landscape', 'composite'), adaptations=('clearance-aware scattering',), guarantees=('minimum tree count', 'preserved routes')) def negotiate(self, ctx, parameters): return Contract(self.area, decisions={'minimum_trees': self.tree_minimum, 'maximum_trees': self.tree_maximum, 'density': self.density}) def realize(self, ctx, contract): p = Plan() x0, _, z0 = self.area.lo x1, _, z1 = self.area.hi candidates = [(x, z) for x in range(x0 + 4, x1 - 3, 4) for z in range(z0 + 4, z1 - 3, 4)] def legal(q, accepted): x, z = q if any(abs(x - a) + abs(z - b) < 10 for a, b in accepted): return False h = ctx.elevation(x, z) if name_of(ctx.state((x, h, z))) != 'grass_block': return False box = Box((x - 3, h + 1, z - 3), (x + 3, h + 16, z + 3)) return all(ctx.view.domain.contains(ctx.world(c)) for c in box.corners()) and ctx.view.clear(ctx.frame.box(box)) and not ctx.view.protected(ctx.frame.box(Box((x - 3, h, z - 3), (x + 3, h + 2, z + 3)))) chosen = scatter(ctx, candidates, legal, self.tree_minimum, self.tree_maximum, 'trees') for i, (x, z) in enumerate(chosen): y = ctx.elevation(x, z) + 1 h = ctx.scope.child(f'tree-{i}').choose((9, 11, 13, 15), 'height') p.children.append(Child(f'tree-{i}', Tree(h), frame=Frame((x, y, z)), bindings=(Binding(self.terrain, 'planting', 'plant'),))) rng = ctx.rng('groundcover') for x in range(x0 + 1, x1): for z in range(z0 + 1, z1): if rng.random() > self.density or any(abs(x - a) <= 3 and abs(z - b) <= 3 for a, b in chosen): continue h = ctx.elevation(x, z) if name_of(ctx.state((x, h, z))) != 'grass_block': continue if name_of(ctx.state((x, h + 1, z))) != 'air': continue if ctx.view.protected(ctx.frame.box(Box((x, h + 1, z), (x, h + 2, z)))): continue p.children.append(Child(f'grass-{x}-{z}', Grass(), frame=Frame((x, h + 1, z)), bindings=(Binding(self.terrain, 'planting', 'plant'),))) return p @dataclass(frozen=True) class FacadeGarden: width: int depth: int sides: tuple[str, ...] def capability(self): return Capability('facade.garden', ('decoration', 'plant'), adaptations=('avoid facade openings',), guarantees=('unobstructed doorways',)) def negotiate(self, ctx, parameters): return Contract(Box((-1, 0, -1), (self.width, 3, self.depth))) def realize(self, ctx, contract): p = Plan() w, d = self.width, self.depth frames = {'north': Frame((0, 0, -1)), 'south': Frame((w - 1, 0, d), 2), 'east': Frame((w, 0, 0), 1), 'west': Frame((-1, 0, d - 1), 3)} for side in self.sides: f = frames[side] length = w if side in ('north', 'south') else d for y in range(1, 4): q = f.point((1, y, 0)) if name_of(ctx.view.state(ctx.world(q))) == 'air': p.block(q, leaves('oak'), 'climber') for x in (2, length - 3): q = f.point((x, 0, 0)) above = f.point((x, 1, 0)) if name_of(ctx.view.state(ctx.world(q))) == 'air' and name_of(ctx.view.state(ctx.world(above))) == 'air': p.block(q, slab('spruce', 'top'), 'flower-shelf') p.block(above, state_of('potted_poppy' if x == 2 else 'potted_fern'), 'pot') return p @dataclass(frozen=True) class Well: def capability(self): return Capability('square.well', ('amenity', 'composite'), guarantees=('contained water', 'grounded cover')) def negotiate(self, ctx, parameters): basin = tuple((x, 1, z) for x in range(1, 3) for z in range(1, 3)) return Contract(Box((-1, 0, -1), (4, 6, 4)), rules=(Rule('support', tuple((x, -1, z) for x in range(4) for z in range(4))), Rule('pool', basin), Rule('support', tuple((x, y, z) for x, z in ((0, 0), (3, 3)) for y in range(2, 6))))) def realize(self, ctx, contract): p = Plan() p.fill(Box((0, 0, 0), (3, 1, 3)), state_of('stone_bricks'), 'basin') p.fill(Box((1, 1, 1), (2, 1, 2)), state_of('water', level='0'), 'water') for x, z in ((0, 0), (3, 3)): p.fill(Box((x, 2, z), (x, 5, z)), log(), 'post') for x in range(-1, 5): for z in range(-1, 5): p.block((x, 5 if x in (-1, 4) else 6, z), slab('dark_oak'), 'shelter') return p @dataclass(frozen=True) class Terrace: width: int = 10 depth: int = 10 def capability(self): return Capability('site.terrace', ('siteworks', 'composite'), adaptations=('small local fill', 'retaining border'), guarantees=('level civic amenity pad',)) def negotiate(self, ctx, parameters): heights = [ctx.view.elevation(ctx.world((x, 0, z))[0], ctx.world((x, 0, z))[2]) - ctx.frame.origin[1] for x in range(self.width) for z in range(self.depth)] top = max(heights) if top - min(heights) > 3: raise ContractError('terrace-relief', ctx.path, conditions='Small terrace limit is 3') region = Box((0, top, 0), (self.width - 1, top + 2, self.depth - 1)) return Contract(Box((0, min(heights), 0), (self.width - 1, top + 8, self.depth - 1)), ports=(Port('entrance', 'public-access', Frame((0, top + 1, self.depth // 2)), region, 10, 'paving'),), grants=(Grant('paving', region, ('surface',), ('path',), 32),), decisions={'height': top, 'fill': sum(top - h for h in heights), 'excavation': 0}) def realize(self, ctx, contract): p = Plan() top = contract.decisions['height'] for x in range(self.width): for z in range(self.depth): wx, _, wz = ctx.world((x, 0, z)) bed = ctx.view.elevation(wx, wz) - ctx.frame.origin[1] for y in range(bed, top + 1): material = 'cobblestone' if y < top else ('stone_bricks' if x in (0, self.width - 1) or z in (0, self.depth - 1) else 'andesite') p.block((x, y, z), state_of(material), 'terrace-paving') p.children.append(Child('well', Well(), frame=Frame((3, top + 1, 3)))) for i, x in enumerate((1, self.width - 2)): p.children.append(Child(f'planter-{i}', Planter(2), frame=Frame((x if i == 0 else x - 1, top + 1, 1)))) return p
hearth/components/primitives.py · 191 行 · 原文件
# Small architectural components with executable contracts. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import AIR, state_of, log, leaves, name_of from hearth.kernel import Capability, Contract, Domain, Grant, Port, Rule, Plan, Child, Binding, ContractError @dataclass(frozen=True) class Volume: box: Box material: str role: str = 'masonry' def capability(self): return Capability('volume.' + self.role, (self.role,)) def negotiate(self, ctx, parameters): return Contract(self.box) def realize(self, ctx, contract): plan = Plan() plan.fill(self.box, self.material) return plan @dataclass(frozen=True) class Grass: tall: bool = False def capability(self): return Capability('plant.grass', ('plant',), offers=('replacement',), assumptions=('substrate',)) def negotiate(self, ctx, parameters): box = Box((0, 0, 0), (0, int(self.tall), 0)) return Contract(box, (Port('replacement', 'planting', Frame(), box, grant='replace'),), (Grant('replace', box, ('plant',), ('tree',), 2, True),), (Rule('support', ((0, -1, 0),)),), atomic_object=True) def realize(self, ctx, contract): plan = Plan() if self.tall: for y, half in enumerate(('lower', 'upper')): plan.block((0, y, 0), state_of('tall_grass', half=half)) else: plan.block((0, 0, 0), state_of('short_grass')) return plan @dataclass(frozen=True) class Tree: height: int = 10 radius: int = 3 def capability(self): return Capability('plant.conifer', ('plant', 'tree'), {'height': Domain(5, 18), 'radius': Domain(1, 4)}, assumptions=('substrate',), adaptations=('prune canopy against obstacles within accepted radius',)) def negotiate(self, ctx, parameters): h, r = parameters.get('height', self.height), parameters.get('radius', self.radius) if not 5 <= h <= 18 or not 1 <= r <= 4: raise ContractError('tree-domain', ctx.path) return Contract(Box((-r, 0, -r), (r, h, r)), rules=(Rule('support', ((0, -1, 0),)), Rule('expected', ((0, 0, 0),), data={'names': ['spruce_log']})), decisions={'height': h, 'radius': r}, reads=(Box((-r, -1, -r), (r, h, r)),)) def realize(self, ctx, contract): p = Plan() h = contract.decisions['height'] radius = contract.decisions['radius'] for y in range(h): p.block((0, y, 0), log()) for y in range(3, h + 1): if y % 3 == 0 and y != h: continue r = min(radius, max(0, (h - y + 1) // 2)) if y % 3 == 0: r = max(0, r - 1) for x in range(-r, r + 1): for z in range(-r, r + 1): if abs(x) + abs(z) > r + 1 or (x == 0 and z == 0 and y < h): continue q = ctx.world((x, y, z)) if ctx.view.domain and not ctx.view.domain.contains(q): continue if name_of(ctx.view.state(q)) == 'air': p.block((x, y, z), leaves()) return p @dataclass(frozen=True) class Wall: width: int = 9 height: int = 5 thickness: int = 1 infill: str | None = None timber: str = 'spruce' def capability(self): return Capability('wall.framed', ('wall', 'enclosure'), offers=('window', 'door'), assumptions=('floor below',), guarantees=('frame preserved', 'sealed infill'), inputs={'width': Domain(5, 64), 'height': Domain(4, 12), 'thickness': Domain(1, 3), 'frame.turn': Domain(choices=(0, 1, 2, 3))}, locked=('width', 'height', 'thickness', 'infill')) def negotiate(self, ctx, parameters): w, h, t = self.width, self.height, self.thickness if not 5 <= w <= 64 or not 4 <= h <= 12 or not 1 <= t <= 3: raise ContractError('wall-domain', ctx.path) box = Box((0, 0, 0), (w - 1, h - 1, t - 1)) install = Box((1, 0, 0), (w - 2, h - 2, t - 1)) ports = (Port('infill', 'wall-installation', Frame((1, 0, 0)), install, 20, 'install', 1, {'thickness': t, 'sill': 1, 'margin': 1}),) grants = (Grant('install', install, ('install',), ('window', 'door'), w * h * t),) boundary = tuple(box.cells()) frame = tuple((x, y, z) for x in (0, w - 1) for y in range(-1, h) for z in range(t)) return Contract(box, ports, grants, (Rule('support', frame), Rule('sealed', boundary, phase='complete')), decisions={'width': w, 'height': h, 'thickness': t}) def realize(self, ctx, contract): p = Plan() p.fill(contract.envelope, self.infill or ctx.view.style['infill']) for x in (0, self.width - 1): p.fill(Box((x, 0, 0), (x, self.height - 1, self.thickness - 1)), log(self.timber)) p.fill(Box((0, self.height - 1, 0), (self.width - 1, self.height - 1, self.thickness - 1)), log(self.timber, 'x')) return p @dataclass(frozen=True) class Window: width: int = 2 height: int = 2 shutters: bool = True glass: str = 'minecraft:glass' def capability(self): return Capability('window.shuttered' if self.shutters else 'window.lattice', ('window', 'sealed-opening'), offers=('daylight',), adaptations=('depth reveal',), guarantees=('sealed opening', 'frame margins')) def negotiate(self, ctx, parameters): if not ctx.bindings: raise ContractError('window-host', ctx.path) port = ctx.view.port(ctx.bindings[0].host, ctx.bindings[0].port) depth = port.facts['thickness'] box = Box((-1, -1, -1), (self.width, self.height - 1, depth - 1)) inner = Box((0, 0, 0), (self.width - 1, self.height - 1, depth - 1)) if not all(port.region.contains(ctx.world(q)) for q in inner.corners()): raise ContractError('window-margins', ctx.path, ctx.frame.origin, 'Opening crosses excluded framing') return Contract(box, rules=(Rule('sealed', tuple(inner.cells())),), decisions={'depth': depth}) def realize(self, ctx, contract): p = Plan() d = contract.decisions['depth'] for z in range(d): p.fill(Box((0, 0, z), (self.width - 1, self.height - 1, z)), self.glass, 'glazing') if self.shutters: from hearth.blocks import slab for x in (-1, self.width): for y in range(self.height): p.block((x, y, -1), state_of('spruce_trapdoor', facing='north', half='bottom', open='true', powered='false', waterlogged='false'), 'shutters') for x in range(self.width): p.block((x, -1, -1), slab('spruce', 'top'), 'sill') else: for x in range(self.width): p.block((x, self.height - 1, -1), state_of('spruce_trapdoor', facing='north', half='top', open='false', powered='false', waterlogged='false'), 'hood') return p @dataclass(frozen=True) class Pool: width: int = 7 depth: int = 6 def capability(self): return Capability('water.basin', ('pool', 'siteworks'), adaptations=('bounded excavation',), guarantees=('contained water',)) def negotiate(self, ctx, parameters): box = Box((0, -2, 0), (self.width - 1, 0, self.depth - 1)) water = tuple(Box((1, -1, 1), (self.width - 2, 0, self.depth - 2)).cells()) return Contract(box, rules=(Rule('pool', water),), decisions={'excavation_limit': box.volume}) def realize(self, ctx, contract): p = Plan() p.fill(contract.envelope, state_of('smooth_sandstone'), 'basin') p.fill(Box((1, -1, 1), (self.width - 2, 0, self.depth - 2)), state_of('water', level='0'), 'water') return p @dataclass(frozen=True) class Assembly: name: str envelope: Box children: tuple[Child, ...] rules: tuple[Rule, ...] = () ports: tuple[Port, ...] = () def capability(self): return Capability(self.name, ('composite',)) def negotiate(self, ctx, parameters): return Contract(self.envelope, ports=self.ports, rules=self.rules) def realize(self, ctx, contract): return Plan(children=list(self.children))
hearth/components/roofs.py · 125 行 · 原文件
# Pitched roof surfaces and open porch attachments with explicit overlap policy. from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of, stairs, slab, log, name_of from hearth.kernel import Capability, Contract, Grant, Port, Rule, Plan, Child from .interior import Light from .primitives import Window @dataclass(frozen=True) class Roof: width: int depth: int axis: str = 'z' material: str = 'deepslate_tile' steep: bool = True def capability(self): return Capability('roof.gable', ('roof', 'enclosure'), offers=('junction',), adaptations=('abut taller wall', 'merge shared eaves'), guarantees=('pitched weather skin',)) def negotiate(self, ctx, parameters): span = self.width if self.axis == 'z' else self.depth height = (span + 2) // 2 + 2 box = Box((-1, -1, -1), (self.width, height, self.depth)) return Contract(box, (Port('junction', 'roof-seam', Frame(), box, 100, 'junction'),), (Grant('junction', box, ('join',), ('roof',), box.volume),), decisions={'axis': self.axis, 'span': span, 'steep': self.steep, 'material': self.material}) def realize(self, ctx, contract): p = Plan() w, d = self.width, self.depth span = w if self.axis == 'z' else d length = d if self.axis == 'z' else w for cross in range(-1, span + 1): step = min(cross + 1, span - cross) y = step if self.steep else (step + 1) // 2 face = ('east' if cross < span / 2 else 'west') if self.axis == 'z' else ('south' if cross < span / 2 else 'north') for along in range(-1, length + 1): x, z = (cross, along) if self.axis == 'z' else (along, cross) q = ctx.world((x, y, z)) existing = name_of(ctx.view.state(q)) if existing != 'air': # Negotiated abutment is only to actual masonry/roof boundaries. continue trim = along in (-1, length) material = 'dark_oak' if trim else self.material p.block((x, y, z), stairs(material, face), 'roof-course') for end in (0, length - 1): frame = Frame((0, 0, end)) if self.axis == 'z' else Frame((end, 0, span - 1), 3) p.children.append(Child(f'gable-{end}', Gable(span, self.steep), frame=frame)) for cross in (-1, span): for along in range(length): x, z = (cross, along) if self.axis == 'z' else (along, cross) if name_of(ctx.view.state(ctx.world((x, -1, z)))) == 'air': p.block((x, -1, z), slab('spruce', 'top'), 'eave') mid = span // 2 peak = min(mid + 1, span - mid) if self.steep else (min(mid + 1, span - mid) + 1) // 2 for along in range(-1, length + 1): x, z = (mid, along) if self.axis == 'z' else (along, mid) if name_of(ctx.view.state(ctx.world((x, peak + 1, z)))) == 'air': p.block((x, peak + 1, z), slab('dark_oak'), 'ridge') for along in (-1, length): x, z = (mid, along) if self.axis == 'z' else (along, mid) if name_of(ctx.view.state(ctx.world((x, peak + 2, z)))) == 'air': p.block((x, peak + 2, z), state_of('dark_oak_fence', north='false', south='false', east='false', west='false', waterlogged='false'), 'finial') return p @dataclass(frozen=True) class Porch: width: int depth: int = 3 def capability(self): return Capability('attachment.porch', ('attachment', 'access', 'composite'), guarantees=('open sheltered access',)) def negotiate(self, ctx, parameters): center = self.width // 2 clear = tuple((x, y, z) for x in range(center - 1, center + 2) for y in (1, 2) for z in range(-self.depth, 0)) return Contract(Box((0, 0, -self.depth), (self.width - 1, 6, -1)), rules=(Rule('clear', clear),)) def realize(self, ctx, contract): p = Plan() w = self.width d = self.depth p.fill(Box((0, 0, -d), (w - 1, 0, -1)), state_of('spruce_planks'), 'deck') for x in (0, w - 1): p.fill(Box((x, 1, -d), (x, 4, -d)), log(), 'post') for z in range(-d, 0): y = 4 + (z + d) // 2 for x in range(w): p.block((x, y, z), slab('dark_oak') if z % 2 else stairs('dark_oak', 'south'), 'canopy') for x in range(w): if abs(x - w // 2) > 1: p.block((x, 1, -d), state_of('spruce_fence', north='false', south='false', east=str(x < w - 1).lower(), west=str(x > 0).lower(), waterlogged='false'), 'balustrade') p.children.append(Child('lantern', Light(), frame=Frame((1, 2, -2)))) return p @dataclass(frozen=True) class Gable: span: int steep: bool = True def capability(self): return Capability('wall.gable', ('wall', 'enclosure'), offers=('window',), adaptations=('abut existing upper wall',)) def negotiate(self, ctx, parameters): height = (self.span + 1) // 2 region = Box((1, 0, 0), (self.span - 2, height - 2, 0)) box = Box((0, -1, -1), (self.span - 1, height - 1, 0)) return Contract(box, (Port('infill', 'wall-installation', Frame((1, 0, 0)), region, 4, 'install', facts={'thickness': 1}),), (Grant('install', region, ('install',), ('window',), 30),)) def realize(self, ctx, contract): p = Plan() for x in range(self.span): step = min(x + 1, self.span - x) y = step if self.steep else (step + 1) // 2 for yy in range(y): if name_of(ctx.view.state(ctx.world((x, yy, 0)))) == 'air': p.block((x, yy, 0), log('spruce') if x in (0, self.span // 2, self.span - 1) else state_of('smooth_sandstone'), 'gable-infill') available = {w.point for w in p.writes} at = (self.span // 2 - 1, 0, 0) if self.steep and all((at[0] + x, y, 0) in available for x in range(2) for y in (0, 1)) and all(name_of(ctx.view.state(ctx.world((at[0] + x, 1, -1)))) == 'air' for x in range(2)): from hearth.kernel import Binding p.children.append(Child('window', Window(2, 2, False), frame=Frame(at), bindings=(Binding(ctx.path, 'infill'),))) return p
hearth/composition.py · 61 行 · 原文件
# High-level selection, arrangement, repetition, scattering and encapsulation. from dataclasses import dataclass from hearth.kernel import Capability, Contract, Plan, Child, ContractError, Rule from hearth.space import Box, Frame @dataclass(frozen=True) class Network: name: str envelope: Box recipe: object tags: tuple = ('composite',) rules: tuple[Rule, ...] = () def capability(self): return Capability(self.name, self.tags) def negotiate(self, ctx, parameters): return Contract(self.envelope, rules=self.rules) def realize(self, ctx, contract): return self.recipe(ctx) def encapsulate(name, envelope, recipe, tags=('composite',), rules=()): return Network(name, envelope, recipe, tags, rules) def attach(key, component, host, port, frame, verb='install', region=None): from hearth.kernel import Binding return Child(key, component, frame=frame, bindings=(Binding(host, port, verb, region),)) def arrange(components, origins, prefix='item'): components, origins = tuple(components), tuple(origins) if len(components) != len(origins): raise ValueError('One placement per component is required') return tuple(Child(f'{prefix}-{i}', c, frame=Frame(tuple(p))) for i, (c, p) in enumerate(zip(components, origins))) def repeat(component, origins, prefix='repeat'): return arrange([component for _ in origins], origins, prefix) def scatter(ctx, candidates, predicate, minimum, maximum, purpose='scatter'): candidates = sorted(set(candidates)) ctx.rng(purpose).shuffle(candidates) accepted = [] for p in candidates: if predicate(p, accepted): accepted.append(p) if len(accepted) >= maximum: break if len(accepted) < minimum: raise ContractError('scatter-minimum', ctx.path, conditions=f'Accepted {len(accepted)}, required {minimum}; finite candidate set exhausted') return tuple(accepted) def constrain(condition, rule, context, position=None, reason=''): if not condition: raise ContractError(rule, context.path, position, reason)
hearth/environment/__init__.py · 3 行 · 原文件
# Public environment operations. from .fields import Field, constant, gradient, radial, wave from .terrain import Terrain
hearth/environment/fields.py · 79 行 · 原文件
# Serializable scalar-field expressions; recognizable terrain emerges from parameters. from dataclasses import dataclass import math @dataclass(frozen=True) class Field: op: str args: tuple def __call__(self, x, z): a = self.args if self.op == 'constant': return a[0] if self.op == 'gradient': return a[0] * x + a[1] * z + a[2] if self.op == 'wave': return a[0] * math.sin(x * a[1] + a[3]) * math.cos(z * a[2] + a[3]) if self.op == 'radial': return a[3] * max(0, 1 - math.hypot(x - a[0], z - a[1]) / a[2]) if self.op == 'add': return a[0](x, z) + a[1](x, z) if self.op == 'multiply': return a[0](x, z) * a[1](x, z) if self.op == 'blend': mask = min(1, max(0, a[2](x, z))) return (1 - mask) * a[0](x, z) + mask * a[1](x, z) if self.op == 'transform': return a[0]((x - a[1]) / a[3], (z - a[2]) / a[3]) if self.op == 'clamp': return max(a[1], min(a[2], a[0](x, z))) raise ValueError(self.op) def __add__(self, other): return Field('add', (self, as_field(other))) def __mul__(self, other): return Field('multiply', (self, as_field(other))) def blend(self, other, mask): return Field('blend', (self, as_field(other), as_field(mask))) def transformed(self, dx=0, dz=0, scale=1): if scale <= 0: raise ValueError('Scale must be positive') return Field('transform', (self, dx, dz, scale)) def clamp(self, low, high): return Field('clamp', (self, low, high)) def expression(self): return {'op': self.op, 'args': [a.expression() if isinstance(a, Field) else a for a in self.args]} def as_field(value): return value if isinstance(value, Field) else constant(value) def constant(value=0): return Field('constant', (value,)) def gradient(x=0, z=0, base=0): return Field('gradient', (x, z, base)) def wave(amplitude=1, frequency_x=0.1, frequency_z=0.1, phase=0): return Field('wave', (amplitude, frequency_x, frequency_z, phase)) def radial(x, z, radius, amplitude): if radius <= 0: raise ValueError('Radius must be positive') return Field('radial', (x, z, radius, amplitude)) def from_expression(expression): """Restore only declared field operations, never execute a serialized program.""" return Field(expression['op'], tuple(from_expression(a) if isinstance(a, dict) and 'op' in a else a for a in expression['args']))
hearth/environment/terrain.py · 42 行 · 原文件
# Frozen field sampling, strata and water under scoped edit interfaces. import math from dataclasses import dataclass from hearth.space import Box, Frame from hearth.blocks import state_of from hearth.kernel import Capability, Contract, Grant, Port, Plan, Rule from .fields import Field @dataclass(frozen=True) class Terrain: area: Box field: Field water_level: int | None = None edit_limit: int = 2500 def capability(self): return Capability('terrain.field', ('environment', 'ground'), offers=('construction', 'planting'), guarantees=('frozen field inputs', 'actual 3D substrate')) def negotiate(self, ctx, parameters): ports = tuple(Port(k, k, Frame(self.area.lo), self.area, capacity=100000, grant=k) for k in ('construction', 'planting')) grants = (Grant('construction', self.area, ('excavate', 'fill', 'surface'), ('siteworks', 'path', 'pool'), self.edit_limit), Grant('planting', self.area, ('plant',), ('plant',), 0)) return Contract(self.area, ports, grants, decisions={'expression': self.field.expression(), 'water': self.water_level, 'edit_limit': self.edit_limit}) def realize(self, ctx, contract): plan = Plan() x0, bottom, z0 = self.area.lo x1, top, z1 = self.area.hi for x in range(x0, x1 + 1): for z in range(z0, z1 + 1): height = math.floor(self.field(x, z)) if not bottom <= height < top: raise ValueError(f'Terrain field exceeds negotiated vertical domain at {(x,z)}') for y in range(bottom, height + 1): material = 'stone' if y < height - 2 else ('dirt' if y < height else 'grass_block') if self.water_level is not None and height < self.water_level: material = 'gravel' if y == height else material plan.block((x, y, z), state_of(material), 'strata') if self.water_level is not None: for y in range(height + 1, self.water_level + 1): plan.block((x, y, z), state_of('water', level='0'), 'water-volume') return plan
hearth/kernel/__init__.py · 5 行 · 原文件
# Public composition kernel, independent of architectural implementations. from .contracts import Binding, Capability, Child, Choice, Component, Contract, Domain, Grant, Plan, Port, Registry, Rule, Write from .errors import ContractError, Diagnostic, SearchExhausted, ValidationError from .scene import Context, Limits, Scene from .validation import validate, validator
hearth/kernel/contracts.py · 150 行 · 原文件
# Serializable contracts, binding requests and pure candidate plans. from dataclasses import dataclass, field from typing import Any, Protocol from hearth.space import Box, Frame, Pos @dataclass(frozen=True) class Domain: minimum: float | None = None maximum: float | None = None choices: tuple = () def accepts(self, value): return (not self.choices or value in self.choices) and (self.minimum is None or value >= self.minimum) and (self.maximum is None or value <= self.maximum) @dataclass(frozen=True) class Capability: name: str tags: tuple[str, ...] parameters: dict[str, Domain] = field(default_factory=dict) offers: tuple[str, ...] = () assumptions: tuple[str, ...] = () adaptations: tuple[str, ...] = () guarantees: tuple[str, ...] = () version: str = '1' inputs: dict = field(default_factory=dict) locked: tuple[str, ...] = () @dataclass(frozen=True) class Rule: kind: str cells: tuple[Pos, ...] = () box: Box | None = None data: dict = field(default_factory=dict) phase: str = 'invariant' def transformed(self, frame): return Rule(self.kind, tuple(frame.point(p) for p in self.cells), frame.box(self.box) if self.box else None, self.data, self.phase) @dataclass(frozen=True) class Grant: key: str box: Box verbs: tuple[str, ...] tags: tuple[str, ...] = () limit: int = 100000 whole: bool = False @dataclass(frozen=True) class Port: key: str kind: str frame: Frame region: Box capacity: int = 1 grant: str | None = None alignment: int = 1 facts: dict = field(default_factory=dict) delegate: tuple[str, str] | None = None @dataclass(frozen=True) class Contract: envelope: Box ports: tuple[Port, ...] = () grants: tuple[Grant, ...] = () rules: tuple[Rule, ...] = () decisions: dict = field(default_factory=dict) reads: tuple[Box, ...] = () atomic_object: bool = False def transformed(self, frame): return Contract(frame.box(self.envelope), tuple(Port(p.key, p.kind, frame.compose(p.frame), frame.box(p.region), p.capacity, p.grant, p.alignment, p.facts, p.delegate) for p in self.ports), tuple(Grant(g.key, frame.box(g.box), g.verbs, g.tags, g.limit, g.whole) for g in self.grants), tuple(r.transformed(frame) for r in self.rules), self.decisions, tuple(frame.box(b) for b in self.reads), self.atomic_object) @dataclass(frozen=True) class Binding: host: str port: str verb: str = 'install' region: Box | None = None @dataclass(frozen=True) class Write: point: Pos state: str operation: str = 'realize' preserve_owner: bool = False nbt: dict | None = None @dataclass(frozen=True) class Child: key: str component: Any params: dict = field(default_factory=dict) frame: Frame = Frame() bindings: tuple[Binding, ...] = () seed: int | None = None @dataclass(frozen=True) class Choice: key: str candidates: tuple[Child, ...] score: Any tolerance: float = 0.5 @dataclass class Plan: writes: list[Write] = field(default_factory=list) children: list[Child] = field(default_factory=list) relations: list[tuple[str, str, str]] = field(default_factory=list) def block(self, point, state, operation='realize', **kwargs): self.writes.append(Write(tuple(point), state, operation, **kwargs)) def fill(self, box, state, operation='fill'): self.writes.extend(Write(p, state, operation) for p in box.cells()) class Component(Protocol): def capability(self) -> Capability: ... def negotiate(self, context, parameters: dict) -> Contract: ... def realize(self, context, contract: Contract) -> Plan: ... class Registry: def __init__(self): self.entries = {} def register(self, component): self.entries[component.capability().name] = component return component def select(self, *tags): return tuple(self.entries[k] for k in sorted(self.entries) if set(tags) <= set(self.entries[k].capability().tags))
hearth/kernel/errors.py · 32 行 · 原文件
# Structured, stable diagnostics for failed contracts and searches. from dataclasses import dataclass @dataclass(frozen=True) class Diagnostic: rule: str component: str position: tuple | None conditions: str def __str__(self): return f'{self.rule}: {self.component} at {self.position}: {self.conditions}' class ContractError(ValueError): def __init__(self, rule, component='/', position=None, conditions=''): self.diagnostic = Diagnostic(rule, component, position, conditions) super().__init__(str(self.diagnostic)) class ValidationError(ContractError): def __init__(self, diagnostics): self.diagnostics = diagnostics self.diagnostic = diagnostics[0] ValueError.__init__(self, '\n'.join(map(str, diagnostics[:12]))) class SearchExhausted(ContractError): pass
hearth/kernel/scene.py · 535 行 · 原文件
# Transaction kernel, automatic ownership and separate semantic/dependency graphs. import copy from dataclasses import dataclass, field, replace, is_dataclass, fields from hearth.blocks import AIR, canonical, validate_state from hearth.space import Box, Frame from hearth.randomness import Scope from .contracts import Binding, Capability, Child, Choice, Contract, Domain, Plan from .errors import ContractError, ValidationError, SearchExhausted from .view import View, ReadTrace from .validation import validate @dataclass(frozen=True) class Limits: dimension: int = 512 blocks: int = 1000000 depth: int = 40 search: int = 24 instances: int = 10000 export_volume: int = 16000000 @dataclass(frozen=True) class Cell: state: str owner: str operation: str nbt: dict | None = None shared: tuple[str, ...] = () @dataclass class Node: path: str type: str version: str parameters: dict frame: Frame scope: Scope contract: Contract parent: str | None primary: str | None = None complete: bool = True stale: bool = False bindings: tuple = () capability: Capability | None = None shared_bindings: tuple = () @dataclass(frozen=True) class Context: path: str frame: Frame scope: Scope view: View bindings: tuple[Binding, ...] limits: Limits def rng(self, purpose='plan'): return self.scope.stream(purpose) def world(self, p): return self.frame.point(p) def local(self, p): return self.frame.inverse(p) def elevation(self, x, z, maximum=None): world = self.world((x, 0, z)) cap = None if maximum is None else maximum + self.frame.origin[1] return self.view.elevation(world[0], world[2], maximum=cap) - self.frame.origin[1] def water(self, x, z): world = self.world((x, 0, z)) level = self.view.water(world[0], world[2]) return None if level is None else level - self.frame.origin[1] def state(self, point): return self.view.state(self.world(point)) class Scene: def __init__(self, seed=0, limits=None, domain=None, style=None, preferences=None): if not isinstance(seed, int): raise TypeError('Seed must be an integer') self.seed = seed self.style = dict(style or {"timber": "spruce", "infill": "minecraft:smooth_sandstone", "roof": "deepslate_tile"}) self.preferences = dict(preferences or {}) self.limits = limits or Limits() self.domain = domain self.blocks = {} self.nodes = {} self.reverse = {} self.reverse_shared = {} self.relations = set() self.members = {} self.dependencies = [] self.operations = {} self.displaced = {} self.erasures = {} self.port_uses = {} self.version = 0 self.completed = False self._recipes = {} self.events = [] @property def view(self): return View(self) def _fork(self): other = copy.copy(self) other.blocks = self.blocks.copy() other.nodes = {p: copy.copy(n) for p, n in self.nodes.items()} other.reverse = {k: set(v) for k, v in self.reverse.items()} other.reverse_shared = {k: set(v) for k, v in self.reverse_shared.items()} other.relations = set(self.relations) other.members = {k: set(v) for k, v in self.members.items()} other.dependencies = list(self.dependencies) other.operations = copy.deepcopy(self.operations) other.displaced = {k: dict(v) for k, v in self.displaced.items()} other.erasures = dict(self.erasures) other.port_uses = dict(self.port_uses) other._recipes = self._recipes.copy() other.events = list(self.events) return other def fork(self, seed=None): """Copy a frozen composition; an optional seed controls future placements only.""" result = self._fork() if seed is not None: if not isinstance(seed, int): raise TypeError('Seed must be an integer') result.seed = seed return result def _commit(self, candidate): candidate.version += 1 candidate.completed = False self.__dict__.update(candidate.__dict__) def place(self, key, component, params=None, frame=Frame(), bindings=(), seed=None, complete=True): if not isinstance(key, str) or not key or any(c in key for c in '/#'): raise ContractError('instance-key', conditions='Keys must be nonempty and exclude / and #') candidate = self._fork() path = '/' + key candidate._instantiate(path, component, params or {}, frame, tuple(bindings), None, Scope(self.seed).child(key, seed), complete) candidate._check(False) self._commit(candidate) return path def compose_choice(self, choice): trial = self._fork() trial._select_child('', choice, Frame(), Scope(self.seed)) trial._check(False) self._commit(trial) return '/' + choice.key def choose(self, key, candidates, score=lambda scene, path: 0): accepted, failed = [], [] for index, child in enumerate(candidates): if index >= self.limits.search: break trial = self._fork() try: path = trial.place(key, child.component, child.params, child.frame, child.bindings, child.seed) accepted.append((score(trial, path), index, trial, path)) except ContractError as exc: failed.append(str(exc)) if not accepted: raise SearchExhausted('search-budget', '/' + key, conditions=f'No validated candidate within budget {self.limits.search}; failures={failed}') accepted.sort(key=lambda item: (item[0], item[1])) best_score = accepted[0][0] best = [c for c in accepted if c[0] <= best_score + 0.1] chosen = Scope(self.seed).child(key).choose(best, 'alternatives') self._commit(chosen[2]) self.events.append({'kind': 'search', 'key': key, 'accepted': len(accepted), 'rejected': len(failed), 'failures': failed}) return chosen[3] def _instantiate(self, path, component, params, frame, bindings, parent, scope, complete=True): if path in self.nodes: raise ContractError('duplicate-instance', path) if len(self.nodes) >= self.limits.instances: raise ContractError('instance-budget', path) if len(path.split('/')) > self.limits.depth: raise ContractError('recursion-budget', path) cap = component.capability() for key, value in params.items(): if key not in cap.parameters or not cap.parameters[key].accepts(value): raise ContractError('parameter-domain', path, conditions=f'{key}={value!r}') for key, domain in cap.inputs.items(): if not isinstance(domain, Domain): continue value = frame if key.startswith('frame.') else component parts = key.split('.')[1:] if key.startswith('frame.') else key.split('.') for part in parts: if part.startswith('_') or not hasattr(value, part): raise ContractError('capability-input', path, conditions=key) value = getattr(value, part) if not domain.accepts(value): raise ContractError('input-domain', path, conditions=f'{key}={value!r}') trace = ReadTrace() ctx = Context(path, frame, scope, View(self, trace), bindings, self.limits) local = component.negotiate(ctx, dict(params)) contract = local.transformed(frame) if max(contract.envelope.size) > self.limits.dimension: raise ContractError('dimension-budget', path) if parent and not all(self.nodes[parent].contract.envelope.contains(p) for p in contract.envelope.corners()): raise ContractError('child-envelope', path, contract.envelope.lo, f'Exceeds accepted parent {parent}') self.nodes[path] = Node(path, cap.name, cap.version, {"construction": describe_inputs(component), "arguments": dict(params)}, frame, scope, contract, parent, complete=False, bindings=bindings, capability=cap) self.displaced[path] = {} self.reverse[path] = set() self._recipes[path] = (component, params, frame, bindings, parent, scope, complete) if parent: self.relations.add((path, 'contained_by', parent)) self.members.setdefault(parent, set()).add(path) grants = [] for binding in bindings: if binding.host not in self.nodes: raise ContractError('missing-host', path, conditions=binding.host) effective_host, port = self.view.resolved_port(binding.host, binding.port) host = self.nodes[effective_host] use_key = (binding.host, binding.port) if self.port_uses.get(use_key, 0) >= port.capacity: raise ContractError('port-capacity', path, port.frame.origin, binding.port) self.port_uses[use_key] = self.port_uses.get(use_key, 0) + 1 if binding.verb == 'install': if not port.region.contains(frame.origin): raise ContractError('port-alignment', path, frame.origin, 'Origin outside installation region') if port.frame.inverse(frame.origin)[0] % port.alignment or frame.turn % 4 != port.frame.turn % 4: raise ContractError('port-alignment', path, frame.origin, 'Outside facade bay grid') grant = next((g for g in host.contract.grants if g.key == port.grant), None) if grant: if binding.verb not in grant.verbs or (grant.tags and not set(cap.tags).intersection(grant.tags)): raise ContractError('permission-kind', path, frame.origin, f'{cap.tags} cannot {binding.verb} {binding.host}') grants.append((Binding(effective_host, port.key, binding.verb, binding.region), grant)) elif binding.verb != 'connect': raise ContractError('no-write-grant', path) kind = 'attached_to' if binding.verb == 'install' else ('connected_to' if binding.verb == 'connect' else 'supported_by') self.relations.add((path, kind, binding.host)) if kind == 'attached_to': self.members.setdefault(binding.host, set()).add(path) if kind == 'attached_to' and self.nodes[path].primary is None: self.nodes[path].primary = binding.host self.dependencies.append({'consumer': path, 'source': binding.host, 'version': self.version, 'region': binding.region or port.region.intersection(contract.envelope.expand(1)) or contract.envelope, 'reason': binding.verb}) for region in contract.reads: self.dependencies.append({'consumer': path, 'source': 'environment', 'version': self.version, 'region': region, 'reason': 'spatial-query'}) plan = component.realize(ctx, local) if trace.bounds: self.dependencies.append({'consumer': path, 'source': 'environment', 'version': self.version, 'region': trace.bounds, 'reason': 'observed-spatial-input'}) for source, region in sorted(trace.sources.items()): if source != path: self.dependencies.append({'consumer': path, 'source': source, 'version': self.version, 'region': region, 'reason': 'observed-interface-input'}) if not isinstance(plan, Plan): raise TypeError('Components return Plan effect sets') existing_consumers = set(self.nodes) - {path} final_writes = {} for write in plan.writes: p = frame.point(write.point) final_writes[p] = write protected_rules = [(n.path, r.box) for n in self.nodes.values() for r in n.contract.rules if r.kind == "protected" and r.box] retired = set() counts = {} for p, write in final_writes.items(): if not contract.envelope.contains(p): raise ContractError('envelope', path, p, 'Realization exceeds negotiated bounds') for protector, region in protected_rules: if region.contains(p) and protector != path: raise ContractError('protected-region', path, p, 'Immutable region held by ' + protector) old = self.blocks.get(p) if old and old.shared and not write.preserve_owner: raise ContractError('shared-consumer', path, p, 'Shared support requires explicit consumer rebinding') if old and write.preserve_owner and old.state.split('[')[0] != write.state.split('[')[0]: raise ContractError('property-update', path, p, 'Property adjustment must retain block type') if old and old.owner != path: authorization = next(((b, g) for b, g in grants if b.host == old.owner and g.box.contains(p) and (b.region is None or b.region.contains(p))), None) if authorization is None: raise ContractError('write-authority', path, p, f'Owned by {old.owner}; no scoped grant') binding, grant = authorization count_key = (binding.host, grant.key) counts[count_key] = counts.get(count_key, 0) + 1 if counts[count_key] > grant.limit: raise ContractError('edit-limit', path, p, f'Limit {grant.limit}') if self.nodes[old.owner].contract.atomic_object and not write.preserve_owner: if not grant.whole or not self.reverse[old.owner].issubset(final_writes): raise ContractError('whole-object', path, p, f'Partial replacement of {old.owner}') retired.add(old.owner) if old and old.owner != path: self.displaced[path].setdefault(p, old) if old: self.reverse[old.owner].discard(p) try: world_state = frame.state(write.state) validate_state(world_state) except ValueError as exc: raise ContractError('blockstate', path, p, str(exc)) from exc opid = path + '#' + write.operation operation = self.operations.setdefault(opid, {'component': path, 'name': write.operation, 'writes': 0, 'replaced': set()}) operation['writes'] += 1 if old: operation['replaced'].add(old.owner) if world_state == AIR: self.blocks.pop(p, None) self.erasures[p] = path else: self.erasures.pop(p, None) owner = old.owner if old and write.preserve_owner else path self.blocks[p] = Cell(canonical(world_state), owner, opid, write.nbt, old.shared if old and write.preserve_owner else ()) self.reverse[owner].add(p) for dependency in self.dependencies: consumer = dependency["consumer"] if consumer in existing_consumers and consumer != parent and not path.startswith(consumer + "/") and any(dependency["region"].contains(p) for p in final_writes): # Binding consumers remain valid only if their actual invariants hold. self.events.append({"kind": "revalidated-input", "consumer": consumer, "cause": path, "version": self.version}) for old in retired: self._retire(old) for child in plan.children: if isinstance(child, Choice): self._select_child(path, child, frame, scope) continue if not child.key or any(c in child.key for c in '/#'): raise ContractError('instance-key', path, conditions=child.key) self._instantiate(path + '/' + child.key, child.component, child.params, frame.compose(child.frame), child.bindings, path, scope.child(child.key, child.seed)) for port in contract.ports: if port.delegate: target, actual = self.view.resolved_port(path, port.key) if actual.frame != port.frame or actual.region != port.region or actual.kind != port.kind: raise ContractError('forwarded-interface', path, port.frame.origin, 'Realized child changed the negotiated public interface') self.relations.add((path, 'exposes', target)) for source, kind, target in plan.relations: if source not in self.nodes or target not in self.nodes: raise ContractError("dangling-relation", path, conditions=f"{source} {kind} {target}") self.relations.add((source, kind, target)) self.nodes[path].complete = complete if len(self.blocks) > self.limits.blocks: raise ContractError('block-budget', path) def _select_child(self, parent, choice, frame, scope): accepted = [] rejected = [] path = parent + '/' + choice.key for i, option in enumerate(choice.candidates[:self.limits.search]): trial = self._fork() try: trial._instantiate(path, option.component, option.params, frame.compose(option.frame), option.bindings, parent or None, scope.child(choice.key, option.seed).child(f'alternative-{i}')) trial._check(False, completed_scope=path) accepted.append((choice.score(trial.view, path), i, trial)) except ContractError as exc: rejected.append(exc.diagnostic) if not accepted: rules = {d.rule for d in rejected} if len(rules) == 1 and len(choice.candidates) <= self.limits.search: error = ContractError(next(iter(rules)), path, conditions='All declared alternatives violate the same condition: ' + str(rejected[0])) else: error = SearchExhausted('search-budget', path, conditions=str(rejected)) error.attempts = len(rejected) error.candidates = [d.__dict__ for d in rejected] raise error accepted.sort(key=lambda item: (item[0], item[1])) feasible = [a for a in accepted if a[0] <= accepted[0][0] + choice.tolerance] chosen = scope.child(choice.key).choose(feasible, 'adaptation-selection') self.__dict__.update(chosen[2].__dict__) self.events.append({'kind': 'candidate-selection', 'component': path, 'attempts': len(accepted) + len(rejected), 'accepted': len(accepted), 'rejected': [d.__dict__ for d in rejected], 'scores': [(a[1], round(a[0], 4)) for a in accepted], 'chosen': chosen[1]}) def _retire(self, path): if self.reverse.get(path): raise ContractError('whole-object', path, conditions='Cannot retire occupied instance') node = self.nodes.get(path) if node: for binding in node.bindings: key = (binding.host, binding.port) self.port_uses[key] = max(0, self.port_uses.get(key, 0) - 1) if node: for shared_host, shared_port, point in node.shared_bindings: key = (shared_host, shared_port) self.port_uses[key] = max(0, self.port_uses.get(key, 0) - 1) self.members.pop(path, None) for children in self.members.values(): children.discard(path) self.nodes.pop(path, None) self.reverse.pop(path, None) self._recipes.pop(path, None) self.relations = {r for r in self.relations if r[0] != path and r[2] != path} self.dependencies = [d for d in self.dependencies if d['consumer'] != path and d['source'] != path] self.port_uses = {k: v for k, v in self.port_uses.items() if k[0] != path} def _check(self, final, completed_scope=None): errors = validate(self, final, completed_scope) if errors: raise ValidationError(errors) def finalize(self): self._check(True) self.completed = True return self def finish_scope(self, path): trial = self._fork() trial.nodes[path].complete = True trial._check(True) self._commit(trial) def descendants(self, path): result = set() pending = [path] while pending: current = pending.pop() if current in result: continue result.add(current) pending.extend(sorted(self.members.get(current, ()))) return frozenset(result) def cells(self, path, descendants=False, shared=False): paths = [path] if descendants: paths = list(self.descendants(path)) return frozenset(p for k in paths for p in (self.reverse.get(k, set()) | (self.reverse_shared.get(k, set()) if shared else set()))) def inspect(self, point): point = tuple(point) record = self.blocks.get(point) if not record: return {'position': point, 'state': AIR, 'instance': None, 'chain': [], 'related': [], 'operation': None} chain, seen = [], set() path = record.owner while path and path not in seen: seen.add(path) node = self.nodes[path] chain.append({'id': path, 'type': node.type}) path = node.primary or node.parent related = sorted(r for r in self.relations if r[0] in seen or r[2] in seen) return {'position': point, 'state': record.state, 'instance': record.owner, 'chain': chain, 'related': related, 'operation': self.operations.get(record.operation), 'shared': record.shared, 'nbt': record.nbt} def share(self, point, participant, host, port): trial = self._fork() p = tuple(point) record = trial.blocks[p] offered = trial.view.port(host, port) if record.owner != host or offered.kind != 'shared-support' or not offered.region.contains(p) or participant not in trial.nodes: raise ContractError('shared-authority', participant, p) if participant in record.shared: return use_key = (host, port) if trial.port_uses.get(use_key, 0) >= offered.capacity: raise ContractError('port-capacity', participant, p) trial.port_uses[use_key] = trial.port_uses.get(use_key, 0) + 1 trial.reverse_shared.setdefault(participant, set()).add(p) from .contracts import Rule node = trial.nodes[participant] node.shared_bindings = node.shared_bindings + ((host, port, p),) node.contract = replace(node.contract, rules=node.contract.rules + (Rule('support', (p,)),)) trial.blocks[p] = replace(record, shared=tuple(sorted(set(record.shared + (participant,))))) trial.relations.add((participant, 'shares_support', host)) trial._check(False) self._commit(trial) def remove(self, path): trial = self._fork() trial._remove_branch(path) trial._check(False) self._commit(trial) def _remove_branch(self, path): paths = {k for k in self.nodes if k == path or k.startswith(path + '/')} affected = set() for k in sorted(paths, reverse=True): current = set(self.reverse[k]) | set(self.displaced.get(k, {})) for p in current: record = self.blocks.get(p) if record is None and self.erasures.get(p) not in paths: continue if record is not None and record.owner not in paths and self.operations[record.operation]['component'] not in paths: continue affected.add(p) if record is not None: self.reverse[record.owner].discard(p) self.erasures.pop(p, None) previous = self.displaced.get(k, {}).get(p) if previous and previous.owner in self.nodes and previous.owner not in paths: self.blocks[p] = previous self.reverse[previous.owner].add(p) else: self.blocks.pop(p, None) self.displaced.pop(k, None) for d in self.dependencies: if d['consumer'] not in paths and (d['source'] in paths or any(d['region'].contains(p) for p in affected)): self.nodes[d['consumer']].stale = True for k in sorted(paths, reverse=True): self.reverse_shared.pop(k, None) self.reverse[k].clear() self._retire(k) self.relations = {r for r in self.relations if r[0] in self.nodes and r[2] in self.nodes} for p, record in list(self.blocks.items()): if set(record.shared).intersection(paths): self.blocks[p] = replace(record, shared=tuple(s for s in record.shared if s not in paths)) def regenerate(self, path, component=None, params=None, dependents=(), seed=None): trial = self._fork() targets = [path] + list(dependents) recipes = {} for p in targets: if p in trial._recipes: recipes[p] = trial._recipes[p] elif p == path and component is not None: n = trial.nodes[p] recipes[p] = (component, n.parameters.get('arguments', {}), n.frame, n.bindings, n.parent, n.scope, n.complete) else: raise ContractError('replay-implementation', p, conditions='Reloaded branch needs an explicitly supplied component implementation') for p in targets: trial._remove_branch(p) for p in targets: comp, oldparams, frame, bindings, parent, scope, complete = recipes[p] if p == path and seed is not None: scope = scope.child('override', seed) trial._instantiate(p, component if p == path and component is not None else comp, params if p == path and params is not None else oldparams, frame, bindings, parent, scope, complete) trial._check(True) self._commit(trial) self.events.append({'kind': 'regenerated', 'targets': targets}) def describe_inputs(value): """Record declared public inputs without concrete-component dispatch.""" if value is None or isinstance(value, (str, int, float, bool)): return value if isinstance(value, (list, tuple)): return [describe_inputs(v) for v in value] if isinstance(value, dict): return {str(k): describe_inputs(v) for k, v in value.items()} if is_dataclass(value): return {'type': type(value).__module__ + '.' + type(value).__qualname__, 'inputs': {f.name: describe_inputs(getattr(value, f.name)) for f in fields(value)}} if callable(value): return {'program': value.__module__ + '.' + value.__qualname__} return {'type': type(value).__module__ + '.' + type(value).__qualname__, 'inputs': {k: describe_inputs(v) for k, v in vars(value).items() if not k.startswith('_')}}
hearth/kernel/validation.py · 220 行 · 原文件
# Extensible actual-geometry validators and bounded player movement. from collections import deque from hearth.blocks import AIR, LIGHTS, name_of, parse, passable, solid, validate_state from hearth.kernel.errors import Diagnostic from hearth.space import Box VALIDATORS = {} def validator(name): def register(fn): VALIDATORS[name] = fn return fn return register def state(scene, p): record = scene.blocks.get(tuple(p)) return record.state if record else AIR def fail(kind, node, point, message): return Diagnostic(kind, node.path, point, message) @validator('protected') def protected(scene, node, rule): from hearth.blocks import blockstates_equivalent for p, expected in zip(rule.cells, rule.data['states']): if not blockstates_equivalent(state(scene, p), expected): yield fail('protected-region', node, p, 'Preserved geometry changed') @validator('support') def support(scene, node, rule): for p in rule.cells: if not solid(state(scene, p)): yield fail('support', node, p, 'Required actual load-bearing cell is missing') @validator('clear') def clear(scene, node, rule): for p in rule.cells: if not passable(state(scene, p)): yield fail('clearance', node, p, 'Protected player headroom is obstructed') @validator('sealed') def sealed(scene, node, rule): for p in rule.cells: if name_of(state(scene, p)) in ('air', 'water'): yield fail('enclosure', node, p, 'Enclosed boundary has a gap') @validator('expected') def expected(scene, node, rule): allowed = set(rule.data['names']) for p in rule.cells: if name_of(state(scene, p)) not in allowed: yield fail('expected-geometry', node, p, f'Expected one of {sorted(allowed)}') @validator('pool') def pool(scene, node, rule): for x, y, z in rule.cells: if name_of(state(scene, (x, y, z))) != 'water': yield fail('pool-water', node, (x, y, z), 'Pool water missing') for q in ((x, y - 1, z), (x - 1, y, z), (x + 1, y, z), (x, y, z - 1), (x, y, z + 1)): if not solid(state(scene, q)) and name_of(state(scene, q)) != 'water': yield fail('pool-containment', node, q, 'Basin leaks') def standable(scene, p): x, y, z = p return passable(state(scene, p)) and passable(state(scene, (x, y + 1, z))) and solid(state(scene, (x, y - 1, z))) def reachable(scene, start, box): if not standable(scene, start): return set() reached = {start} queue = deque([start]) while queue: x, y, z = queue.popleft() for dx, dz in ((1, 0), (-1, 0), (0, 1), (0, -1)): for dy in (0, 1, -1): q = (x + dx, y + dy, z + dz) if q not in reached and box.contains(q) and standable(scene, q): # Ascending requires clearance above the lower step as well. high = (x, y + 2, z) if dy == 1 else (q[0], q[1] + 2, q[2]) if dy and not passable(state(scene, high)): continue reached.add(q) queue.append(q) return reached @validator('route') def route(scene, node, rule): if not rule.cells or rule.box is None: yield fail('route-contract', node, None, 'Route needs start, targets and bounded search region') return reached = reachable(scene, rule.cells[0], rule.box) for p in rule.cells: if p not in reached: yield fail('reachability', node, p, 'No walkable route with two blocks of headroom from entrance') @validator('light') def light(scene, node, rule): sources = [p for p in rule.box.cells() if name_of(state(scene, p)) in LIGHTS] if not sources: yield fail('lighting', node, rule.box.lo, 'Completed room has no actual light source') return # Propagate actual sources through transmissive cells, with one unit attenuation. levels = {p: LIGHTS[name_of(state(scene, p))] for p in sources} queue = deque(sources) domain = rule.box.expand(1) while queue: p = queue.popleft() level = levels[p] - 1 if level < rule.data.get('minimum', 1): continue for dx, dy, dz in ((1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1)): q = (p[0] + dx, p[1] + dy, p[2] + dz) if not domain.contains(q) or levels.get(q, 0) >= level: continue material = state(scene, q) if passable(material) or 'glass' in name_of(material) or name_of(material) == 'chain': levels[q] = level queue.append(q) for p in rule.cells: if levels.get(p, 0) < rule.data.get('minimum', 1): yield fail('lighting', node, p, 'Actual source attenuation/occlusion leaves required location dark') @validator('furnishing') def furnishing(scene, node, rule): names = {name_of(state(scene, p)) for p in rule.box.cells()} for group in rule.data['groups']: if not names.intersection(group): yield fail('furnishing', node, rule.box.lo, f'Missing functional furnishing: {group}') def validate(scene, final=False, completed_scope=None): diagnostics = [] for p, record in scene.blocks.items(): try: validate_state(record.state) except ValueError as exc: diagnostics.append(Diagnostic('blockstate', record.owner, p, str(exc))) continue if p not in scene.reverse.get(record.owner, set()): diagnostics.append(Diagnostic('reverse-index', record.owner, p, 'Current cell absent from reverse index')) if record.owner not in scene.nodes: diagnostics.append(Diagnostic('ownership', record.owner, p, 'Owner missing')) if record.nbt is not None: if record.nbt.get('id') != 'minecraft:' + name_of(record.state): diagnostics.append(Diagnostic('block-entity', record.owner, p, 'Block entity type mismatches actual block')) slots = set() for item in record.nbt.get('Items', []): if not 0 <= item.get('Slot', -1) < 27 or item['Slot'] in slots or not 1 <= item.get('count', 0) <= 64 or not item.get('id', '').startswith('minecraft:'): diagnostics.append(Diagnostic('inventory', record.owner, p, 'Invalid or duplicate inventory slot/item count')) slots.add(item.get('Slot')) name, props = parse(record.state) if name.endswith('_door') and not name.endswith('_trapdoor'): dy = 1 if props.get('half') == 'lower' else -1 q = (p[0], p[1] + dy, p[2]) other, op = parse(state(scene, q)) if other != name or op.get('half') == props.get('half') or any(op.get(k) != props.get(k) for k in ('facing', 'hinge', 'open', 'powered')): diagnostics.append(Diagnostic('door-pair', record.owner, p, 'Door halves absent or inconsistent')) if name.endswith('_bed'): direction = {'north': (0, -1), 'south': (0, 1), 'east': (1, 0), 'west': (-1, 0)}[props['facing']] sign = 1 if props['part'] == 'foot' else -1 q = (p[0] + direction[0] * sign, p[1], p[2] + direction[1] * sign) other, op = parse(state(scene, q)) if name != other or op.get('part') == props['part'] or op.get('facing') != props['facing']: diagnostics.append(Diagnostic('bed-pair', record.owner, p, 'Bed halves inconsistent')) if name_of(record.state) in ('sunflower', 'rose_bush', 'peony', 'lilac', 'tall_grass', 'large_fern'): dy = 1 if props.get('half') == 'lower' else -1 q = (p[0], p[1] + dy, p[2]) other, op = parse(state(scene, q)) if other != name or op.get('half') == props.get('half'): diagnostics.append(Diagnostic('plant-pair', record.owner, p, 'Tall plant halves inconsistent')) for owner, points in scene.reverse.items(): for p in points: if p not in scene.blocks or scene.blocks[p].owner != owner: diagnostics.append(Diagnostic('reverse-index', owner, p, 'Obsolete current membership')) for node in scene.nodes.values(): for port in node.contract.ports: if port.delegate and (node.complete or final): try: _, actual = scene.view.resolved_port(node.path, port.key) if (port.frame, port.region, port.kind) != (actual.frame, actual.region, actual.kind): diagnostics.append(Diagnostic('forwarded-interface', node.path, port.frame.origin, 'Child interface changed without parent renegotiation')) except (KeyError, ValueError): diagnostics.append(Diagnostic('forwarded-interface', node.path, port.frame.origin, 'Delegated port missing')) for parent in (node.parent, node.primary): if parent is not None and parent not in scene.nodes: diagnostics.append(Diagnostic('structure-graph', node.path, None, 'Current structural parent missing: ' + parent)) if final and (not node.complete or node.stale): diagnostics.append(Diagnostic('unfinished', node.path, None, 'Scope unfinished or dependent inputs stale')) for rule in node.contract.rules: if rule.phase == 'complete' and not final: scope = node closed = True while scope: closed = closed and scope.complete scope = scene.nodes.get(scope.parent) if completed_scope and (node.path == completed_scope or node.path.startswith(completed_scope + '/')): closed = node.complete if not closed: continue if rule.kind not in VALIDATORS: diagnostics.append(Diagnostic('unknown-validator', node.path, None, rule.kind)) else: diagnostics.extend(VALIDATORS[rule.kind](scene, node, rule)) return diagnostics
hearth/kernel/view.py · 166 行 · 原文件
# Read-only, domain-aware environmental observations. from dataclasses import dataclass from types import MappingProxyType import copy from hearth.blocks import AIR, solid, name_of, passable from hearth.kernel.errors import ContractError from hearth.space import Box @dataclass(frozen=True) class Observation: version: int region: Box elevation: int water: int | None material: str slope: int support_depth: int class ReadTrace: """Coalesce actual environmental reads and interface dependencies for one candidate.""" def __init__(self): self.low = None self.high = None self.sources = {} def point(self, p): if self.low is None: self.low = list(p) self.high = list(p) else: for i in range(3): self.low[i] = min(self.low[i], p[i]) self.high[i] = max(self.high[i], p[i]) def region(self, box): self.point(box.lo) self.point(box.hi) @property def bounds(self): return None if self.low is None else Box(tuple(self.low), tuple(self.high)) class View: def __init__(self, scene, trace=None): self.__scene = scene self.__trace = trace @property def version(self): return self.__scene.version @property def domain(self): return self.__scene.domain @property def style(self): return MappingProxyType(self.__scene.style) def preference(self, name, point): if self.domain and not self.domain.contains(point): raise ContractError("unknown-space", position=point) field = self.__scene.preferences.get(name) return None if field is None else field(point[0], point[2]) def state(self, p): p = tuple(p) if self.__trace: self.__trace.point(p) if self.domain and not self.domain.contains(p): raise ContractError('unknown-space', position=p, conditions='Outside explicit environment domain') record = self.__scene.blocks.get(p) return record.state if record else AIR def owner(self, p): if self.__trace: self.__trace.point(p) record = self.__scene.blocks.get(tuple(p)) return record.owner if record else None def supports(self, p): return solid(self.state(p)) def clear(self, box): return all(passable(self.state(p)) for p in box.cells()) def elevation(self, x, z, maximum=None): if self.domain is None: raise ContractError('unknown-space', position=(x, 0, z), conditions='No environmental domain') for y in range(self.domain.hi[1] if maximum is None else min(maximum, self.domain.hi[1]), self.domain.lo[1] - 1, -1): if self.supports((x, y, z)): return y raise ContractError('missing-substrate', position=(x, self.domain.lo[1], z), conditions='No actual solid substrate') def water(self, x, z): if self.domain is None: raise ContractError('unknown-space', position=(x, 0, z)) for y in range(self.domain.hi[1], self.domain.lo[1] - 1, -1): if name_of(self.state((x, y, z))) == 'water': return y return None def sample(self, x, z): y = self.elevation(x, z) heights = [self.elevation(x + dx, z + dz) for dx, dz in ((1, 0), (-1, 0), (0, 1), (0, -1)) if self.domain.contains((x + dx, y, z + dz))] depth = 0 for yy in range(y, self.domain.lo[1] - 1, -1): if not self.supports((x, yy, z)): break depth += 1 return Observation(self.version, Box((x, self.domain.lo[1], z), (x, self.domain.hi[1], z)), y, self.water(x, z), self.state((x, y, z)), max([abs(h - y) for h in heights] or [0]), depth) def port(self, host, key): node = self.__scene.nodes[host] for p in node.contract.ports: if p.key == key: if self.__trace: self.__trace.sources[host] = p.region return copy.deepcopy(p) raise ContractError('missing-port', host, conditions=key) def cost(self, path, tag=None): paths = [key for key, n in self.__scene.nodes.items() if (key == path or key.startswith(path + '/')) and (tag is None or (n.capability and tag in n.capability.tags))] occupied = sum(len(self.__scene.reverse.get(key, ())) for key in paths) replaced = sum(len(self.__scene.displaced.get(key, ())) for key in paths) return {'occupied': occupied, 'replaced': replaced, 'instances': len(paths)} def offers(self, host, kind=None): return tuple(copy.deepcopy(p) for p in self.__scene.nodes[host].contract.ports if kind is None or p.kind == kind) def capability(self, host): return copy.deepcopy(self.__scene.nodes[host].capability) def resolved_port(self, host, key): seen = set() while True: if (host, key) in seen: raise ContractError('port-cycle', host, conditions=key) seen.add((host, key)) port = self.port(host, key) if not port.delegate: return host, port child, key = port.delegate host = host + '/' + child def contract(self, path): if self.__trace: self.__trace.sources[path] = self.__scene.nodes[path].contract.envelope return copy.deepcopy(self.__scene.nodes[path].contract) def protected(self, box): if self.__trace: self.__trace.region(box) return any(r.kind in ('clear', 'protected') and any(box.contains(p) for p in r.cells) for n in self.__scene.nodes.values() for r in n.contract.rules) def obstacle_distance(self, p, radius=8): best = radius + 1 for q in Box(tuple(v - radius for v in p), tuple(v + radius for v in p)).cells(): if q in self.__scene.blocks and not passable(self.__scene.blocks[q].state): best = min(best, max(abs(a - b) for a, b in zip(p, q))) return best
hearth/persistence.py · 194 行 · 原文件
# One-region Litematica transport paired with verified structural records. import hashlib import json import sys from dataclasses import fields, is_dataclass from pathlib import Path from . import __version__ from .blocks import canonical, AIR from .space import Box, Frame from .randomness import Scope from .kernel import contracts from .kernel.scene import Scene, Node, Cell, Limits from .kernel.errors import ContractError FORMAT_VERSION = 1 TYPES = {c.__name__: c for c in (Box, Frame, Scope, Node, Cell, Limits, contracts.Contract, contracts.Rule, contracts.Port, contracts.Grant, contracts.Binding, contracts.Capability, contracts.Domain)} def encode(value): if is_dataclass(value): return {'$type': type(value).__name__, **{f.name: encode(getattr(value, f.name)) for f in fields(value)}} if isinstance(value, tuple): return {'$tuple': [encode(v) for v in value]} if isinstance(value, set): return {'$set': [encode(v) for v in sorted(value)]} if isinstance(value, dict): return {k: encode(v) for k, v in value.items()} if isinstance(value, list): return [encode(v) for v in value] return value def decode(value): if isinstance(value, list): return [decode(v) for v in value] if isinstance(value, dict): if '$tuple' in value: return tuple(decode(v) for v in value['$tuple']) if '$set' in value: return set(decode(v) for v in value['$set']) if '$type' in value: return TYPES[value['$type']](**{k: decode(v) for k, v in value.items() if k != '$type'}) return {k: decode(v) for k, v in value.items()} return value def semantic_digest(scene): digest = hashlib.sha256() for p, c in sorted(scene.blocks.items()): digest.update(json.dumps([p, canonical(c.state), c.nbt], sort_keys=True, separators=(',', ':')).encode()) return digest.hexdigest() def companion_path(path: Path): return path.with_suffix(path.suffix + '.structure.json') def _mcio(): try: import mcio except ImportError: sys.path.insert(0, '/work/generator/MCIO') from mcio.sketch import LitematicCanvas from mcio.schematic import load_schematic from mcio.nbt import tag from mcio.nbt.nbt import File return LitematicCanvas, load_schematic, tag, File def _to_nbt(value, tag, key=''): if isinstance(value, dict): return tag.Compound({k: _to_nbt(v, tag, k) for k, v in value.items()}) if isinstance(value, list): if not value: return tag.List[tag.Compound]([]) items = [_to_nbt(v, tag) for v in value] return tag.List[type(items[0])](items) if isinstance(value, str): return tag.String(value) if isinstance(value, int): return tag.Byte(value) if key == 'Slot' else tag.Int(value) raise TypeError(type(value)) def _plain(value): if isinstance(value, dict): return {str(k): _plain(v) for k, v in value.items()} if isinstance(value, (list, tuple)): return [_plain(v) for v in value] if isinstance(value, str): return str(value) return int(value) def export_scene(scene, path: Path, verify=True): path = Path(path) scene.finalize() bounds = Box.enclosing(scene.blocks) if max(bounds.size) > scene.limits.dimension: raise ContractError('export-bounds', conditions=str(bounds)) if bounds.volume > scene.limits.export_volume: raise ContractError('export-volume', conditions=f'{bounds.volume} > {scene.limits.export_volume}') canvas_type, _, tag, nbtfile = _mcio() sx, sy, sz = bounds.size canvas = canvas_type((sy, sz, sx)) offset = bounds.lo block_entities = [] for p, cell in sorted(scene.blocks.items()): x, y, z = tuple(v - o for v, o in zip(p, offset)) canvas.block((y, z, x), cell.state) if cell.nbt is not None: block_entities.append(_to_nbt({**cell.nbt, 'x': x, 'y': y, 'z': z}, tag)) schematic = canvas.to_litematica(name='Hearth', author='Hearth procedural library', description='Contract-composed settlement; structural identity in companion JSON', minecraft_data_version=3955) nbt = schematic.write_to_nbt() nbt['Regions']['Hearth']['TileEntities'] = tag.List[tag.Compound](block_entities) nbt['Regions']['Hearth']['Entities'] = tag.List[tag.Compound]([]) path.parent.mkdir(parents=True, exist_ok=True) temporary = path.with_suffix(path.suffix + '.tmp') nbtfile(nbt).save(temporary) owners = sorted(scene.nodes) operations = sorted(scene.operations) owner_id, op_id = {v: i for i, v in enumerate(owners)}, {v: i for i, v in enumerate(operations)} data = {'format': 'hearth.structure', 'version': FORMAT_VERSION, 'implementation': __version__, 'minecraft_data_version': 3955, 'digest': semantic_digest(scene), 'offset': offset, 'size': bounds.size, 'seed': scene.seed, 'style': scene.style, 'preferences': {k: v.expression() for k, v in scene.preferences.items()}, 'domain': encode(scene.domain), 'limits': encode(scene.limits), 'scene_version': scene.version, 'nodes': encode(scene.nodes), 'relations': encode(scene.relations), 'dependencies': encode(scene.dependencies), 'operations': encode(scene.operations), 'erasures': [[list(p), owner] for p, owner in sorted(scene.erasures.items())], 'displaced': {k: [[list(p), encode(c)] for p, c in sorted(v.items())] for k, v in scene.displaced.items()}, 'events': encode(scene.events), 'port_uses': [[*k, v] for k, v in sorted(scene.port_uses.items())], 'owners': owners, 'operation_ids': operations, 'cells': [[*p, owner_id[c.owner], op_id[c.operation], list(c.shared)] for p, c in sorted(scene.blocks.items())]} target = companion_path(path) temporary_meta = target.with_suffix('.json.tmp') temporary_meta.write_text(json.dumps(data, sort_keys=True, separators=(',', ':'))) temporary.replace(path) temporary_meta.replace(target) if verify: restored = load_scene(path) if semantic_digest(restored) != semantic_digest(scene): raise ContractError('roundtrip', conditions='Semantic geometry differs') return path def load_scene(path: Path): path = Path(path) meta = companion_path(path) if not meta.exists(): raise ContractError('untrusted-structure', conditions='Missing companion; geometry cannot reconstruct semantic identity') data = json.loads(meta.read_text()) if data.get('format') != 'hearth.structure' or data.get('version') != FORMAT_VERSION: raise ContractError('untrusted-structure', conditions='Unknown companion format/version') _, load, _, nbtfile = _mcio() loaded = load(path) nbt = nbtfile.load_regardless_of_gzipped(filename=path) regions = nbt['Regions'] if len(regions) != 1 or int(nbt['MinecraftDataVersion']) != 3955: raise ContractError('transport', conditions='Require one Java 1.21.1 region') region = next(iter(regions.values())) if list(loaded.size_yzx) != [data['size'][1], data['size'][2], data['size'][0]]: raise ContractError('geometry-mismatch', conditions='Export dimensions changed') if region['Entities']: raise ContractError('geometry-mismatch', conditions='Unexpected entities') inventories = {} for entry in region['TileEntities']: item = _plain(entry) p = tuple(item.pop(k) + data['offset'][i] for i, k in enumerate(('x', 'y', 'z'))) inventories[p] = item from .environment.fields import from_expression scene = Scene(data['seed'], decode(data['limits']), decode(data['domain']), data.get('style'), {k: from_expression(v) for k, v in data.get('preferences', {}).items()}) scene.nodes = decode(data['nodes']) scene.relations = decode(data['relations']) for child, kind, parent in scene.relations: if kind in ('contained_by', 'attached_to'): scene.members.setdefault(parent, set()).add(child) scene.dependencies = decode(data['dependencies']) scene.operations = decode(data['operations']) scene.erasures = {tuple(p): owner for p, owner in data.get('erasures', [])} scene.events = decode(data['events']) scene.displaced = {k: {tuple(p): decode(c) for p, c in v} for k, v in data.get('displaced', {}).items()} scene.version = data['scene_version'] scene.port_uses = {(a, b): n for a, b, n in data['port_uses']} ownership = {tuple(row[:3]): row[3:] for row in data['cells']} scene.reverse = {k: set() for k in scene.nodes} ids = loaded.read_flat(0, loaded.volume).reshape(loaded.size_yzx) import numpy as np for y, z, x in np.argwhere(ids != 0): block = canonical(loaded.palette[int(ids[y, z, x])]) if block == AIR: continue p = tuple(int(v) + o for v, o in zip((x, y, z), data['offset'])) if p not in ownership: raise ContractError('geometry-mismatch', position=p, conditions='Unrecorded block') owner, op, shared = ownership[p] owner = data['owners'][owner] scene.blocks[p] = Cell(block, owner, data['operation_ids'][op], inventories.get(p), tuple(shared)) scene.reverse[owner].add(p) for participant in shared: scene.reverse_shared.setdefault(participant, set()).add(p) if set(ownership) != set(scene.blocks) or set(inventories) - set(scene.blocks) or semantic_digest(scene) != data['digest']: raise ContractError('geometry-mismatch', conditions='Schematic and structural companion are not a matching semantic pair') scene.finalize() return scene
hearth/programs.py · 175 行 · 原文件
# Lightweight high-level room-graph programs and settlement intent. from hearth import Scene, Box, Frame from hearth.randomness import Scope from hearth.kernel import Capability, Contract, Plan, Child, Binding, Rule, Port from hearth.environment import Terrain, gradient, wave, radial from hearth.components.building import Blueprint, Building, RoomSpec, adapted from hearth.components.landscape import PathNetwork, Landscape, LampPost, Terrace from hearth.components.primitives import Window from hearth.composition import encapsulate def dwelling(seed): rng = Scope(seed).child('dwelling').stream('layout') rooms = [RoomSpec(0, 0, 0, 'living'), RoomSpec(0, 0, 1, 'bedroom')] if rng.choice((True, False)): rooms.append(RoomSpec(0, 1, 0, 'kitchen')) if rng.choice((True, False)): rooms.append(RoomSpec(1, 0, 0, 'library')) return Blueprint(tuple(rooms), bay=rng.choice((9, 11)), porch=True, roof_axis='auto', steep=True) def atelier(seed): rng = Scope(seed).child('atelier').stream('layout') rooms = [RoomSpec(0, 0, 0, 'workshop'), RoomSpec(1, 0, 0, 'storage')] if rng.choice((True, False)): rooms.append(RoomSpec(1, 0, 1, 'bedroom')) if rng.choice((True, False)): rooms.append(RoomSpec(0, 1, 0, 'kitchen')) return Blueprint(tuple(rooms), bay=rng.choice((9, 11)), porch=rng.choice((True, False)), roof_axis='x', roof_material='brick', steep=rng.choice((True, False)), window_component=Window(shutters=False)) def commons(seed): rng = Scope(seed).child('commons').stream('layout') rooms = [RoomSpec(0, 0, 0, 'library'), RoomSpec(0, 1, 0, 'living'), RoomSpec(1, 1, 0, 'kitchen')] for level in range(1, rng.choice((2, 3))): rooms.append(RoomSpec(0, 1, level, 'bedroom' if level == 1 else 'library')) if rng.choice((True, False)): rooms.append(RoomSpec(1, 0, 0, 'storage')) return Blueprint(tuple(rooms), bay=rng.choice((9, 11)), porch=True, roof_axis='z') PROGRAMS = {'dwelling': dwelling, 'atelier': atelier, 'commons': commons} def building_scene(design, seed=0, field=None, water=None): design.validate() b = design.bay width = (max(r.x for r in design.rooms) + 1) * b depth = (max(r.z for r in design.rooms) + 1) * b domain = Box((-8, -4, -18), (width + 8, 64, depth + 8)) scene = Scene(seed, domain=domain) expression = field if field is not None else gradient(base=4) + wave(.8, .1, .11, Scope(seed).stream('environment').random() * 6) scene.place('land', Terrain(domain, expression, water)) # Encapsulation preserves the public building instance as the selected child. choice = adapted('building', design, '/land') scene.compose_choice(choice) return scene.finalize() class Settlement: def __init__(self, designs, domain, terrain): self.designs = tuple(designs) self.domain = domain self.terrain = terrain def capability(self): return Capability('settlement.village', ('settlement', 'composite'), offers=('public-access',), guarantees=('building entrances connected',)) def negotiate(self, ctx, parameters): gateway = (0, ctx.elevation(0, -12) + 1, -12) interface = Box((-1, gateway[1] - 1, -12), (1, gateway[1] + 1, -12)) port = Port('public', 'public-access', Frame(gateway), interface, 10000, delegate=('connections', 'public')) return Contract(self.domain, ports=(port,), decisions={'buildings': len(self.designs), 'arrangement': 'opposed street with staggered frontage', 'circulation': ctx.scope.choose(('spine', 'loop'), 'circulation'), 'gateway': gateway}) def realize(self, ctx, contract): p = Plan() for i, design in enumerate(self.designs): row = i // 2 left = i % 2 == 0 z = row * 38 + ctx.scope.child(f'plot-{i}').choose((-2, 0, 2), 'frontage') origin = (-16, 0, z - design.bay // 2) if left else (16, 0, z + design.bay // 2) p.children.append(adapted(f'plot-{i}', design, self.terrain, Frame(origin, 1 if left else 3))) p.children.append(Child('square', Terrace(), frame=Frame((5, 0, 10)), bindings=(Binding(self.terrain, 'construction', 'fill'),))) p.children.append(Child('connections', SettlementConnections(len(self.designs), self.domain, self.terrain, contract.decisions['circulation'], contract.decisions['gateway']))) p.children.append(Child('landscape', Landscape(self.domain, self.terrain, 8, 12, 0.045))) return p class SettlementConnections: def __init__(self, count, domain, terrain, mode='spine', gateway=None): self.count = count self.domain = domain self.terrain = terrain self.mode = mode self.gateway = gateway def capability(self): return Capability('settlement.connections', ('connection', 'composite')) def negotiate(self, ctx, parameters): parent = ctx.path.rsplit('/', 1)[0] targets = tuple(ctx.local(ctx.view.port(f'{parent}/plot-{i}', 'street').frame.origin) for i in range(self.count)) targets = targets + (ctx.local(ctx.view.port(parent + '/square', 'entrance').frame.origin), self.gateway) interface = Box((self.gateway[0] - 1, self.gateway[1] - 1, self.gateway[2]), (self.gateway[0] + 1, self.gateway[1] + 1, self.gateway[2])) port = Port('public', 'public-access', Frame(self.gateway), interface, 10000, delegate=('paths', 'public')) return Contract(self.domain, ports=(port,), rules=(Rule('route', targets, self.domain, phase='complete'),)) def realize(self, ctx, contract): parent = ctx.path.rsplit('/', 1)[0] points = [] links = [] bindings = [Binding(self.terrain, 'construction', 'surface')] for i in range(self.count): host = f'{parent}/plot-{i}' port = ctx.view.port(host, 'street') x, y, z = ctx.local(port.frame.origin) lane = (-3 if x < 0 else 3) if self.mode == 'loop' else 0 points.extend(((x, y, z), (lane, ctx.elevation(lane, z) + 1, z))) links.append((2 * i, 2 * i + 1)) bindings.append(Binding(host, 'street', 'surface')) if i and self.mode == 'spine': links.append((2 * i - 1, 2 * i + 1)) if self.mode == 'loop': low = min(q[2] for q in points) high = max(q[2] for q in points) base = len(points) for x, z in ((-3, low), (-3, high), (3, high), (3, low)): points.append((x, ctx.elevation(x, z) + 1, z)) links.extend((base + i, base + (i + 1) % 4) for i in range(4)) square = ctx.local(ctx.view.port(parent + '/square', 'entrance').frame.origin) lane = 3 if self.mode == 'loop' else 0 points.extend((square, (lane, ctx.elevation(lane, square[2]) + 1, square[2]))) links.append((len(points) - 2, len(points) - 1)) if self.mode == 'spine': links.append((1, len(points) - 1)) points.append(self.gateway) links.append((1, len(points) - 1)) bindings.append(Binding(parent + '/square', 'entrance', 'surface')) p = Plan(children=[Child('paths', PathNetwork(tuple(points), tuple(links), gateway=self.gateway), bindings=tuple(bindings))]) for i in range(self.count): p.relations.append((ctx.path + '/paths', 'connects', f'{parent}/plot-{i}')) for i, z in enumerate(sorted({q[-1] for q in points[:self.count * 2]})): x = 5 if i % 2 else -5 y = ctx.elevation(x, z + 4) + 1 p.children.append(Child(f'lamp-{i}', LampPost(), frame=Frame((x, y, z + 4)))) return p def settlement_scene(seed=0, count=None): scope = Scope(seed) rng = scope.stream('settlement-layout') if count is None: count = rng.choice((3, 4, 5)) if count < 1: raise ValueError('A settlement needs at least one building') designs = [] for i in range(count): local = scope.child(f'building-{i}').stream('room-graph') rooms = [RoomSpec(0, 0, 0, local.choice(('living', 'workshop', 'library')))] for x, z in local.sample(((1, 0), (0, 1)), local.choice((0, 1, 2))): rooms.append(RoomSpec(x, z, 0, local.choice(('storage', 'kitchen', 'living')))) if local.choice((True, True, False)): column = local.choice(rooms) for level in range(1, local.choice((2, 2, 3))): rooms.append(RoomSpec(column.x, column.z, level, 'bedroom' if level == 1 else 'library')) designs.append(Blueprint(tuple(rooms), bay=local.choice((9, 11)), porch=local.choice((True, True, False)), roof_axis=local.choice(('auto', 'x', 'z')), roof_material=local.choice(('deepslate_tile', 'brick')), steep=local.choice((True, True, False)))) rows = (count + 1) // 2 domain = Box((-49, -4, -23), (49, 64, (rows - 1) * 38 + 28)) field = gradient(.012, -.009, 4.8) + wave(.7, .075, .09, rng.random() * 6) + radial(-36, rows * 12, 26, 1.1) scene = Scene(seed, domain=domain) scene.place('land', Terrain(domain, field, edit_limit=20000)) scene.place('village', Settlement(designs, domain, '/land')) return scene.finalize()
hearth/randomness.py · 21 行 · 原文件
# Stateless hierarchical scopes, with explicitly local random streams. import hashlib import json import random from dataclasses import dataclass @dataclass(frozen=True) class Scope: seed: int key: tuple[str, ...] = () def child(self, key: str, override: int | None = None): return Scope(self.seed, self.key + (key,)) if override is None else Scope(override, (key,)) def stream(self, purpose: str = 'plan') -> random.Random: payload = json.dumps([self.seed, self.key, purpose], separators=(',', ':')).encode() return random.Random(int.from_bytes(hashlib.sha256(payload).digest(), 'big')) def choose(self, values, purpose='plan'): return self.stream(purpose).choice(tuple(values))
hearth/space.py · 109 行 · 原文件
# Integer geometry and explicit local-to-world transforms. from dataclasses import dataclass from itertools import product from typing import Iterable Pos = tuple[int, int, int] @dataclass(frozen=True) class Box: lo: Pos hi: Pos def __post_init__(self): object.__setattr__(self, 'lo', tuple(self.lo)) object.__setattr__(self, 'hi', tuple(self.hi)) if any(not isinstance(v, int) for v in (*self.lo, *self.hi)): raise TypeError('Box coordinates must be integers') if any(a > b for a, b in zip(self.lo, self.hi)): raise ValueError('Inverted box') def contains(self, p: Pos) -> bool: return all(a <= v <= b for a, v, b in zip(self.lo, p, self.hi)) def cells(self) -> Iterable[Pos]: return product(*(range(a, b + 1) for a, b in zip(self.lo, self.hi))) def corners(self): return product(*zip(self.lo, self.hi)) def intersection(self, other): low = tuple(max(a, b) for a, b in zip(self.lo, other.lo)) high = tuple(min(a, b) for a, b in zip(self.hi, other.hi)) return None if any(a > b for a, b in zip(low, high)) else Box(low, high) def expand(self, n: int): return Box(tuple(v - n for v in self.lo), tuple(v + n for v in self.hi)) @property def size(self): return tuple(b - a + 1 for a, b in zip(self.lo, self.hi)) @property def volume(self): x, y, z = self.size return x * y * z @classmethod def enclosing(cls, points): points = list(points) if not points: raise ValueError('No realized geometry') return cls(tuple(min(p[i] for p in points) for i in range(3)), tuple(max(p[i] for p in points) for i in range(3))) @dataclass(frozen=True) class Frame: origin: Pos = (0, 0, 0) turn: int = 0 def __post_init__(self): object.__setattr__(self, 'origin', tuple(self.origin)) if not isinstance(self.turn, int) or any(not isinstance(v, int) for v in self.origin): raise TypeError('Frames use integer coordinates and quarter turns') object.__setattr__(self, 'turn', self.turn % 4) def vector(self, p: Pos) -> Pos: x, y, z = p for _ in range(self.turn % 4): x, z = -z, x return x, y, z def point(self, p: Pos) -> Pos: return tuple(a + b for a, b in zip(self.origin, self.vector(p))) def inverse(self, p: Pos) -> Pos: return Frame(turn=-self.turn).vector(tuple(a - b for a, b in zip(p, self.origin))) def box(self, box: Box) -> Box: return Box.enclosing(self.point(p) for p in box.corners()) def compose(self, other): return Frame(self.point(other.origin), (self.turn + other.turn) % 4) def state(self, state: str) -> str: from .blocks import parse, state_of name, props = parse(state) dirs = ['north', 'east', 'south', 'west'] rotated = {} for key, value in props.items(): if key in dirs: key = dirs[(dirs.index(key) + self.turn) % 4] if key == 'facing' and value in dirs: value = dirs[(dirs.index(value) + self.turn) % 4] if key in ('shape', 'orientation') and any(v in dirs for v in value.split('_')): from .blocks import SCHEMA tokens = [dirs[(dirs.index(v) + self.turn) % 4] if v in dirs else v for v in value.split('_')] value = '_'.join(tokens) allowed = SCHEMA[name.removeprefix('minecraft:')][0][key] if value not in allowed: matches = [candidate for candidate in allowed if sorted(candidate.split('_')) == sorted(tokens)] if matches: value = sorted(matches)[0] if key == 'axis' and value in ('x', 'z') and self.turn % 2: value = 'z' if value == 'x' else 'x' if key == 'rotation': value = str((int(value) + 4 * self.turn) % 16) rotated[key] = value return state_of(name, **rotated)
examples/__init__.py · 1 行 · 原文件
# Runnable public-API examples and explicit assessment tools.
examples/assess.py · 13 行 · 原文件
# Explicit finite batch output, never an unnoticed unit-test side effect. import argparse import json from pathlib import Path from hearth.assessment import run_corpus if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('reports/corpus')) p.add_argument('--artifacts', action='store_true') a = p.parse_args() print(json.dumps(run_corpus(a.output, a.seed, a.artifacts), indent=2))
examples/building.py · 13 行 · 原文件
# Run any of the three short room-composition programs with an explicit seed. import argparse from pathlib import Path from hearth.programs import PROGRAMS, building_scene from hearth.persistence import export_scene if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('program', choices=PROGRAMS) p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('samples/building.litematic')) a = p.parse_args() export_scene(building_scene(PROGRAMS[a.program](a.seed), a.seed), a.output)
examples/courtyard.py · 25 行 · 原文件
# New composition written after the core abstractions; no library changes needed. import argparse from pathlib import Path from hearth.components.building import Blueprint, RoomSpec from hearth.programs import building_scene from hearth.randomness import Scope from hearth.persistence import export_scene def build(seed): rng = Scope(seed).stream('courtyard') ring = ((0, 0), (1, 0), (2, 0), (2, 1), (2, 2), (1, 2), (0, 2), (0, 1)) functions = ('living', 'library', 'workshop', 'storage', 'kitchen', 'bedroom', 'bedroom', 'storage') rooms = [RoomSpec(x, z, 0, purpose) for (x, z), purpose in zip(ring, functions)] for x, z in rng.sample(((0, 0), (2, 0), (0, 2), (2, 2)), rng.choice((1, 2))): rooms.append(RoomSpec(x, z, 1, 'bedroom')) return building_scene(Blueprint(tuple(rooms), bay=9, porch=True, roof_axis='auto'), seed) if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('samples/courtyard.litematic')) a = p.parse_args() export_scene(build(a.seed), a.output)
examples/extension.py · 27 行 · 原文件
# Substitute independent lighting and encapsulate an independently packaged room. import argparse from pathlib import Path from hearth import Scene, Box, Frame from hearth.kernel import Registry from hearth.components.interior import Light from hearth.components.building import Blueprint, RoomSpec from hearth.programs import building_scene from hearth.persistence import export_scene from extension_demo import Pendant, ReadingSuite def build(seed): registry = Registry() registry.register(Light()) registry.register(Pendant()) lights = registry.select('room-light') design = Blueprint((RoomSpec(0, 0, 0, 'library'), RoomSpec(0, 0, 1, 'bedroom')), light_component=lights[seed % len(lights)]) return building_scene(design, seed) if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('samples/extension.litematic')) a = p.parse_args() export_scene(build(a.seed), a.output)
examples/gallery.py · 25 行 · 原文件
# A later client composes a public gallery with connected reading and work rooms. import argparse from pathlib import Path from hearth.components.building import Blueprint, RoomSpec from hearth.programs import building_scene from hearth.randomness import Scope from hearth.persistence import export_scene from extension_demo import Pendant def build(seed): rng = Scope(seed).stream('gallery-layout') length = rng.choice((2, 3)) rooms = [RoomSpec(0, z, 0, 'library' if z % 2 else 'living') for z in range(length)] rooms.append(RoomSpec(1, length - 1, 0, 'workshop')) rooms.append(RoomSpec(0, length - 1, 1, 'bedroom')) return building_scene(Blueprint(tuple(rooms), bay=9, roof_axis='z', light_component=Pendant()), seed) if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('samples/gallery.litematic')) a = p.parse_args() export_scene(build(a.seed), a.output)
examples/inspection.py · 28 行 · 原文件
# Generate a real glass query, highlight membership, export and repeat after reload. import argparse import json from pathlib import Path from hearth.programs import dwelling, building_scene from hearth.persistence import export_scene, load_scene from hearth.blocks import name_of def demonstrate(seed, output): scene = building_scene(dwelling(seed), seed) point = next(p for p, c in sorted(scene.blocks.items()) if name_of(c.state) == 'glass' and 'room-' in c.owner) query = scene.inspect(point) print(json.dumps(query, default=lambda v: sorted(v), indent=2)) print('Exact current component cells:', sorted(scene.cells(query['instance']))) export_scene(scene, output) restored = load_scene(output) assert restored.inspect(point) == query print('Reloaded query identical; world coordinate:', point) return query if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('samples/inspection.litematic')) a = p.parse_args() demonstrate(a.seed, a.output)
examples/preview.py · 62 行 · 原文件
# Render labeled exterior views and geometry-only slices with the optional proc tools. import argparse import json from pathlib import Path import subprocess import sys from hearth.persistence import export_scene, load_scene, companion_path from hearth.programs import settlement_scene RENDER = Path('/opt/tools/render_schematic.mjs') CUTAWAY = Path('/opt/tools/cutaway.py') VITE = Path('/work/generator/MCRender/node_modules/.bin/vite-node') def render(source, target, azimuth, elevation, size, radius): subprocess.run(['xvfb-run', '-a', str(VITE), '--script', str(RENDER), '--', '--input', str(source), '--output', str(target), '--size', str(size), '--azimuth', str(azimuth), '--elevation', str(elevation), '--radius', str(radius), '--fov', '30', '--ambient', '0.8'], check=True) def preview(seed, source, output, size=1200, cutaways=False): output.mkdir(parents=True, exist_ok=True) if source is None: source = output / 'source.litematic' export_scene(settlement_scene(seed), source) scene = load_scene(source) if scene.seed != seed: raise ValueError(f'--seed {seed} does not match the input artifact seed {scene.seed}') views = [('front', 210, 28, 3.5), ('rear', 30, 26, 3.5)] records = [] for label, azimuth, elevation, radius in views: target = output / (label + '.png') render(source, target, azimuth, elevation, size, radius) records.append({'source': str(source), 'seed': seed, 'label': label, 'image': str(target), 'azimuth': azimuth, 'elevation': elevation}) if cutaways: building = next(n for n in scene.nodes.values() if n.type == 'building.rooms') floor = building.contract.decisions['floor'] + building.frame.origin[1] offset = json.loads(companion_path(source).read_text())['offset'] cuts = [('floor-cut', 'y', floor + 4 - offset[1], 210, 64)] stair = next((n for n in scene.nodes.values() if n.type == 'circulation.stair'), None) if stair is not None: occupied = scene.cells(stair.path) # Cut beside the actual flight, including flights in a remote wing. axis = min((0, 2), key=lambda i: max(p[i] for p in occupied) - min(p[i] for p in occupied)) limit = max(p[axis] for p in occupied) + 1 - offset[axis] cuts.append(('stair-cut', 'xz'[axis // 2], limit, 110 if axis == 0 else 20, 26)) for label, axis, limit, azimuth, elevation in cuts: cut = output / (label + '.litematic') subprocess.run([sys.executable, str(CUTAWAY), '--input', str(source), '--output', str(cut), '--axis', axis, '--max', str(limit), '--name', label], check=True) target = output / (label + '.png') render(cut, target, azimuth, elevation, size, 3.2) records.append({'source': str(source), 'seed': seed, 'label': label, 'axis': axis, 'export_local_cut': limit, 'image': str(target), 'geometry_preview_only': True}) (output / 'views.json').write_text(json.dumps(records, indent=2)) if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--input', type=Path) p.add_argument('--output', type=Path, default=Path('previews/default')) p.add_argument('--size', type=int, default=1200) p.add_argument('--cutaways', action='store_true') a = p.parse_args() preview(a.seed, a.input, a.output, a.size, a.cutaways)
examples/prototype.py · 33 行 · 原文件
# Run the small terrain, planting and attached-window composition before full buildings. import argparse from pathlib import Path from hearth import Scene, Box, Frame, Binding from hearth.environment import Terrain, gradient, wave from hearth.components.primitives import Wall, Window, Grass, Tree from hearth.adapters.site import Foundation from hearth.composition import encapsulate from hearth.kernel import Plan, Child from hearth.persistence import export_scene def build(seed=0): scene = Scene(seed, domain=Box((-8, -3, -8), (20, 24, 20))) scene.place('land', Terrain(scene.domain, gradient(base=2) + wave(0.6, 0.2, 0.2))) def facade(ctx): return Plan(children=[Child('wall', Wall(thickness=2)), Child('window', Window(), frame=Frame((3, 1, 0)), bindings=(Binding(ctx.path + '/wall', 'infill'),))]) scene.place('footing', Foundation.rectangular(9, 2, 4), bindings=(Binding('/land', 'construction', 'fill'),)) scene.place('facade', encapsulate('facade', Box((-1, 0, -2), (10, 6, 3)), facade), frame=Frame((0, 4, 0))) y = scene.view.elevation(13, 9) + 1 scene.place('grass', Grass(True), frame=Frame((13, y, 9)), bindings=(Binding('/land', 'planting', 'plant'),)) scene.place('tree', Tree(), frame=Frame((13, y, 9)), bindings=(Binding('/land', 'planting', 'plant'), Binding('/grass', 'replacement', 'plant'))) return scene.finalize() if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--seed', type=int, default=0) parser.add_argument('--output', type=Path, default=Path('samples/prototype.litematic')) args = parser.parse_args() export_scene(build(args.seed), args.output)
examples/verify_replay.py · 35 行 · 原文件
# Explicit cross-process hash-seed replay and paired metadata verification. import argparse import json import os from pathlib import Path import subprocess import sys import tempfile from hearth.persistence import load_scene, semantic_digest from hearth.space import Box def verify(seed, output): root = Path(__file__).resolve().parents[1] rows = [] with tempfile.TemporaryDirectory(dir=root / 'test', prefix='tmp-replay-') as temporary: for hash_seed in ('3', '8675309'): path = Path(temporary) / f'seed {seed} hash {hash_seed}.litematic' env = dict(os.environ, PYTHONHASHSEED=hash_seed) subprocess.run([sys.executable, str(root / 'generate.py'), '--seed', str(seed), '--output', str(path)], check=True, cwd=root, env=env) scene = load_scene(path) rows.append({'seed': seed, 'PYTHONHASHSEED': hash_seed, 'digest': semantic_digest(scene), 'bounds': [Box.enclosing(scene.blocks).lo, Box.enclosing(scene.blocks).hi], 'blocks': len(scene.blocks), 'buildings': sum(n.type == 'building.rooms' for n in scene.nodes.values())}) if rows[0]['digest'] != rows[1]['digest'] or rows[0]['bounds'] != rows[1]['bounds']: raise AssertionError('Cross-process replay mismatch') output.parent.mkdir(parents=True, exist_ok=True) output.write_text(json.dumps({'verified': True, 'runs': rows}, indent=2)) return rows if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--seed', type=int, default=0) p.add_argument('--output', type=Path, default=Path('reports/replay.json')) a = p.parse_args() verify(a.seed, a.output)
extension_demo/__init__.py · 38 行 · 原文件
# Independent component package; imports only Hearth's public protocols and components. from dataclasses import dataclass from hearth.kernel import Capability, Contract, Plan, Child, Rule, Port from hearth.space import Box, Frame from hearth.blocks import state_of, slab from hearth.components.interior import Room @dataclass(frozen=True) class Pendant: def capability(self): return Capability('extension.pendant', ('light', 'room-light'), guarantees=('actual light source',)) def negotiate(self, context, parameters): return Contract(Box((0, 0, 0), (0, 1, 0)), rules=(Rule('expected', ((0, 0, 0),), data={'names': ['ochre_froglight']}),)) def realize(self, context, contract): plan = Plan() plan.block((0, 0, 0), state_of('ochre_froglight', axis='y')) plan.block((0, 1, 0), slab('dark_oak')) return plan @dataclass(frozen=True) class ReadingSuite: width: int = 11 def capability(self): return Capability('extension.reading-suite', ('room', 'habitable', 'composite'), offers=('access',), guarantees=('lit', 'furnished', 'enclosed', 'reachable')) def negotiate(self, context, parameters): entry = (self.width // 2, 1, 0) port = Port('north', 'access', Frame(entry), Box(entry, (entry[0], 2, 0)), 10, delegate=('reading-room', 'north')) return Contract(Box((-1, 0, -1), (self.width, 9, self.width)), ports=(port,)) def realize(self, context, contract): return Plan(children=[Child('reading-room', Room('library', self.width, self.width, light_component=Pendant()))])
test/conftest.py · 13 行 · 原文件
# Tests keep transient artifacts under test/ and remove them after each test. import sys import tempfile from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).parents[1])) @pytest.fixture def work(): with tempfile.TemporaryDirectory(dir=Path(__file__).parent, prefix='tmp-') as name: yield Path(name)
test/test_contracts_provenance.py · 279 行 · 原文件
# Mutation, sharing, phases, rotations, extension and synchronized provenance tests. from dataclasses import dataclass, replace import json import pytest from hearth import Scene, Box, Frame, Binding, ContractError from hearth.kernel import Capability, Contract, Grant, Port, Rule, Plan, Child, Limits, SearchExhausted from hearth.blocks import state_of from hearth.components.primitives import Volume, Assembly, Window, Wall, Grass, Tree, Pool from hearth.kernel.scene import Cell from hearth.persistence import export_scene, load_scene, semantic_digest from hearth.randomness import Scope from hearth.composition import encapsulate, repeat, arrange, scatter from extension_demo import Pendant, ReadingSuite @dataclass(frozen=True) class Editable: def capability(self): return Capability('editable', ('support',)) def negotiate(self, c, p): b = Box((0, 0, 0), (0, 0, 0)) return Contract(b, (Port('edit', 'adjust', Frame(), b, 10, 'edit'), Port('shared', 'shared-support', Frame(), b, 4)), (Grant('edit', b, ('adjust', 'excavate'), ('editor',), 1),)) def realize(self, c, b): p = Plan() p.block((0, 0, 0), state_of('oak_log', axis='y')) return p @dataclass(frozen=True) class Editor: material: str preserve: bool = True def capability(self): return Capability('editor', ('editor',)) def negotiate(self, c, p): return Contract(Box((0, 0, 0), (0, 0, 0))) def realize(self, c, b): p = Plan() p.block((0, 0, 0), self.material, preserve_owner=self.preserve) return p def test_adjustment_membership_history_deletion_and_reload(work): s = Scene() s.place('owner', Editable()) s.place('adjust', Editor(state_of('oak_log', axis='x')), bindings=(Binding('/owner', 'edit', 'adjust'),)) q = s.inspect((0, 0, 0)) assert q['instance'] == '/owner' and q['operation']['component'] == '/adjust' assert s.cells('/adjust') == frozenset() export_scene(s, work / 'adjust.litematic') r = load_scene(work / 'adjust.litematic') assert r.inspect((0, 0, 0)) == q s.remove('/adjust') assert s.inspect((0, 0, 0))['state'] == state_of('oak_log', axis='y') s.place('erase', Editor(state_of('air'), False), bindings=(Binding('/owner', 'edit', 'excavate'),)) assert s.inspect((0, 0, 0))['instance'] is None and not s.cells('/owner') s.remove('/erase') assert s.cells('/owner') == {(0, 0, 0)} def test_identical_blocks_do_not_grant_sharing_and_explicit_shared_support(): s = Scene() s.place('support', Editable()) s.place('bridge', Assembly('bridge', Box((0, 0, 0), (2, 2, 2)), ())) with pytest.raises(ContractError, match='write-authority'): s.place('intruder', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('oak_log', axis='y'))) s.share((0, 0, 0), '/bridge', '/support', 'shared') assert s.cells('/bridge', shared=True) == {(0, 0, 0)} assert ('/bridge', 'shares_support', '/support') in s.inspect((0, 0, 0))['related'] with pytest.raises(ContractError, match='support'): s.remove('/support') s.remove('/bridge') assert not s.inspect((0, 0, 0))['shared'] def test_partial_tall_plant_replacement_atomicity(): from hearth.environment import Terrain, constant s = Scene(domain=Box((-2, -2, -2), (4, 15, 4))) s.place('terrain', Terrain(s.domain, constant(0))) s.place('grass', Grass(True), frame=Frame((0, 1, 0))) @dataclass class Pruner: def capability(self): return Capability('pruner', ('tree',)) def negotiate(self, c, p): return Contract(Box((0, 0, 0), (0, 0, 0))) def realize(self, c, b): p = Plan() p.block((0, 0, 0), state_of('oak_log', axis='y')) return p snapshot = (semantic_digest(s), set(s.nodes), set(s.relations), dict(s.port_uses), list(s.dependencies)) with pytest.raises(ContractError, match='whole-object'): s.place('prune', Pruner(), frame=Frame((0, 1, 0)), bindings=(Binding('/grass', 'replacement', 'plant'),)) assert snapshot == (semantic_digest(s), set(s.nodes), set(s.relations), dict(s.port_uses), list(s.dependencies)) @pytest.mark.parametrize('turn', range(4)) def test_rotated_attachment_ports_claims_membership(turn, work): frame = Frame((-13, 5, 17), turn) def compose(c): return Plan(children=[Child('base', Volume(Box((0, -1, 0), (8, -1, 2)), state_of('stone'))), Child('wall', Wall(thickness=3)), Child('a', Window(), frame=Frame((2, 1, 0)), bindings=(Binding(c.path + '/wall', 'infill'),)), Child('b', Window(shutters=False), frame=Frame((6, 1, 0)), bindings=(Binding(c.path + '/wall', 'infill'),))]) s = Scene(31) s.place('house', encapsulate('house', Box((-1, -1, -2), (10, 8, 4)), compose), frame=frame) a, b = frame.point((2, 1, 0)), frame.point((6, 1, 0)) assert s.inspect(a)['instance'] != s.inspect(b)['instance'] assert [n['type'] for n in s.inspect(a)['chain']] == ['window.shuttered', 'wall.framed', 'house'] assert s.nodes['/house/wall'].contract.ports[0].frame.turn == turn assert all(s.nodes['/house/a'].contract.envelope.contains(p) for p in s.cells('/house/a')) export_scene(s, work / 'rotated.litematic') assert load_scene(work / 'rotated.litematic').inspect(a) == s.inspect(a) def test_completion_obligation_and_late_decoration(): s = Scene() b = Box((0, 0, 0), (3, 4, 3)) s.place('unfinished', Assembly('room', b, (), (Rule('light', ((1, 1, 1),), b, phase='complete'),)), complete=False) with pytest.raises(ContractError): s.finalize() s.place('lamp', Pendant(), frame=Frame((1, 2, 1))) s.finish_scope('/unfinished') s.finalize() with pytest.raises(ContractError, match='lighting'): s.remove('/lamp') def test_extension_low_level_composite_and_nested_protocol(): s = Scene(4) room = ReadingSuite() wrapper = encapsulate('independent-suite', Box((-2, 0, -2), (14, 11, 14)), lambda c: Plan(children=[Child('suite', room)])) s.place('hall', wrapper) s.finalize() assert any(n.type == 'extension.pendant' for n in s.nodes.values()) assert any(n.type == 'extension.reading-suite' for n in s.nodes.values()) def test_independent_order_and_failed_alternative_streams(): @dataclass class Seeded: def capability(self): return Capability('seeded', ()) def negotiate(self, c, p): return Contract(Box((0, 0, 0), (2, 0, 0))) def realize(self, c, b): p = Plan() p.block((c.rng('geometry').randrange(3), 0, 0), state_of('stone')) return p a, b = Scene(81), Scene(81) for scene, order in ((a, ('one', 'two')), (b, ('two', 'one'))): for key in order: scene.place(key, Seeded(), frame=Frame((10 if key == 'two' else 0, 0, 0))) assert semantic_digest(a) == semantic_digest(b) before = a.cells('/one') with pytest.raises(SearchExhausted): a.choose('failed', [Child('x', Volume(Box((0, 0, 0), (2, 0, 0)), state_of('dirt')))]) a.place('planter', Seeded(), frame=Frame((20, 0, 0))) assert a.cells('/one') == before c = Scene(81) c.place('one', Seeded(), seed=123) assert c.nodes['/one'].scope.seed == 123 def test_regeneration_restores_displaced_terrain_and_no_stale_cells(): from hearth.environment import Terrain, constant s = Scene(domain=Box((-2, -3, -2), (12, 20, 12))) s.place('land', Terrain(s.domain, constant(0))) before = semantic_digest(s) s.place('pool', Pool(), frame=Frame((1, 0, 1)), bindings=(Binding('/land', 'construction', 'excavate'),)) s.remove('/pool') assert semantic_digest(s) == before assert not any('/pool' in (a, c) for a, b, c in s.relations) def test_edit_limits_unknown_space_and_budget(): from hearth.environment import Terrain, constant s = Scene(domain=Box((-3, -3, -3), (12, 20, 12))) s.place('land', Terrain(s.domain, constant(0), edit_limit=1)) with pytest.raises(ContractError, match='edit-limit'): s.place('pool', Pool(), bindings=(Binding('/land', 'construction', 'excavate'),)) with pytest.raises(ContractError, match='unknown-space'): s.view.state((100, 1, 1)) s = Scene(limits=Limits(blocks=1)) with pytest.raises(ContractError, match='block-budget'): s.place('large', Volume(Box((0, 0, 0), (3, 0, 0)), state_of('stone'))) assert not s.nodes and not s.blocks def test_attachment_membership_across_encapsulation_boundaries(): s = Scene() s.place('house', Assembly('house', Box((-2, -1, -2), (12, 8, 5)), (Child('base', Volume(Box((0, -1, 0), (8, -1, 0)), state_of('stone'))), Child('wall', Wall())))) s.place('facade-window', Window(), frame=Frame((3, 1, 0)), bindings=(Binding('/house/wall', 'infill'),)) assert s.cells('/facade-window') <= s.cells('/house/wall', descendants=True) assert s.cells('/facade-window') <= s.cells('/house', descendants=True) assert s.inspect((3, 1, 0))['chain'][-1]['id'] == '/house' with pytest.raises(ContractError): s.remove('/house') s.regenerate('/house', dependents=('/facade-window',)) assert s.inspect((3, 1, 0))['instance'] == '/facade-window' def test_public_readonly_contracts_and_protected_preference(): from hearth.components.constraints import Preserve from hearth.environment import Terrain, constant s = Scene(domain=Box((-3, -3, -3), (12, 20, 12)), preferences={'planting': constant(100)}) s.place('land', Terrain(s.domain, constant(0))) s.place('reserve', Preserve(Box((1, -2, 1), (3, 1, 3)))) assert s.view.preference('planting', (2, 0, 2)) == 100 with pytest.raises(ContractError, match='protected-region'): s.place('pool', Pool(), bindings=(Binding('/land', 'construction', 'excavate'),)) original = s.nodes['/land'].contract.decisions['water'] public = s.view.contract('/land') public.decisions['water'] = 99 assert s.nodes['/land'].contract.decisions['water'] == original def test_explicit_candidate_budget_exhaustion(): from hearth.kernel import Choice s = Scene(limits=Limits(search=1)) s.place('occupied', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('stone'))) choice = Choice('choice', (Child('bad', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('dirt'))), Child('valid', Volume(Box((3, 0, 0), (3, 0, 0)), state_of('stone')))), lambda view, path: 0) with pytest.raises(SearchExhausted, match='search-budget'): s.compose_choice(choice) assert '/choice' not in s.nodes s.limits = replace(s.limits, search=2) s.compose_choice(choice) assert s.cells('/choice') == {(3, 0, 0)} def test_validator_extension_and_negotiated_domain(): from hearth.kernel import validator, Diagnostic @validator('test.actual-stone') def actual_stone(scene, node, rule): for p in rule.cells: if scene.inspect(p)['state'] != 'minecraft:stone': yield Diagnostic('test.actual-stone', node.path, p, 'Need actual stone') s = Scene() s.place('rule', Assembly('rule', Box((0, 0, 0), (0, 0, 0)), (Child('stone', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('stone'))),), (Rule('test.actual-stone', ((0, 0, 0),)),))) with pytest.raises(ContractError, match='test.actual-stone'): s.remove('/rule/stone') with pytest.raises(ContractError, match='input-domain'): s.place('bad-wall', Wall(width=100)) def test_forwarded_interfaces_discharge_after_scope_construction(): from hearth.kernel import Choice later = Assembly('later', Box((0, 0, 0), (0, 0, 0)), (Child('solid', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('stone'))),), ports=(Port('access', 'access', Frame(), Box((0, 0, 0), (0, 0, 0))),)) choice = Choice('first', (Child('one', Volume(Box((0, 0, 0), (0, 0, 0)), state_of('stone'))), Child('two', Volume(Box((1, 0, 0), (1, 0, 0)), state_of('stone')))), lambda v, p: 0) wrapper = Assembly('wrapper', Box((0, 0, 0), (3, 1, 1)), (choice, Child('later', later, frame=Frame((3, 0, 0)))), ports=(Port('access', 'access', Frame((3, 0, 0)), Box((3, 0, 0), (3, 0, 0)), delegate=('later', 'access')),)) s = Scene() s.place('root', wrapper) s.finalize() assert s.view.port('/root', 'access').frame.origin == (3, 0, 0) def test_dense_export_budget_is_explicit(work): s = Scene(limits=Limits(export_volume=10)) s.place('line', Volume(Box((0, 0, 0), (10, 0, 0)), state_of('stone'))) with pytest.raises(ContractError, match='export-volume'): export_scene(s, work / 'too large.litematic') assert not (work / 'too large.litematic').exists()
test/test_geometry_environment.py · 243 行 · 原文件
# Actual-geometry damage tests, independent environment sampling and regeneration. from dataclasses import replace, dataclass from pathlib import Path import pytest from hearth import Scene, Box, Frame, Binding, ContractError from hearth.kernel import validate, Capability, Contract, Plan, Port, Grant, Child, Rule from hearth.kernel.scene import Cell from hearth.blocks import state_of, name_of, blockstates_equivalent, validate_state from hearth.environment import Terrain, constant, gradient, wave, radial from hearth.components.building import Building, Blueprint, RoomSpec from hearth.components.primitives import Pool, Volume from hearth.programs import PROGRAMS, building_scene, settlement_scene from hearth.assessment import adaptation_expression, principal_signature from hearth.persistence import export_scene, load_scene, semantic_digest, companion_path, _mcio def damage(scene, p, material=None): scene = scene._fork() old = scene.blocks.get(p) if old: scene.reverse[old.owner].discard(p) scene.blocks.pop(p) if material: owner = old.owner if old else next(n.path for n in scene.nodes.values() if n.type.startswith('room.')) operation = old.operation if old else next(iter(scene.operations)) scene.blocks[p] = Cell(material, owner, operation) scene.reverse[owner].add(p) return scene @pytest.fixture def house(): return building_scene(Blueprint((RoomSpec(0, 0, 0, 'living'), RoomSpec(0, 0, 1, 'bedroom'))), 7, gradient(.04, 0, 4), 6) def test_removed_support_blocked_stair_exit_and_paired_door(house): foundation = next(n for n in house.nodes.values() if n.type == 'adapter.foundation') p = foundation.contract.rules[0].cells[0] assert 'support' in {d.rule for d in validate(damage(house, p), True)} stair = next(n for n in house.nodes.values() if n.type == 'circulation.stair') p = next(r for r in stair.contract.rules if r.kind == 'clear').cells[4] assert 'clearance' in {d.rule for d in validate(damage(house, p, state_of('stone')), True)} door = next(p for p, c in house.blocks.items() if 'spruce_door' in c.state and 'half=lower' in c.state) issues = validate(damage(house, door, state_of('stone')), True) assert {'door-pair', 'reachability'} <= {d.rule for d in issues} assert all(d.component.startswith('/') and d.conditions for d in issues) def test_lights_furniture_seal_and_inventory_are_actual(house): room = '/building/room-0-0-0' s = house for p in house.cells(room, True): if name_of(house.blocks[p].state) == 'lantern': s = damage(s, p) assert 'lighting' in {d.rule for d in validate(s, True)} glass = next(p for p in house.cells(room, True) if name_of(house.blocks[p].state) == 'glass') assert 'enclosure' in {d.rule for d in validate(damage(house, glass), True)} bed = next(p for p, c in house.blocks.items() if name_of(c.state) == 'red_bed') assert 'bed-pair' in {d.rule for d in validate(damage(house, bed), True)} barrel = next(p for p, c in house.blocks.items() if c.nbt) s = house._fork() nbt = dict(s.blocks[barrel].nbt) nbt['Items'] = [{'Slot': 0, 'id': 'minecraft:bread', 'count': 100}] s.blocks[barrel] = replace(s.blocks[barrel], nbt=nbt) assert 'inventory' in {d.rule for d in validate(s, True)} def test_pool_boundary_damage_and_unsupported_substrate(): s = Scene(domain=Box((-3, -3, -3), (14, 20, 14))) s.place('land', Terrain(s.domain, constant(0))) s.place('pool', Pool(), bindings=(Binding('/land', 'construction', 'excavate'),)) assert 'pool-containment' in {d.rule for d in validate(damage(s, (0, 0, 2)), True)} def test_nbt_roundtrip_and_real_schematic_mismatch(house, work): path = work / 'inventory and spaces.litematic' export_scene(house, path) restored = load_scene(path) assert semantic_digest(restored) == semantic_digest(house) assert {p: c.nbt for p, c in restored.blocks.items() if c.nbt} == {p: c.nbt for p, c in house.blocks.items() if c.nbt} _, _, tag, nbtfile = _mcio() nbt = nbtfile.load_regardless_of_gzipped(filename=path) region = next(iter(nbt['Regions'].values())) region['TileEntities'][0]['Items'][0]['count'] = tag.Int(7) nbtfile(nbt).save(path) with pytest.raises(ContractError, match='geometry-mismatch'): load_scene(path) companion_path(path).unlink() with pytest.raises(ContractError, match='untrusted-structure'): load_scene(path) @pytest.mark.parametrize('environment_seed', range(16)) @pytest.mark.parametrize('building_seed', range(4)) def test_64_frozen_independent_pairings(environment_seed, building_seed): field, water = adaptation_expression(environment_seed) domain = Box((-8, -4, -18), (34, 64, 34)) s = Scene(building_seed, domain=domain) s.place('ground', Terrain(domain, field, water)) before = {p: c.state for p, c in s.blocks.items()} # An existing protected environmental observation outside all building edits. protected = (32, s.view.elevation(32, 32), 32) from hearth.components.primitives import Assembly s.place('preserved', Assembly('protected-soil', Box(protected, protected), (), (Rule('expected', (protected,), data={'names': [name_of(s.blocks[protected].state)]}),))) design = PROGRAMS['dwelling'](building_seed) s.place('house', Building(design, '/ground')) s.finalize() assert s.nodes['/house'].contract.decisions['rooms'] == [(r.x, r.z, r.level, r.purpose) for r in design.normalized()] allowed = set() for path, old in s.displaced.items(): if path.startswith('/house/'): allowed.update(old) assert all(s.nodes[path].contract.envelope.contains(p) for p in old) assert all(p in allowed or (p in s.blocks and s.blocks[p].state == material) for p, material in before.items()) assert s.blocks[protected].state == before[protected] assert s.nodes['/house/approach'].contract.decisions['rows'] assert all(s.view.supports(p) for p in s.nodes['/house/foundation'].contract.rules[0].cells) def test_environment_implementation_substitution_and_public_forwarding(): @dataclass(frozen=True) class IndependentField: def __call__(self, x, z): return 4 + 0.01 * x - 0.01 * z def expression(self): return {'polynomial': [4, .01, -.01]} @dataclass(frozen=True) class WrappedEnvironment: domain: Box def capability(self): return Capability('extension.environment', ('environment', 'composite')) def negotiate(self, c, p): ports = tuple(Port(key, key, Frame(self.domain.lo), self.domain, 100000, delegate=('strata', key)) for key in ('construction', 'planting')) return Contract(self.domain, ports=ports) def realize(self, c, b): return Plan(children=[Child('strata', Terrain(self.domain, IndependentField()))]) domain = Box((-8, -4, -18), (30, 50, 30)) s = Scene(2, domain=domain) s.place('world', WrappedEnvironment(domain)) s.place('house', Building(Blueprint((RoomSpec(0, 0, 0, 'living'),)), '/world')) s.finalize() assert s.view.port('/house', 'street').delegate == ('approach', 'street') assert any(d['source'] == '/world' for d in s.dependencies) def test_environment_dependency_regeneration_is_explicit_and_atomic(): domain = Box((-8, -4, -18), (28, 55, 28)) s = Scene(3, domain=domain) s.place('land', Terrain(domain, constant(3))) design = Blueprint((RoomSpec(0, 0, 0, 'living'), RoomSpec(0, 0, 1, 'bedroom'))) s.place('house', Building(design, '/land')) before = semantic_digest(s) with pytest.raises(ContractError): s.regenerate('/land', Terrain(domain, constant(4))) assert semantic_digest(s) == before old_floor = s.nodes['/house'].contract.decisions['floor'] s.regenerate('/land', Terrain(domain, constant(4)), dependents=('/house',)) assert s.nodes['/house'].contract.decisions['floor'] == old_floor + 1 assert not any(n.stale for n in s.nodes.values()) assert all(p in s.blocks for cells in s.reverse.values() for p in cells) @pytest.mark.parametrize('program', tuple(PROGRAMS)) @pytest.mark.parametrize('seed', range(8)) def test_three_composition_programs(program, seed): s = building_scene(PROGRAMS[program](seed), seed) assert s.completed and any(n.type.startswith('room.') for n in s.nodes.values()) @pytest.mark.parametrize('seed,count', [(i, None) for i in range(8)] + [(0, 3), (0, 6)]) def test_settlement_corpus_and_boundaries(seed, count): s = settlement_scene(seed, count) assert s.completed buildings = [n for n in s.nodes.values() if n.type == 'building.rooms'] assert len(buildings) == count if count else 3 <= len(buildings) <= 6 route = next(n for n in s.nodes.values() if n.type == 'settlement.connections') assert len(route.contract.rules[0].cells) == len(buildings) + 2 def test_blockstate_explicit_semantics_and_rotation(): assert blockstates_equivalent('minecraft:oak_log[axis=x]', 'minecraft:oak_log[axis=x]') assert not blockstates_equivalent('minecraft:oak_log', 'minecraft:oak_log[axis=y]') assert not blockstates_equivalent('minecraft:oak_log[axis=x]', 'minecraft:oak_log[axis=z]') assert not blockstates_equivalent('minecraft:oak_log[axis=x]', 'minecraft:spruce_log[axis=x]') with pytest.raises(ValueError): validate_state('minecraft:stone[facing=north]') for turn in range(4): validate_state(Frame(turn=turn).state('minecraft:rail[shape=north_east,waterlogged=false]')) def test_complete_settlement_transforms_and_public_gateway(): from hearth.programs import Settlement, dwelling, atelier local = Box((-49, -4, -23), (49, 64, 66)) frame = Frame((150, 2, 80), 1) s = Scene(0, domain=frame.box(local)) s.place('land', Terrain(s.domain, constant(4))) s.place('district', Settlement((dwelling(1), atelier(1), dwelling(4)), local, '/land'), frame=frame) s.finalize() ports = s.view.offers('/district', 'public-access') assert len(ports) == 1 and ports[0].frame.turn == 1 assert ports[0].frame.origin == frame.point((0, 3, -12)) assert s.view.capability('/district/plot-0').inputs['design.bay'].accepts(9) assert any(d['reason'] == 'observed-spatial-input' for d in s.dependencies) def test_actual_subsurface_support_not_just_height(): domain = Box((-8, -4, -18), (28, 55, 28)) s = Scene(0, domain=domain) s.place('ground', Terrain(domain, constant(4))) s.place('local-cavity', Volume(Box((2, 3, 2), (2, 3, 2)), state_of('air'), 'siteworks'), bindings=(Binding('/ground', 'construction', 'excavate'),)) assert s.view.elevation(2, 2) == 4 and s.view.sample(2, 2).support_depth == 1 before = semantic_digest(s) with pytest.raises(ContractError, match='substrate-depth'): s.place('house', Building(Blueprint((RoomSpec(0, 0, 0, 'living'),)), '/ground')) assert semantic_digest(s) == before def test_path_endpoint_respects_host_authority(): from hearth.components.landscape import PathNetwork from hearth.components.primitives import Assembly domain = Box((-4, -3, -4), (12, 20, 12)) s = Scene(0, domain=domain) s.place('ground', Terrain(domain, constant(0))) # An unrelated solid host behind the offered endpoint must survive path widening. s.place('behind', Volume(Box((-1, 1, -1), (-1, 1, 1)), state_of('stone'))) s.place('route', PathNetwork(((0, 1, 0), (8, 1, 0)), ((0, 1),)), bindings=(Binding('/ground', 'construction', 'surface'),)) assert s.cells('/behind') == {(-1, 1, -1), (-1, 1, 0), (-1, 1, 1)} s.finalize() def test_upper_room_bay_boundary_with_vertical_circulation(): design = Blueprint((RoomSpec(0, 0, 0, 'living'), RoomSpec(0, 0, 1, 'bedroom')), bay=13) s = building_scene(design, 5, gradient(base=4), 6) assert s.completed and s.nodes['/building'].contract.decisions['bay'] == 13 assert s.nodes['/building/room-0-0-0/stairs'].contract.rules
test/test_kernel.py · 122 行 · 原文件
# Foundation tests run before extending architectural content. from dataclasses import dataclass import pytest from hearth import Scene, Box, Frame, Binding, ContractError from hearth.kernel import Capability, Contract, Plan, Child, Rule from hearth.components.primitives import Assembly, Volume, Wall, Window, Grass, Tree, Pool from hearth.environment import Terrain, constant from hearth.blocks import state_of, blockstates_equivalent from hearth.persistence import export_scene, load_scene, semantic_digest def land(): s = Scene(12, domain=Box((-10, -3, -10), (20, 25, 20))) s.place('terrain', Terrain(s.domain, constant(0))) return s def test_composite_attachment_automatic_chain(): s = Scene(4) children = (Child('base', Volume(Box((0, 0, 0), (8, 0, 0)), state_of('stone'))), Child('wall', Wall(), frame=Frame((0, 1, 0))), Child('window', Window(), frame=Frame((2, 2, 0)), bindings=(Binding('/house/wall', 'infill'),))) s.place('house', Assembly('house', Box((-1, 0, -2), (10, 8, 3)), children)) q = s.inspect((2, 2, 0)) assert [n['type'] for n in q['chain']] == ['window.shuttered', 'wall.framed', 'house'] assert len(s.cells('/house/window')) == 10 assert s.cells('/house/window') <= s.cells('/house', True) def test_substitution_same_parent(): def parent(window): return Assembly('room', Box((-1, -1, -2), (10, 8, 3)), (Child('base', Volume(Box((0, -1, 0), (8, -1, 0)), state_of('stone'))), Child('wall', Wall()), Child('window', window, frame=Frame((2, 1, 0)), bindings=(Binding('/room/wall', 'infill'),)))) a, b = Scene(), Scene() a.place('room', parent(Window())) b.place('room', parent(Window(shutters=False))) assert semantic_digest(a) != semantic_digest(b) assert a.nodes['/room/window'].contract.envelope == b.nodes['/room/window'].contract.envelope def test_tree_grass_and_pool_preserve_support(): s = land() s.place('grass', Grass(), frame=Frame((0, 1, 0)), bindings=(Binding('/terrain', 'planting', 'plant'),)) s.place('tree', Tree(), frame=Frame((0, 1, 0)), bindings=(Binding('/terrain', 'planting', 'plant'), Binding('/grass', 'replacement', 'plant'))) assert '/grass' not in s.nodes assert s.inspect((0, 1, 0))['instance'] == '/tree' before = semantic_digest(s) nodes = set(s.nodes) ops = set(s.operations) with pytest.raises(ContractError): s.place('pool', Pool(), frame=Frame((-2, 0, -2)), bindings=(Binding('/terrain', 'construction', 'excavate'),)) assert semantic_digest(s) == before and set(s.nodes) == nodes and set(s.operations) == ops with pytest.raises(ContractError): s.place('grass2', Grass(), frame=Frame((0, 1, 0))) s.place('pool-ok', Pool(), frame=Frame((6, 0, 6)), bindings=(Binding('/terrain', 'construction', 'excavate'),)) s.finalize() def test_tall_grass_whole_object_and_no_tree_excavation(): s = land() s.place('grass', Grass(True), frame=Frame((0, 1, 0))) with pytest.raises(ContractError): s.place('ordinary-tree', Tree(), frame=Frame((0, 0, 0)), bindings=(Binding('/terrain', 'construction', 'excavate'),)) s.place('tree', Tree(), frame=Frame((0, 1, 0)), bindings=(Binding('/grass', 'replacement', 'plant'),)) assert '/grass' not in s.nodes def test_transforms_and_persistence(work): frame = Frame((14, 3, -7), 1) s = Scene(-42) s.place('beam', Volume(Box((0, 0, 0), (2, 0, 0)), state_of('oak_log', axis='x')), frame=frame) assert s.inspect((14, 3, -5))['state'] == state_of('oak_log', axis='z') path = work / 'space name.litematic' export_scene(s, path) restored = load_scene(path) assert restored.inspect((14, 3, -5)) == s.inspect((14, 3, -5)) assert blockstates_equivalent('minecraft:oak_stairs[facing=north,half=bottom]', 'minecraft:oak_stairs[half=bottom,facing=north]') assert not blockstates_equivalent('minecraft:oak_log', 'minecraft:oak_log[axis=y]') import json meta = path.with_suffix('.litematic.structure.json') data = json.loads(meta.read_text()) data['digest'] = 'bad' meta.write_text(json.dumps(data)) with pytest.raises(ContractError, match='geometry-mismatch'): load_scene(path) def test_clearance_rollback_and_bounds(): s = Scene() s.place('stairs', Assembly('circulation', Box((0, 0, 0), (3, 5, 3)), (), (Rule('clear', ((1, 2, 1), (1, 3, 1))),))) with pytest.raises(ContractError, match='clearance'): s.place('decoration', Volume(Box((1, 3, 1), (1, 3, 1)), state_of('stone'))) assert set(s.nodes) == {'/stairs'} and not s.blocks @dataclass class Escaper: def capability(self): return Capability('bad', ()) def negotiate(self, c, p): return Contract(Box((0, 0, 0), (0, 0, 0))) def realize(self, c, b): p = Plan() p.block((1, 0, 0), state_of('stone')) return p with pytest.raises(ContractError, match='envelope'): s.place('bad', Escaper()) def test_seed_stability_and_regeneration(): from hearth.randomness import Scope a = Scope(123).child('house') before = a.stream('layout').getrandbits(64) Scope(123).child('failed').stream().random() assert before == a.stream('layout').getrandbits(64) s = Scene() s.place('beam', Volume(Box((0, 0, 0), (2, 0, 0)), state_of('stone'))) s.regenerate('/beam', Volume(Box((0, 0, 0), (1, 0, 0)), state_of('oak_planks'))) assert s.inspect((2, 0, 0))['instance'] is None assert len(s.cells('/beam')) == 2

原始运行:runs/proc/proc-compose/astra-max-kokemeow;只读归档:runs/archive/proc-proc-compose-astra-max-kokemeow-attempt-0001。报告由原始文件和单独保存的复验记录生成。样本有限、渲染非仿真、接口语汇有边界;新的使用场景仍需要自己的契约、负例与生成证据。