Fraclab SDK machine-readable notes

Primary human docs:
- docs/index.md
- docs/getting-started/first-algorithm.md
- docs/guides/input-spec.md
- docs/guides/output.md
- docs/guides/compile-export-import.md

Primary source-of-truth code:
- src/fraclab_sdk/runtime/runner_main.py
- src/fraclab_sdk/runtime/output.py
- src/fraclab_sdk/runtime/data_client.py
- src/fraclab_sdk/models/output_contract.py
- src/fraclab_sdk/models/drs.py
- src/fraclab_sdk/models/dataspec.py
- src/fraclab_sdk/models/algorithm_manifest.py

Critical rules:
- Algorithm entrypoint is main.py -> run(ctx)
- Runtime context exposes ctx.data_client, ctx.params, ctx.output, ctx.logger, ctx.run_context
- For frame datasets, use get_frame_columns/read_frame/iter_frame_chunks/iter_dataset_frame_chunks/iter_frame_batches
- Do not use get_parquet_dir/get_parquet_files in new algorithms; raw parquet path access is not the public runtime contract
- Do not use ctx.artifacts
- Output files must stay under ctx.output.dir
- output/manifest.json is generated by the SDK
- Algorithm-defined JSON uses camelCase
- Bundle ds.json/drs.json keep platform field names such as key/resource/layout/items

Allowed output literals from src/fraclab_sdk/models/output_contract.py:
- kind: frame | object | blob | scalar
- owner: stage | well | platform
- cardinality: one | many
- role: primary | supporting | debug
- FrameOutputSchema.index: time | depth | none

Allowed DRS literals from src/fraclab_sdk/models/drs.py:
- cardinality: one | many | zeroOrMany

See AI_GUIDE.md for the full contract and examples.
