Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { angular } from "@angular-wave/angular.ts";
import { WasmScopeAbi } from "@angular-wave/angular.ts/services/wasm";
import { WasmAbi } from "@angular-wave/angular.ts/services/wasm";
import { GoWasmScopeAbi } from "../go-wasm-scope-abi.js";
import "../wasm_exec.js";

const moduleName = "goWasmTodo";
const requires = [];
const manifest = {"registrations":[{"kind":"controller","name":"goTodoController","export":"__ng_controller_GoTodoController","scopeName":"goTodo:main","methods":["add","toggle","archive"],"fields":[{"name":"items","goName":"items","goType":"[]main.Todo"},{"name":"remainingCount","goName":"remainingCount()","goType":"int"},{"name":"newTodo","goName":"newTodo","goType":"string"},{"name":"titleSeen","goName":"titleSeen","goType":"string"}],"watches":[{"path":"newTodo","handler":"onNewTodoChanged","goType":"string"}]}]};

const scopeAbi = new WasmScopeAbi();
const scopeAbi = new WasmAbi.ScopeAbi();
const goScopeAbi = new GoWasmScopeAbi(scopeAbi);

globalThis.__angularTsGoWasmScopeAbi = goScopeAbi;
Expand Down
127 changes: 124 additions & 3 deletions src/DESIGN_PHILOSOPHY.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ declarative and safer.

AngularTS APIs should make the user's intent obvious.

Machine, workflow, and router APIs follow the durable API ergonomics contract
below. Public types belong in the `ng` namespace only when users encounter and
need documentation for them.

Preferred user paths:

- declare app structure through `NgModule`
- declare shared reactive state through `app.model(...)`
- declare service config through service-owned config
- declare third-party modules through `app.use(plugin, config)`
- declare third-party modules through `angular.module(...)` and module
dependencies
- declare operational behavior through policies
- consume runtime services through injection

Expand Down Expand Up @@ -165,6 +170,109 @@ Public surface should avoid:
Compatibility can preserve old paths during migration, but documentation should
teach the stable user path first.

## API Ergonomics Contract

Machine, workflow, and router ergonomics are governed by a no-new-runtime-API
rule: simplify authoring, inference, naming, documentation, and exported types
before adding another runtime method, helper, directive, or test API.

The common authoring path starts from one object literal and does not require
explicit generic parameters. TypeScript should infer state names, route names,
event names, command names, payloads, params, and resolves from that literal
and preserve them through named module registration.

### Runtime Vocabulary

| Name | Meaning |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `send` | Deliver a typed event to a machine or workflow state engine. It does not start workflow commands or router navigation. |
| `run` | Start a named workflow command and return its asynchronous command result. |
| `go` | Navigate to a named router state through `$state.go(...)`. |
| `transition` | The router navigation lifecycle and its evidence object. Machine and workflow event delivery uses `send(...)`; application navigation uses `$state.go(...)`. |
| `status` | A stable result or runtime-state discriminator intended for application control flow. |
| `snapshot` | Capture documented durable evidence without executable callbacks, adapters, or framework internals. |
| `restore` | Apply a compatible snapshot to an existing runtime object while preserving its reactive identity. |

Different verbs are intentional. `machine.send(...)` handles an event,
`workflow.run(...)` starts a command, and `$state.go(...)` starts navigation.
Using one generic dispatch verb for all three would erase meaningful lifecycle
and result differences.

### Outcomes And Evidence

| Boundary | Control flow | Evidence |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
| `machine.send(...)` | Branch on `ok`, then use `status` to distinguish `transitioned`, `updated`, missing, invalid, guard-denied, or policy-denied outcomes. | The result describes the attempted transition. Machines do not accumulate diagnostics. |
| `workflow.run(...)` | Branch on `ok`, then use settled `status` values: `completed`, `failed`, `cancelled`, `timeout`, or `rejected`. Queueing is execution policy, not a returned outcome. | Diagnostics and bounded history explain failures and support retry, repeat, snapshots, and recovery. |
| `$state.go(...)` | Await the `TransitionPromise`; fulfillment and rejection are the asynchronous navigation branches. | The attached `Transition` records success, error, redirects, and lifecycle detail after settlement. |
| `policy.check(...)` | Branch on the decision `type`. Common gate policies use `allow`, `deny`, and `redirect`; specialized policies use domain terms such as `deliver`, `drop`, or cache strategies. | Optional reason, status, target, error, and metadata explain the decision. |

