docs: update CHANGELOG and README for v1.0.0-pre.3

This commit is contained in:
2026-03-07 12:16:47 +01:00
parent 4250f91969
commit 06d04cf92b
3 changed files with 24 additions and 41 deletions
+19 -1
View File
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [1.0.0-pre.3] - 2026-03-07
### Added
- `STK_MOD_DEP_LOG_BUFFER` (2048) added to `stk.h`
### Changed
- Dependency failure logging now emits a single line per module listing all unmet deps with their reason: `not found` or `requires <constraint>, have <version>`
- `Deferring 'test_mod_dep': unmet deps: test_mod (not found)`
- `Unloading 'test_mod_dep': unmet deps: test_mod (not found), renderer (requires ^2.0.0, have 1.3.0)`
- Silent defer at `stk_init` and vague `"unmet dependencies"` cascade log in `stk_poll` replaced with `stk_log_dependency_failures()`
- Kahn topological sort refactored into generic `stk_kahn_sort()` accepting a `has_dep` callback and an `on_cycle` callback, decoupling it from `stk_modules`. `stk_topo_sort()` is now a thin wrapper. `stk_sort_load_order()` uses the same core via `stk_batch_has_dep()`, inspecting tmp files so simultaneous load events are processed dependency-first without a retry cycle
- `stk_module_load()` split into `stk_module_preload()`, `stk_module_activate()`, `stk_module_discard()`, and `stk_validate_dependencies_single()`. Init is not called if deps are unmet
- On UNLOAD events in `stk_poll()`, the unload set is expanded to include all transitively dependent modules via `stk_collect_dependents()`, sorted dependents-first via `stk_sort_unload_order()`. Modules unloaded due to expansion are queued to pending
- On LOAD events with unmet dependencies, the tmp path is added to the pending queue instead of being dropped
- `stk_pending_retry()` now skips already-loaded entries and prunes entries whose file no longer exists
- `free_poll` label moved above `stk_pending_retry()` so retry always runs regardless of exit path
## [1.0.0-pre.2] - 2026-03-06
### Fixed
@@ -145,7 +162,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Dependency management and versioning not yet implemented
- API is unstable and subject to change in future releases
[Unreleased]: https://github.com/anth64/stk/compare/v1.0.0-pre.2...HEAD
[Unreleased]: https://github.com/anth64/stk/compare/v1.0.0-pre.3...HEAD
[1.0.0-pre.3]: https://github.com/anth64/stk/compare/v1.0.0-pre.2...v1.0.0-pre.3
[1.0.0-pre.2]: https://github.com/anth64/stk/compare/v1.0.0-pre.1...v1.0.0-pre.2
[1.0.0-pre.1]: https://github.com/anth64/stk/compare/v0.1.3...v1.0.0-pre.1
[0.1.3]: https://github.com/anth64/stk/releases/tag/v0.1.3
+2 -1
View File
@@ -234,7 +234,7 @@ stk_init();
## Project Status
**Current Version:** 1.0.0-pre.1
**Current Version:** 1.0.0-pre.3
### What Works
- Cross-platform module loading and hot-reloading
@@ -244,6 +244,7 @@ stk_init();
- Runtime-configurable logging behavior
- Optional module metadata (name, version, description)
- Dependency declaration, validation, and versioning
- Detailed dependency failure logging (missing ids, version mismatches)
- Cascade unload when dependencies are removed
- Pending queue with automatic retry when deps become available
- Topological sort with cycle detection
+3 -39
View File
@@ -206,18 +206,8 @@ unsigned char stk_validate_dependencies(size_t count)
return result;
}
/*
* has_dep(i, j, ctx): return 1 if node i depends on node j, 0 otherwise.
* Used by stk_kahn_sort to abstract over loaded modules vs incoming batch.
*/
typedef int (*stk_dep_query_fn)(size_t i, size_t j, void *ctx);
/*
* Core Kahn's topological sort. Produces dependencies-first ordering.
* on_cycle is called for each node not reachable (i.e. in a cycle).
* Returns STK_MOD_INIT_SUCCESS or STK_MOD_DEP_CIRCULAR_ERROR /
* STK_MOD_REALLOC_FAILURE.
*/
static unsigned char stk_kahn_sort(size_t count, size_t *order,
stk_dep_query_fn has_dep, void *ctx,
void (*on_cycle)(size_t i))
@@ -722,11 +712,6 @@ static int stk_batch_has_dep(size_t i, size_t j, void *ctx)
return result;
}
/*
* Sort file_indices[] (length n) so that within the batch, modules whose ids
* appear as dependencies of others come first. Uses already-copied tmp files
* to read dep symbols. Falls back to original order if sort fails.
*/
void stk_sort_load_order(int *file_indices, size_t n,
char (*file_names)[STK_PATH_MAX], const char *tmp_dir)
{
@@ -761,12 +746,6 @@ cleanup:
free(result);
}
/*
* Expand indices[0..]*in_count to include all loaded modules that transitively
* depend on any module already in the set. Writes the expanded set back into
* indices[] and updates *out_count. indices[] must have capacity module_count.
* Returns 1 if any new dependents were added, 0 otherwise.
*/
void stk_collect_dependents(size_t *indices, size_t *count)
{
size_t i, d;
@@ -775,7 +754,6 @@ void stk_collect_dependents(size_t *indices, size_t *count)
do {
changed = 0;
for (i = 0; i < module_count; i++) {
/* skip if already in the set */
in_set = 0;
{
size_t k;
@@ -789,17 +767,16 @@ void stk_collect_dependents(size_t *indices, size_t *count)
if (in_set)
continue;
/* check if any of its deps are in the set */
for (d = 0; d < stk_modules[i].dep_count; d++) {
int dep_idx =
int dep_index =
is_mod_loaded(stk_modules[i].deps[d].id);
if (dep_idx < 0)
if (dep_index < 0)
continue;
{
size_t k;
for (k = 0; k < *count; k++) {
if (indices[k] ==
(size_t)dep_idx) {
(size_t)dep_index) {
indices[(*count)++] = i;
changed = 1;
goto next_module;
@@ -812,11 +789,6 @@ void stk_collect_dependents(size_t *indices, size_t *count)
} while (changed);
}
/*
* Sort indices[] (length n) so that dependents come before their dependencies.
* This is the reverse of topological order. indices[] is sorted in-place.
* Falls back to reverse-index order if topo sort fails or alloc fails.
*/
void stk_sort_unload_order(size_t *indices, size_t n)
{
size_t *topo = NULL;
@@ -836,10 +808,6 @@ void stk_sort_unload_order(size_t *indices, size_t n)
if (stk_topo_sort(module_count, topo) != STK_MOD_INIT_SUCCESS)
goto fallback;
/*
* topo[] is dependencies-first. Walk it in reverse to get
* dependents-first, picking only indices that are in our set.
*/
k = 0;
for (i = module_count; i > 0; --i) {
size_t mod = topo[i - 1];
@@ -866,7 +834,6 @@ void stk_sort_unload_order(size_t *indices, size_t n)
fallback:
free(topo);
free(result);
/* reverse index order: higher indices (dependents) first */
for (i = 0; i < n / 2; i++) {
size_t tmp = indices[i];
indices[i] = indices[n - 1 - i];
@@ -891,7 +858,6 @@ void stk_module_unload_all(void)
stk_module_unload(order[i]);
free(order);
} else {
/* fallback: reverse index order */
for (i = module_count; i > 0; --i)
stk_module_unload(i - 1);
}
@@ -943,7 +909,6 @@ void stk_pending_add_batch(const char (*paths)[STK_PATH_MAX_OS], size_t count)
if (!paths || count == 0)
return;
/* First pass: overwrite existing entries and count truly new ones */
new_count = 0;
for (i = 0; i < count; i++) {
int found = 0;
@@ -979,7 +944,6 @@ void stk_pending_add_batch(const char (*paths)[STK_PATH_MAX_OS], size_t count)
free(stk_pending);
stk_pending = new_pending;
/* Second pass: append only the truly new ones */
for (i = 0; i < count; i++) {
int found = 0;
extract_module_id(paths[i], incoming_id);