5586f87f43
Translate one-based public shard numbers to mutest's zero-based API, retain requested labels in output paths, and grant compiler-probe tests a 120-second per-mutant floor. Corrected hemx-build shard 1/8 now passes. req: test/022 req: test/023
18 KiB
18 KiB
hemx — AGENTS.md
Purpose
This file tells coding agents how to work in this repository. It is a durable operating contract, not a generated inventory.
Keep it stable. Prefer pointers to canonical sources over copied structure, file lists, metrics, architecture maps, command inventories, or status snapshots.
Agent workflow
- Start from product intent and requirements; inspect code only after the target behavior is clear.
- For v1 work, read
docs/v1-product-evidence.md, thenREQUIREMENTS.md; usePLAN.mdonly as the mutable implementation cursor. - Read
REQUIREMENTS.mdbefore changing behavior. - If behavior changes, update
REQUIREMENTS.mdin the same change. - If implementation work does not change durable product obligations, acceptance, safety/recovery behavior, or verification duties, say
REQUIREMENT IMPACT: nonein the handoff and why. - Cite relevant requirements in code, tests, or docs as
req: <component>/001. - Do not add citation-only padding to satisfy tooling; cite only where the requirement constrains the text.
- Use requirement tags consistently: stable area tags like
[parser],[auth],[ui]; temporary planning tags like[bootstrap],[mvp], or[milestone-1]only while they are useful. - Run
redgate list,redgate refs, andredgate healthwhen requirements change; includeredgate lintwhen the change is meant to reduce requirement maintainability warnings.
Git workflow
- Commit complete, coherent slices only; do not commit broken work or temporary debug output.
- Use Conventional Commits:
type(scope): summary. - Keep commit subjects readable; requirement IDs do not have to be in the subject.
- Every behavior-changing or requirement-changing commit should cite relevant requirement IDs in the commit body or trailers using
req: <component>/001. - Use commit history for evolution:
git log --grep 'req: parser/012'should find the commits that changed that behavior. - Use the current tree for state:
REQUIREMENTS.md, citations, tests, andredgate healthdescribe what is true now. - Before committing requirement or behavior changes, run relevant tests and the strongest
redgate healthmode supported by the installed tool. Do not invent an unsupported--strictflag; report a tool/format mismatch explicitly.
Requirements-first TDD
- Write requirements as desired behavior, not as a snapshot of current behavior.
- Keep each requirement row to one checkable obligation with an explicit redgate ring field; shorten near-limit rows or split oversized examples, escape hatches, or negative cases into separate stable IDs while preserving the original ID's main intent.
- First split intent into broad error classes: what can go wrong, and what outcome must hold.
- Test the largest risky classes before narrow examples.
- Add adversarial tests for malformed, hostile, ambiguous, missing, duplicated, and boundary inputs.
- Do not over-codify existing behavior while direction is still moving.
- Add narrow concrete tests only after requirements converge into a stable direction.
Redgate CLI
redgate list— show requirements as TSV.redgate refs— showreq:citations found in the repo.redgate health— show uncited requirements, duplicate IDs, and stale citations.redgate lint— show maintainability warnings such as missing rings and oversized requirement rows; when fixing one row in a section, normalize nearby rows with the same warning if it stays a requirement-only cleanup.redgate refs— with the installed CLI, parse the elected requirement format and audit repository citations;redgate healthadditionally enforces a newer prescriptive-row style not yet elected by this requirements corpus.redgate agents— print this starter template; review, shrink, and edit before committing.
Local guidance
- Add only durable style, ownership, gotchas, and at most a few stable commands agents should actually run.
- Prefer links or pointers to canonical sources over copied lists.
- Avoid project trees, architecture maps, generated inventories, current file sizes, issue lists, TODO inventories, and other snapshots that will rot.
- Stable commands:
cargo run -p hemx-xtask -- test,cargo run -p hemx-xtask -- mutation [PACKAGE] [SHARD/TOTAL],cargo run -p hemx-xtask -- html-examples-smoke,cargo check --workspace,redgate refs. Use the xtask runner for full verification so jobs are capped from local CPU and memory and commands resolve the workspace independently of the caller's directory; use the html_examples smoke for focused repo-owned browser verification of the HTML pattern gallery, no-reload dynamic interactions, and no/tmpscripts. Keep fast crate tests, focused browser smoke, and full xtask authority distinct; mutation shards use one-based1..=TOTALnumbering and allow the wrapper's 120-second floor for repo-owned compiler probes. The full path should stay within a documented 10 minute local timeout or use every deterministic mutation shard under the same wrapper. req: test/004 req: test/006 req: test/012 req: test/013 req: test/014 req: test/015 req: test/016 req: test/022 req: test/023 - Example behavior tests should prefer
hemx_testgenerated-resource assertion methods over raw slot constants, raw effect/payload matching, or boolean predicates wrapped in opaqueassert!; failures should include the expectation and actual effects, while rendered target/handle assertions should name the generated resource. Keep browser selector helpers as test adapters only, not authoring APIs. Process-backed tests use the RAIITestProcessharness rather than duplicating readiness loops and child cleanup. req: test/008 req: test/009 req: test/010 req: test/017 req: test/018 req: test/019 - Run the workout product exemplar with
cargo run -p hemx-xtask -- workout devand openhttp://127.0.0.1:3028; setHEMX_WORKOUT_ADDR=127.0.0.1:3030if the default port is busy. Its durable visual direction and recovery expectations live inexamples/workout/DESIGN.md. req: examples/008 - Use the same Workout command surface for tests, production build, and mobile release:
cargo run -p hemx-xtask -- workout test,cargo run -p hemx-xtask -- workout build,HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-release, andHEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-verify; Android/iOS SDKs, store submission targets, and signing remain external blockers, not repo-owned secrets, and do not imply a broadhemx-mobileframework. req: examples/006 req: examples/011 req: examples/013 - hemx core stays small: effects, typed ids, registries, and wire schema only; keep features in core only when they fit typed resources plus the closed EffectBatch op set, and treat DOM details as runtime lowering. Workspace crates stay separated, stable-Rust-compatible, and free of kitchen-sink boundaries; new primitives must delete special cases. Public identifiers should flow through typed wrappers over internal
ResourceId/ResourceRef, not special-case opcodes. Wire output lowers symbolic authoring names to compact metadata, the versioned canonical hemxEffectBatchcodec, postcard surface facts, and form-encoded public requests—not JSON. ABI/schema versions and build fingerprints must guard runtime/server compatibility. v0 scope is the checked hypermedia core plus page/runtime/wire/diagnostic/test/axum proof, not optional sync/wasm/query/auth/router breadth. req: v0_scope/001 req: v0_scope/002 req: v0_scope/005 req: laws/001 req: invariant/001 req: invariant/005 req: typed_id/001 req: typed_id/003 req: effect_algebra/001 req: effect_algebra/006 req: wire/001 req: wire/002 req: wire/003 req: wire/004 req: wire/005 req: wire/006 req: abi/001 req: abi/002 req: abi/003 req: abi/004 req: abi/005 req: misc/001 req: misc/002 req: misc/003 req: misc/004 req: misc/005 req: misc/006 req: misc/007 req: misc/008 req: misc/009 req: misc/010 - Routing, auth, sessions, transport, transitions, sync, async data helpers, multipart parsing/uploads, and storage belong in integration/user crates; hemx-axum preserves normal HTTP auth, credentials, CSRF, multipart/browser fallback, and progressive-enhancement semantics rather than defining policy in core. Sync is optional integration state reconciliation over push/transport, not core. req: auth/001 req: auth/002 req: auth/003 req: auth/004 req: auth/005 req: async_data/001 req: async_data/002 req: async_data/003 req: multipart/001 req: multipart/002 req: multipart/003 req: sync/001 req: sync/008
- Public examples and beginner APIs should use templates plus Rust, generated component APIs, resources, view wrappers, render/page helpers,
#[hemx::app], plain#[hemx::handler]functions, andIntoEffect, not atoms, raw ids, selectors, wire formats, runtime opcodes, manual registries,$OUT_DIRincludes, raw render/lower calls, raw HTML construction, imperative DOM mutation, or raw effect constructors; keep advanced layers out of starters. req: canonical_authoring/001 req: canonical_authoring/004 req: canonical_authoring/006 req: canonical_authoring/010 req: canonical_authoring/015 req: invariant/003 req: dx/001 req: dx/002 req: dx/010 req: component/003 req: component/004 req: component/005 req: view/001 req: view/002 req: view/003 req: html_safety/001 req: html_safety/003 req: html_safety/005 req: public_api/001 req: public_api/002 req: public_api/003 req: public_api/005 req: public_api/006 req: progressive_disclosure/001 req: progressive_disclosure/002 req: progressive_disclosure/003 req: derive_app/001 req: derive_app/002 req: derive_handler/001 req: derive_handler/002 req: derive_handler/003 req: derive_handler/004 req: derive_handler/005 - Typed partial swaps should stay expressed as generated target plus rendered partial plus swap kind, not selector-driven rerendering or response-side selector retargeting; HTTP, page navigation, push, and island behavior adapt around that loop, and docs should layer new primitives progressively. Navigation is an effect/page-swap concern, not a core router framework; enhanced links and GET forms preserve real URL/history semantics so page state stays reloadable/shareable without a client state graph. Push streams carry canonical versioned hemx
EffectBatchbytes over server-owned SSE/WebSocket transport and keepdata-hemx-sseroot-scoped/same-origin by default. Preserve keyed/optional scope identity for addressable loop nodes, reconcile filtered keyed collections without clearing retained rows, prefer generated keyed-slot helpers over low-level keyed calls, and route self/row-update diagnostics toward localdata-hemx-slot/h-keytargets. req: canonical_authoring/002 req: canonical_authoring/014 req: modes/001 req: scope/001 req: list/001 req: list/002 req: list/003 req: list/004 req: list/005 req: list/006 req: nav/001 req: nav/002 req: nav/003 req: nav/004 req: nav/005 req: push/001 req: push/002 req: push/003 req: push/004 req: push/005 req: push/006 req: push/007 req: progressive_disclosure/004 req: page_swap/001 req: page_swap/002 req: page_swap/003 req: locality/001 req: locality/002 req: target_policy/001 req: target_policy/002 examples/html_examplesis the copy-paste HTML pattern gallery for htmx-style examples; keep exact htmx URL slugs visible while translating behavior to boring.heml, generated resources, and server-owned Rust state, not HTMX syntax, selector targeting, or user-authored browser JavaScript. Shared runtime loading and declarativedata-hemx-*are allowed. Boost containers enhance same-origin descendants only and preserve native external/download/new-tab behavior. req: htmx_equivalents/001 req: htmx_equivalents/003 req: htmx_equivalents/005 req: examples/005 req: examples/007 req: examples/012 req: page_swap/007 req: page_swap/008- Use
cargo run -p hemx-xtask -- app new PATHfor the generic page/form/keyed-row/notice starter, andcargo run -p hemx-xtask -- app new --mobile PATHfor the phone-first starter with host capabilities, recovery truth, and release-kit commands; do not treat it as a mobile framework or store-submission bot. req: ceremony/005 req: ceremony/006 req: ceremony/007 - The public component-reuse explanation lives in
docs/recipes/reusable-partials.md; do not grow a client component framework to explain partial composition. - The stable public
.hemlauthoring surface lives indocs/hemplate-syntax.md; Hemlate examples must use that real hemplate syntax, not Vue/Handlebars sketches. hemx-build consumes hemplate Surface facts and must not grow an independent.hemlparser or CSS-path identity model. Plain CSS/SCSS owns appearance; generated class constants are ergonomic references, not a styling framework or behavior selector system. Generated resources, form/handle metadata, atoms, and event constants come from hemx-build facts, not hand-written app plumbing. Forms remain HTML-shaped, checked against user-authored Rust domain types, parsed throughFormValue, and manipulated through generated form/control ids rather than selectors. Proc-macros stay local/side-effect-free while build.rs owns global codegen and hard build failures. No-op global codegen must preserve generated artifact timestamps so downstream Rust compilation remains fresh only when canonical output changes. req: boundary/001 req: boundary/002 req: boundary/003 req: boundary/004 req: surface/001 req: surface/002 req: surface/003 req: surface/004 req: surface/005 req: surface/006 req: surface/007 req: surface/008 req: surface/009 req: surface/010 req: codegen/001 req: codegen/003 req: codegen/004 req: codegen/005 req: codegen/006 req: form/001 req: form/004 req: form/007 req: form/008 req: form_effects/001 req: form_effects/002 req: form_effects/003 req: build/001 req: build/002 req: build/003 req: build/004 req: build/005 req: build/006 req: build/007 req: build/008 req: build/009 req: style/001 req: style/002 req: style/003 req: style/004 req: style/005 req: style/006 - Optional
.hemleditor overlays must share authority withhemx-builddiagnostics anddocs/hemplate-syntax.md;hemx-lspowns editor protocol glue for diagnostics/completion/hover and derive-known template facts, while VS Code/Cursor/Neovim keep normal HTML/tree-sitter tooling. Simpleh-forcompletion facts cover one Rust identifier bound directly to aselfvector field; malformed bindings and non-vector fields must not fabricate locals. Do not create a second template language, selector model, formatter, Rust type system, or custom editor framework. Compiler diagnostics with directive/target metadata select that source attribute instead of line 0 column 0. Cross-file template/handler references visible to build validation must fail atcargo checkwith useful spans; global completeness checks stay component-scoped unless caught at mount/tests. req: diagnostics/004 req: diagnostics/005 req: diagnostics/006 req: diagnostics/007 req: diagnostics/008 req: diag/009 req: diag/010 req: invariant/004 req: invariant/006 req: check/001 req: check/003 - JS runtime changes must preserve root-scoped lookup, delegated listeners, canonical hemx
EffectBatchapplication, fail-closed request handling, transactional/recoverable failure behavior, root-scoped error outlets, and tiny pending/failure/trigger-timing conventions without selectors, handler-name parsing, VDOM, expressions, or per-node listeners. Runtime.d.tstypes are developer convenience only, not core tooling authority. req: invariant/002 req: runtime/001 req: runtime/002 req: runtime/003 req: runtime/005 req: runtime/006 req: failure/001 req: failure/002 req: failure/003 req: failure/004 req: failure/005 req: failure/006 req: convention/001 req: convention/002 req: convention/003 req: convention/004 req: convention/005 req: convention/006 req: convention/007 req: convention/008 req: convention/009 req: convention/010 req: convention/011 req: convention/012 req: convention/013 req: convention/014 req: convention/015 req: convention/016 req: convention/017 req: ts/001 - Opaque island JavaScript is a leaf adapter for high-frequency local behavior only; client-local handlers keep the server-handler shape while
hemx-wasmowns concrete opt-in syntax. Use native events/generated helpers at the boundary and do not introduce a component runtime, client state graph, VDOM, selector interop, or second UI model. req: canonical_authoring/017 req: client_local/001 req: client_local/003 req: client_local/004 req: interop/001 req: interop/002 req: interop/003 req: interop/006 req: interop/007 req: interop/008 req: interop/009 req: interop/010 req: interop/011 req: interop/012 - Host capability adapters must stay at the
hemx-hostboundary: typed capabilities use fire/request/stream/schedule shapes; adapters may call host APIs and return host events, but they must not mutate DOM or own app/domain state. req: host/001 req: host/002 - Local/offline app behavior should be commands/events/projections; do not add
hemx-local, stored DOM patches, storedEffectBatchtruth, or a core client state graph without a proven reusable contract. Atoms are explicit addressable/bootstrap/sync resources, not the default state container or a reactive framework. Replay, reconciliation, export, and deletion rules stay explicit product decisions, and exemplars should show UI effects as app-state output. The local-first multiplayer kanban remains an advanced north-star integration milestone, not beginner/API surface scope. req: canonical_authoring/018 req: canonical_authoring/019 req: state/001 req: state/002 req: state/003 req: state/004 req: state/005 req: state/006 req: state/007 req: local/001 req: local/002 req: local/003 req: local/004 req: milestone/001 req: milestone/002 req: milestone/003 - Axum 0.8 apps should serve and load the shared runtime through hemx-axum helpers such as
runtime_js_path()andruntime_js(), not hard-coded/hemx.jsURLs or app-owned cache-busting strings; keep hemx-axum as route/runtime/handler adapter around generated partial swaps, not a routing owner. req: axum/002 req: axum_integration/001 req: axum_integration/002 req: axum_integration/003 req: axum_integration/005 req: axum_integration/006