Diagnostics are evidence, not a substitute for `ok`, `status`, Promise
settlement, or policy decision `type`. Specialized policy decision types remain
separate because a cache strategy and an authorization gate do not have the
same semantics.

Snapshots contain durable state and evidence only. They must not contain live
scopes, callbacks, adapters, promises, abort controllers, DOM nodes, or runtime
registries. Restore applies snapshot state to an existing runtime; it does not
revive in-flight commands, hooks, retained views, or external resources.

### Public Type Placement

The ambient `ng` namespace contains types users encounter while authoring an
app or consuming injected runtime objects: declarations, config, callback
arguments that need explicit annotation, runtime services, results, statuses,
snapshots, diagnostics, and supported extension contracts.

The main package entry point contains the ordinary authoring functions and the
runtime/evidence types needed by the common path. Advanced adapters, protocol
messages, mapped inference helpers, and reusable package-author contracts use
direct module imports. Implementation-only mapped types, registries, provider
recipes, and proxy machinery are not public exports.

A type is not hidden merely because its name is verbose. Return values, config
values, callback arguments, snapshots, results, diagnostics, and extension
contracts remain documented wherever users encounter or implement them.

### Registration Inference

| Registration | Inference rule |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `app.machine(name, definition)` | Preserve data, event, payload, and state-name information from the machine definition or injectable definition factory. |
| `app.workflow(name, definition)` | Preserve data, event, command, command input/output, and state-name information from the workflow definition or injectable definition factory. |
| `module.router(tree)` | Infer the route map from the literal route tree and return a typed router module carrying that map. |
| `module.router(...)` | Preserve the route map already carried by a typed router module and reject names, params, or resolves outside that map. A route tree registered on an untyped module infers its contract from the declaration. |
| `module.lazyState(prefix, loader)` | Preserve the typed router module's route map and constrain the lazy prefix to a declared lazy boundary. The loader does not silently widen the known route map. |

Named registration must not make ordinary users repeat generic arguments that
were available at the declaration site.

### Policy Attachment

Policy uses existing config ownership boundaries:

| Primitive | Attachment point |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Machine | Transition admission policy is the machine definition's `policy` field; guards and hooks stay on the transition or machine definition that owns them. |
| Workflow | Command timeout and concurrency stay on `WorkflowConfig` or per-run options. Persistence and recovery stay on `WorkflowSupervisorConfig` through `persistence`, `persistencePolicy`, and `recovery`. |
| Router | App-wide defaults stay in `$router` config. Route-subtree navigation, transition, and retention policy stays under `StateDeclaration.policy` and inherits through the route tree. |

Machine, workflow, and router do not gain a second generic policy registry.
Configuration remains declarative and local to the primitive that executes the
decision.

### State Terminology

A machine or workflow `state` is an execution mode in that primitive's local
`states` map. A router state is a named navigation node with views, params,
resolves, and URL behavior. A route tree is the hierarchical module declaration
made from router states.

Router documentation retains “state” because it is the established router
runtime term (`$state`, `StateDeclaration`, and `$transitions`). It uses “route
tree” for module-level hierarchy and always says “router state” where confusion
with machine or workflow state is plausible.

## Type Safety

Configuration and extension APIs should be type-safe.
Expand All @@ -173,7 +281,7 @@ Type safety should:

- reject unknown config keys
- reject invalid config fields
- infer model and plugin config types
- infer model and module-local config types
- prevent root-scoped dependencies from leaking into app-owned factories where
possible
- avoid exposing internal implementation types just to make the compiler happy
Expand All @@ -190,8 +298,9 @@ A stable AngularTS API needs:
- generated public docs
- a clear service or concept guide
- executable or testable samples
- 100% test coverage for new modules
- migration notes when replacing older paths
- public type inventory classification
- a named, documented contract for every public injectable
- clear ownership and lifecycle guidance

If users can see or import a public API, they should be able to find what it is
Expand All @@ -211,6 +320,17 @@ Before adding or keeping an API, ask:
- does this expose only the types users need?
- can it be documented with an executable or testable sample?

For security policy features, add only when all of these are true:

- the behavior is truly cross-cutting across more than one domain (routing,
request stack, realtime, service worker, etc.);
- incorrect usage creates a meaningful security risk (permissions, secret
leakage, privilege escalation, or trust-boundary failure);
- a deterministic centralized policy removes repeated app-specific authorization and
headers/guard logic;
- safe defaults keep apps secure out of the box, with explicit opt-in for riskier
behavior.

If the answer is no, the feature should be redesigned, deferred, or kept
internal.

Expand All @@ -230,4 +350,5 @@ At that point:
- public API surface matches user needs
- provider internals remain available to the injector but disappear from the
normal authoring path
- new modules target 100% test coverage before being considered mature
- docs and generated outputs teach the same stable model
77 changes: 30 additions & 47 deletions src/DOCUMENTATION_REQUIREMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This requirement applies to:
- renamed public types
- changed service config
- changed `NgModule` authoring methods
- changed plugin APIs
- changed module extension APIs
- changed runtime service behavior
- provider-to-config migrations

Expand All @@ -30,49 +30,45 @@ not affect generated types, docs, examples, or user-visible behavior.

## Required Documentation For Every Public Change

1. Public type inventory

- Add or update the entry in `src/PUBLIC_API_SURFACE_INVENTORY.md`.
- Classify the symbol as authoring, runtime, config, callback, extension,
evidence, provider, internal, or legacy.
- Record the user need: author, inject, configure, implement, consume, or
none.
- Record the docs page and sample path.
1. Public contract
- Export a named type through `src/namespace.ts` when users encounter it.
- Export the same contract through `src/docs.ts` for generated docs.
- Do not expose provider recipes or implementation-only protocol types.
- Add the relevant user guide and sample path in the owning module docs.

2. Generated type surface

- Regenerate declaration files when public TypeScript surface changes.
- Regenerate integration surfaces when generated bindings track the public
namespace.
- Do not expose internal or unpublished implementation types through
generated parity by accident.

3. Generated docs

- Public symbols must have enough JSDoc or TypeDoc context to be useful in
`docs/static/typedoc`.
- Generated docs must be refreshed whenever exported public types change.
- Hidden/internal symbols must not appear as recommended user-facing API.

4. User guidance

- Add or update the relevant page under `docs/content`.
- Explain the stable user path, not the internal provider path.
- Put config beside the runtime service it configures.
- Include migration notes when replacing provider usage or removing a public
type.

5. Executable or testable samples

- Every new public API needs at least one sample in `docs/content` or
`docs/static/examples`.
- Snippets must be validated by `make docs-examples-check`.
- Multi-step flows should live in `docs/static/examples` so they can be
promoted to runnable checks.
- Behavioral APIs need source tests in addition to docs samples.
- New modules must target 100% test coverage before they are considered
level-9 complete.
- Any temporary coverage gap for a new module must be documented in its
pull request with a reason, owner, and closing condition.

6. Migration coverage

- Every deprecated public path needs a replacement path or explicit removal
rationale.
- Provider-to-config migrations must show the old path and new path.
Expand All @@ -96,50 +92,37 @@ make check
make doc
```

For new modules, add coverage verification for the module and document the
result in the pull request. The target is 100% coverage for the new module's
owned files.

For docs-only changes that include examples:

```bash
make docs-examples-check
make doc
```

## Future Documentation Tooling

The current repository already has `make generated-check`,
`make docs-examples-check`, and `make doc`. The refactor should add stricter
documentation tooling in small slices:

1. Add a docs requirement target
For a complete level-9 documentation refresh:

Candidate target:

```bash
make docs-requirement
```

It should give maintainers one command for generated surface checks, docs
example checks, and TypeDoc generation. It is a convenience target, not a
statement that CI must require it.

2. Add a public-type documentation check

The check should report when a curated public type has no matching TypeDoc
page or no inventory entry.

3. Add sample coverage metadata

Public inventory entries should include a docs sample path. Tooling should
report public user-facing types that lack at least one sample.

4. Promote runnable examples
```bash
make docs-requirement
```

Complex examples under `docs/static/examples` should become Playwright or
TypeScript fixtures instead of passive snippets.
This target runs generated surface checks, docs example checks, and TypeDoc
generation. It is a maintainer convenience target for the documentation
requirement, not a CI mandate.

5. Add migration-note checks
## Documentation Tooling

Deprecated provider paths and removed public types should require migration
notes before namespace changes land.
- `make docs-requirement` refreshes generated surfaces, validates examples,
generates TypeDoc, and checks public type documentation.
- `make public-type-docs-check` derives the current public surface from
`src/namespace.ts` and requires a generated TypeDoc page for every export.
- `make docs-examples-check` validates API references used by documentation
examples.
- Complex examples under `docs/static/examples` should become Playwright or
TypeScript fixtures instead of passive snippets.

## Level-9 Documentation Completeness

Expand Down
Loading
Loading